memorix 1.0.7 → 1.0.8

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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../node_modules/tsup/assets/esm_shims.js","../src/store/sqlite-db.ts","../src/store/file-lock.ts","../src/store/persistence-json.ts","../src/store/persistence.ts","../src/store/graph-store.ts","../src/memory/graph.ts","../src/types.ts","../src/store/mini-skill-store.ts","../src/compact/token-budget.ts","../src/skills/mini-skills.ts","../src/config/yaml-loader.ts","../src/config/dotenv-loader.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/llm/provider.ts","../src/search/query-expansion.ts","../src/project/aliases.ts","../src/llm/quality.ts","../src/memory/freshness.ts","../src/store/orama-store.ts","../src/store/sqlite-store.ts","../src/store/obs-store.ts","../src/memory/entity-extractor.ts","../src/memory/secret-filter.ts","../src/memory/observations.ts","../src/store/session-store.ts","../src/memory/disclosure-policy.ts","../src/project/detector.ts","../src/llm/memory-manager.ts","../src/memory/formation/extract.ts","../src/memory/formation/resolve.ts","../src/memory/formation/evaluate.ts","../src/memory/formation/index.ts","../src/config/behavior.ts","../src/memory/session.ts","../src/memory/retention.ts","../src/skills/engine.ts","../src/memory/consolidation.ts","../src/team/team-store.ts","../src/team/poll.ts","../src/memory/export-import.ts","../src/dashboard/project-classification.ts","../src/dashboard/server.ts","../src/team/event-bus.ts","../src/orchestrate/task-graph.ts","../src/orchestrate/context-collector.ts","../src/orchestrate/planner.ts","../src/team/handoff.ts","../src/multimodal/image-loader.ts","../src/audit/index.ts","../src/hooks/installers/index.ts","../src/git/hooks-path.ts","../src/sdk.ts","../src/server.ts","../src/memory/attribution-guard.ts","../src/memory/auto-relations.ts","../src/compact/engine.ts","../src/compact/index-format.ts","../src/memory/refs.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/gemini-cli.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/gemini-cli.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","../src/server/tool-profile.ts","../src/server/formation-timeout.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","/**\r\n * Shared SQLite Database Handle\r\n *\r\n * Provides a singleton-per-dataDir better-sqlite3 connection shared across\r\n * all SQLite-backed stores (observations, mini-skills, sessions, team).\r\n *\r\n * Responsibilities:\r\n * - Dynamic require of better-sqlite3 (optionalDependencies)\r\n * - WAL mode and busy_timeout configuration\r\n * - Schema creation for ALL tables (observations, mini_skills, sessions, meta, team_*)\r\n * - Singleton caching per dataDir\r\n * - Graceful close\r\n */\r\n\r\nimport { createRequire } from 'node:module';\r\nimport path from 'node:path';\r\nimport fs from 'node:fs';\r\n\r\n// Dynamic require for better-sqlite3 (native module, optionalDependencies)\r\nlet BetterSqlite3: any;\r\n\r\nexport function loadBetterSqlite3(): any {\r\n if (BetterSqlite3) return BetterSqlite3;\r\n try {\r\n const require = createRequire(import.meta.url);\r\n BetterSqlite3 = require('better-sqlite3');\r\n return BetterSqlite3;\r\n } catch {\r\n throw new Error('[memorix] better-sqlite3 is not available');\r\n }\r\n}\r\n\r\n// ── Schema DDL ──────────────────────────────────────────────────────\r\n\r\nconst CREATE_OBSERVATIONS_TABLE = `\r\nCREATE TABLE IF NOT EXISTS observations (\r\n id INTEGER PRIMARY KEY,\r\n entityName TEXT NOT NULL,\r\n type TEXT NOT NULL,\r\n title TEXT NOT NULL,\r\n narrative TEXT NOT NULL DEFAULT '',\r\n facts TEXT NOT NULL DEFAULT '[]',\r\n filesModified TEXT NOT NULL DEFAULT '[]',\r\n concepts TEXT NOT NULL DEFAULT '[]',\r\n tokens INTEGER NOT NULL DEFAULT 0,\r\n createdAt TEXT NOT NULL,\r\n updatedAt TEXT,\r\n projectId TEXT NOT NULL,\r\n hasCausalLanguage INTEGER DEFAULT 0,\r\n topicKey TEXT,\r\n revisionCount INTEGER DEFAULT 1,\r\n sessionId TEXT,\r\n status TEXT NOT NULL DEFAULT 'active',\r\n progress TEXT,\r\n source TEXT DEFAULT 'agent',\r\n commitHash TEXT,\r\n relatedCommits TEXT,\r\n relatedEntities TEXT,\r\n sourceDetail TEXT,\r\n valueCategory TEXT\r\n);\r\n`;\r\n\r\nconst CREATE_MINI_SKILLS_TABLE = `\r\nCREATE TABLE IF NOT EXISTS mini_skills (\r\n id INTEGER PRIMARY KEY,\r\n sourceObservationIds TEXT NOT NULL DEFAULT '[]',\r\n sourceEntity TEXT NOT NULL DEFAULT 'unknown',\r\n title TEXT NOT NULL,\r\n instruction TEXT NOT NULL DEFAULT '',\r\n trigger_desc TEXT NOT NULL DEFAULT '',\r\n facts TEXT NOT NULL DEFAULT '[]',\r\n projectId TEXT NOT NULL,\r\n createdAt TEXT NOT NULL,\r\n usedCount INTEGER NOT NULL DEFAULT 0,\r\n tags TEXT NOT NULL DEFAULT '[]'\r\n);\r\n`;\r\n\r\nconst CREATE_SESSIONS_TABLE = `\r\nCREATE TABLE IF NOT EXISTS sessions (\r\n id TEXT PRIMARY KEY,\r\n projectId TEXT NOT NULL,\r\n startedAt TEXT NOT NULL,\r\n endedAt TEXT,\r\n status TEXT NOT NULL DEFAULT 'active',\r\n summary TEXT,\r\n agent TEXT\r\n);\r\n`;\r\n\r\nconst CREATE_META_TABLE = `\r\nCREATE TABLE IF NOT EXISTS meta (\r\n key TEXT PRIMARY KEY,\r\n value TEXT NOT NULL\r\n);\r\n`;\r\n\r\n// ── Phase 4a: Autonomous Agent Team Tables ──────────────────────────\n\r\nconst CREATE_TEAM_AGENTS_TABLE = `\r\nCREATE TABLE IF NOT EXISTS team_agents (\r\n agent_id TEXT PRIMARY KEY,\r\n project_id TEXT NOT NULL,\r\n agent_type TEXT NOT NULL,\r\n instance_id TEXT NOT NULL,\r\n name TEXT NOT NULL DEFAULT '',\r\n role TEXT,\r\n capabilities TEXT,\r\n status TEXT NOT NULL DEFAULT 'active',\r\n joined_at INTEGER NOT NULL,\r\n last_heartbeat INTEGER NOT NULL,\r\n left_at INTEGER,\r\n last_seen_obs_generation INTEGER NOT NULL DEFAULT 0,\r\n UNIQUE(project_id, agent_type, instance_id)\r\n);\r\n`;\r\n\r\nconst CREATE_TEAM_MESSAGES_TABLE = `\r\nCREATE TABLE IF NOT EXISTS team_messages (\r\n id TEXT PRIMARY KEY,\r\n project_id TEXT NOT NULL,\r\n sender_agent_id TEXT NOT NULL,\r\n recipient_agent_id TEXT,\r\n type TEXT NOT NULL DEFAULT 'direct',\r\n content TEXT NOT NULL DEFAULT '',\r\n payload TEXT,\r\n task_id TEXT,\r\n read_at INTEGER,\r\n created_at INTEGER NOT NULL,\r\n to_role TEXT,\r\n handoff_status TEXT,\r\n FOREIGN KEY (sender_agent_id) REFERENCES team_agents(agent_id),\r\n FOREIGN KEY (task_id) REFERENCES team_tasks(task_id)\r\n);\r\n`;\r\n\r\nconst CREATE_TEAM_TASKS_TABLE = `\r\nCREATE TABLE IF NOT EXISTS team_tasks (\r\n task_id TEXT PRIMARY KEY,\r\n project_id TEXT NOT NULL,\r\n description TEXT NOT NULL,\r\n status TEXT NOT NULL DEFAULT 'pending',\r\n assignee_agent_id TEXT,\r\n result TEXT,\r\n metadata TEXT,\r\n created_by TEXT,\r\n created_at INTEGER NOT NULL,\r\n updated_at INTEGER NOT NULL,\r\n required_role TEXT,\r\n preferred_role TEXT,\r\n FOREIGN KEY (assignee_agent_id) REFERENCES team_agents(agent_id),\r\n FOREIGN KEY (created_by) REFERENCES team_agents(agent_id)\r\n);\r\n`;\r\n\r\nconst CREATE_TEAM_TASK_DEPS_TABLE = `\r\nCREATE TABLE IF NOT EXISTS team_task_deps (\r\n task_id TEXT NOT NULL,\r\n dep_task_id TEXT NOT NULL,\r\n PRIMARY KEY (task_id, dep_task_id),\r\n FOREIGN KEY (task_id) REFERENCES team_tasks(task_id),\r\n FOREIGN KEY (dep_task_id) REFERENCES team_tasks(task_id)\r\n);\r\n`;\r\n\r\nconst CREATE_TEAM_LOCKS_TABLE = `\r\nCREATE TABLE IF NOT EXISTS team_locks (\r\n file TEXT NOT NULL,\r\n project_id TEXT NOT NULL,\r\n locked_by TEXT NOT NULL,\r\n locked_at INTEGER NOT NULL,\r\n expires_at INTEGER NOT NULL,\r\n PRIMARY KEY (file, project_id),\r\n FOREIGN KEY (locked_by) REFERENCES team_agents(agent_id)\r\n);\r\n`;\r\n\r\n// ── Phase 4d: Role-based Agent Team Tables ────────────────────────────\n\r\nconst CREATE_TEAM_ROLES_TABLE = `\r\nCREATE TABLE IF NOT EXISTS team_roles (\r\n role_id TEXT PRIMARY KEY,\r\n project_id TEXT NOT NULL,\r\n label TEXT NOT NULL,\r\n description TEXT,\r\n preferred_agent_types TEXT NOT NULL DEFAULT '[]',\r\n max_concurrent INTEGER NOT NULL DEFAULT 1,\r\n created_at INTEGER NOT NULL\r\n);\r\n`;\r\n\r\n// ── Chat Transcript Table ──────────────────────────────────────────────\r\n\r\nconst CREATE_CHAT_TRANSCRIPT_TABLE = `\r\nCREATE TABLE IF NOT EXISTS chat_transcript (\r\n id INTEGER PRIMARY KEY AUTOINCREMENT,\r\n project_id TEXT NOT NULL,\r\n thread_id TEXT NOT NULL DEFAULT 'default',\r\n role TEXT NOT NULL,\r\n content TEXT NOT NULL DEFAULT '',\r\n sources_json TEXT NOT NULL DEFAULT '[]',\r\n meta_json TEXT NOT NULL DEFAULT '{}',\r\n error INTEGER NOT NULL DEFAULT 0,\r\n created_at TEXT NOT NULL\r\n);\r\n`;\r\n\r\n// ── Knowledge Graph Tables ────────────────────────────────────────────\r\n\r\nconst CREATE_GRAPH_ENTITIES_TABLE = `\r\nCREATE TABLE IF NOT EXISTS graph_entities (\r\n name TEXT PRIMARY KEY,\r\n entityType TEXT NOT NULL DEFAULT '',\r\n observations TEXT NOT NULL DEFAULT '[]'\r\n);\r\n`;\r\n\r\nconst CREATE_GRAPH_RELATIONS_TABLE = `\r\nCREATE TABLE IF NOT EXISTS graph_relations (\r\n id INTEGER PRIMARY KEY AUTOINCREMENT,\r\n from_entity TEXT NOT NULL,\r\n to_entity TEXT NOT NULL,\r\n relationType TEXT NOT NULL DEFAULT '',\r\n UNIQUE(from_entity, to_entity, relationType)\r\n);\r\n`;\r\n\r\nconst CREATE_INDEXES = `\r\nCREATE INDEX IF NOT EXISTS idx_observations_projectId ON observations(projectId);\r\nCREATE INDEX IF NOT EXISTS idx_observations_topicKey ON observations(projectId, topicKey);\r\nCREATE INDEX IF NOT EXISTS idx_observations_status ON observations(status);\r\nCREATE INDEX IF NOT EXISTS idx_mini_skills_projectId ON mini_skills(projectId);\r\nCREATE INDEX IF NOT EXISTS idx_sessions_projectId ON sessions(projectId);\r\nCREATE INDEX IF NOT EXISTS idx_sessions_status ON sessions(projectId, status);\r\nCREATE INDEX IF NOT EXISTS idx_team_agents_project ON team_agents(project_id, status);\r\nCREATE INDEX IF NOT EXISTS idx_team_messages_recipient ON team_messages(recipient_agent_id, read_at);\r\nCREATE INDEX IF NOT EXISTS idx_team_messages_project ON team_messages(project_id, created_at);\r\nCREATE INDEX IF NOT EXISTS idx_team_tasks_project ON team_tasks(project_id, status);\r\nCREATE INDEX IF NOT EXISTS idx_team_tasks_assignee ON team_tasks(assignee_agent_id, status);\r\nCREATE INDEX IF NOT EXISTS idx_team_locks_project ON team_locks(project_id);\r\nCREATE INDEX IF NOT EXISTS idx_team_roles_project ON team_roles(project_id);\r\nCREATE INDEX IF NOT EXISTS idx_team_tasks_role ON team_tasks(required_role);\r\nCREATE INDEX IF NOT EXISTS idx_team_messages_role ON team_messages(to_role);\r\nCREATE INDEX IF NOT EXISTS idx_graph_relations_from ON graph_relations(from_entity);\r\nCREATE INDEX IF NOT EXISTS idx_graph_relations_to ON graph_relations(to_entity);\r\nCREATE INDEX IF NOT EXISTS idx_chat_transcript_project ON chat_transcript(project_id, thread_id);\r\n`;\r\n\r\n// ── Singleton cache ─────────────────────────────────────────────────\r\n\r\nconst _dbCache = new Map<string, any>();\r\n\r\n/**\r\n * Get or create a shared better-sqlite3 database handle for the given data directory.\r\n *\r\n * The handle is cached per normalized dataDir path. All stores (observations,\r\n * mini-skills, sessions) share the same connection and the same DB file.\r\n *\r\n * Callers must NOT close the returned handle directly — use closeDatabase().\r\n */\r\nexport function getDatabase(dataDir: string): any {\r\n const normalized = path.resolve(dataDir);\r\n const existing = _dbCache.get(normalized);\r\n if (existing) return existing;\r\n\r\n const DB = loadBetterSqlite3();\r\n fs.mkdirSync(dataDir, { recursive: true });\r\n\r\n const dbPath = path.join(dataDir, 'memorix.db');\r\n const db = new DB(dbPath);\r\n\r\n // WAL mode for concurrent read performance\r\n db.pragma('journal_mode = WAL');\r\n db.pragma('busy_timeout = 5000');\r\n db.pragma('foreign_keys = ON');\r\n\r\n // Create all tables\r\n db.exec(CREATE_OBSERVATIONS_TABLE);\r\n db.exec(CREATE_MINI_SKILLS_TABLE);\r\n db.exec(CREATE_SESSIONS_TABLE);\r\n db.exec(CREATE_META_TABLE);\r\n // Phase 4a: Agent Team tables (order matters for FK references)\n db.exec(CREATE_TEAM_AGENTS_TABLE);\r\n db.exec(CREATE_TEAM_TASKS_TABLE);\r\n db.exec(CREATE_TEAM_TASK_DEPS_TABLE);\r\n db.exec(CREATE_TEAM_MESSAGES_TABLE);\r\n db.exec(CREATE_TEAM_LOCKS_TABLE);\r\n db.exec(CREATE_TEAM_ROLES_TABLE);\r\n db.exec(CREATE_GRAPH_ENTITIES_TABLE);\r\n db.exec(CREATE_GRAPH_RELATIONS_TABLE);\r\n db.exec(CREATE_CHAT_TRANSCRIPT_TABLE);\r\n\r\n // Phase 3a migration: add sourceSnapshot + updatedAt to mini_skills\r\n // Idempotent — ALTER TABLE ADD COLUMN throws if column already exists\r\n // IMPORTANT: These must run BEFORE CREATE_INDEXES so columns exist when indexes reference them\r\n try { db.exec(`ALTER TABLE mini_skills ADD COLUMN sourceSnapshot TEXT NOT NULL DEFAULT ''`); } catch { /* already exists */ }\r\n try { db.exec(`ALTER TABLE mini_skills ADD COLUMN updatedAt TEXT`); } catch { /* already exists */ }\r\n\r\n // Phase 4a: observation attribution columns\r\n try { db.exec(`ALTER TABLE observations ADD COLUMN createdByAgentId TEXT`); } catch { /* already exists */ }\r\n try { db.exec(`ALTER TABLE observations ADD COLUMN writeGeneration INTEGER DEFAULT 0`); } catch { /* already exists */ }\r\n\r\n // Phase 4d: role-based Agent Team columns\n try { db.exec(`ALTER TABLE team_tasks ADD COLUMN required_role TEXT`); } catch { /* already exists */ }\r\n try { db.exec(`ALTER TABLE team_tasks ADD COLUMN preferred_role TEXT`); } catch { /* already exists */ }\r\n try { db.exec(`ALTER TABLE team_messages ADD COLUMN to_role TEXT`); } catch { /* already exists */ }\r\n try { db.exec(`ALTER TABLE team_messages ADD COLUMN handoff_status TEXT`); } catch { /* already exists */ }\r\n\r\n // Create indexes AFTER all ALTER TABLE migrations so referenced columns exist\r\n db.exec(CREATE_INDEXES);\r\n\r\n // Seed meta defaults\r\n db.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('storage_generation', '0')`).run();\r\n db.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('next_id', '1')`).run();\r\n db.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('mini_skills_generation', '0')`).run();\r\n\r\n _dbCache.set(normalized, db);\r\n return db;\r\n}\r\n\r\n/**\r\n * Close and remove a cached database handle for the given data directory.\r\n * Safe to call even if no handle exists.\r\n */\r\nexport function closeDatabase(dataDir: string): void {\r\n const normalized = path.resolve(dataDir);\r\n const db = _dbCache.get(normalized);\r\n if (db) {\r\n try { db.close(); } catch { /* best-effort */ }\r\n _dbCache.delete(normalized);\r\n }\r\n}\r\n\r\n/**\r\n * Close all cached database handles. Used during shutdown or tests.\r\n */\r\nexport function closeAllDatabases(): void {\r\n for (const [key, db] of _dbCache) {\r\n try { db.close(); } catch { /* best-effort */ }\r\n _dbCache.delete(key);\r\n }\r\n}\r\n\r\n/**\r\n * Check if better-sqlite3 is available without throwing.\r\n */\r\nexport function isSqliteAvailable(): boolean {\r\n try {\r\n loadBetterSqlite3();\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n","/**\r\n * File Lock & Atomic Write Utilities\r\n *\r\n * Provides cross-process file locking using .lock files with atomic creation\r\n * (O_CREAT | O_EXCL), and atomic file writes via temp-file-then-rename.\r\n *\r\n * This prevents data corruption when multiple MCP server instances\r\n * (e.g., Cursor + Windsurf) write to the same project directory simultaneously.\r\n */\r\n\r\nimport { promises as fs } from 'node:fs';\r\nimport path from 'node:path';\r\n\r\n/** Lock is considered stale after 10 seconds (process crash recovery) */\r\nconst LOCK_STALE_MS = 10_000;\r\n/** Retry interval when waiting for lock */\r\nconst RETRY_INTERVAL_MS = 50;\r\n/** Maximum retries before giving up (50ms × 60 = 3 seconds) */\r\nconst MAX_RETRIES = 60;\r\n\r\n/**\r\n * Acquire a lock file atomically.\r\n * Uses O_WRONLY | O_CREAT | O_EXCL — fails if file already exists.\r\n * Handles stale locks from crashed processes.\r\n */\r\nexport async function acquireLock(lockPath: string): Promise<void> {\r\n for (let i = 0; i < MAX_RETRIES; i++) {\r\n try {\r\n const fd = await fs.open(lockPath, 'wx');\r\n await fd.writeFile(JSON.stringify({ pid: process.pid, time: Date.now() }));\r\n await fd.close();\r\n return;\r\n } catch (err: unknown) {\r\n const code = err instanceof Error && 'code' in err ? (err as NodeJS.ErrnoException).code : undefined;\r\n if (code === 'EEXIST' || code === 'EPERM') {\r\n // Lock exists — check if stale\r\n try {\r\n const stat = await fs.stat(lockPath);\r\n if (Date.now() - stat.mtimeMs > LOCK_STALE_MS) {\r\n await fs.unlink(lockPath).catch(() => {});\r\n continue;\r\n }\r\n } catch {\r\n continue; // Lock disappeared — retry immediately\r\n }\r\n await new Promise(r => setTimeout(r, RETRY_INTERVAL_MS));\r\n } else {\r\n throw err;\r\n }\r\n }\r\n }\r\n // Last resort: force-remove stale lock and try once more\r\n await fs.unlink(lockPath).catch(() => {});\r\n try {\r\n const fd = await fs.open(lockPath, 'wx');\r\n await fd.writeFile(JSON.stringify({ pid: process.pid, time: Date.now() }));\r\n await fd.close();\r\n return;\r\n } catch {\r\n throw new Error(`Failed to acquire lock: ${lockPath} (timeout after ${MAX_RETRIES * RETRY_INTERVAL_MS}ms)`);\r\n }\r\n}\r\n\r\n/**\r\n * Release a lock file.\r\n */\r\nexport async function releaseLock(lockPath: string): Promise<void> {\r\n await fs.unlink(lockPath).catch(() => {});\r\n}\r\n\r\n/**\r\n * Execute a function while holding a project-level lock.\r\n * Ensures only one process writes to the project directory at a time.\r\n *\r\n * @param projectDir - The project data directory to lock\r\n * @param fn - The async function to execute while holding the lock\r\n * @returns The return value of fn\r\n */\r\nexport async function withFileLock<T>(projectDir: string, fn: () => Promise<T>): Promise<T> {\r\n const lockPath = path.join(projectDir, '.memorix.lock');\r\n await acquireLock(lockPath);\r\n try {\r\n return await fn();\r\n } finally {\r\n await releaseLock(lockPath);\r\n }\r\n}\r\n\r\n/**\r\n * Write a file atomically: write to .tmp, then rename.\r\n * Prevents partial writes from corrupting data files on crash.\r\n *\r\n * On most filesystems, rename() is atomic within the same directory,\r\n * so readers always see either the old complete file or the new complete file.\r\n */\r\nexport async function atomicWriteFile(filePath: string, data: string): Promise<void> {\r\n const tmpPath = filePath + `.tmp.${process.pid}`;\r\n await fs.writeFile(tmpPath, data, 'utf-8');\r\n await fs.rename(tmpPath, filePath);\r\n}\r\n","/**\r\n * JSON Persistence Helpers — Migration / Export / Debug Only\r\n *\r\n * These functions read/write JSON/JSONL files for one-time migration\r\n * from legacy storage formats into SQLite, or for export/import and debug.\r\n *\r\n * NOT used as runtime canonical store — SQLite is the sole canonical backend.\r\n */\r\n\r\nimport { promises as fs } from 'node:fs';\r\nimport path from 'node:path';\r\nimport { atomicWriteFile } from './file-lock.js';\r\n\r\n/**\r\n * Get the file path for the knowledge graph JSONL file.\r\n * (MCP-compatible format, same as official Memory Server)\r\n */\r\nexport function getGraphFilePath(projectDir: string): string {\r\n return path.join(projectDir, 'graph.jsonl');\r\n}\r\n\r\n/**\r\n * Save the knowledge graph in JSONL format (MCP-compatible).\r\n * Each line is a JSON object with type: \"entity\" or \"relation\".\r\n *\r\n * Format adopted from MCP Official Memory Server.\r\n */\r\nexport async function saveGraphJsonl(\r\n projectDir: string,\r\n entities: Array<{ name: string; entityType: string; observations: string[] }>,\r\n relations: Array<{ from: string; to: string; relationType: string }>,\r\n): Promise<void> {\r\n const lines = [\r\n ...entities.map((e) =>\r\n JSON.stringify({ type: 'entity', name: e.name, entityType: e.entityType, observations: e.observations }),\r\n ),\r\n ...relations.map((r) =>\r\n JSON.stringify({ type: 'relation', from: r.from, to: r.to, relationType: r.relationType }),\r\n ),\r\n ];\r\n await atomicWriteFile(getGraphFilePath(projectDir), lines.join('\\n'));\r\n}\r\n\r\n/**\r\n * Load the knowledge graph from JSONL format.\r\n */\r\nexport async function loadGraphJsonl(\r\n projectDir: string,\r\n): Promise<{\r\n entities: Array<{ name: string; entityType: string; observations: string[] }>;\r\n relations: Array<{ from: string; to: string; relationType: string }>;\r\n}> {\r\n const filePath = getGraphFilePath(projectDir);\r\n try {\r\n const data = await fs.readFile(filePath, 'utf-8');\r\n const lines = data.split('\\n').filter((line) => line.trim() !== '');\r\n return lines.reduce(\r\n (graph, line) => {\r\n const item = JSON.parse(line);\r\n if (item.type === 'entity') {\r\n graph.entities.push({\r\n name: item.name,\r\n entityType: item.entityType,\r\n observations: item.observations,\r\n });\r\n }\r\n if (item.type === 'relation') {\r\n graph.relations.push({\r\n from: item.from,\r\n to: item.to,\r\n relationType: item.relationType,\r\n });\r\n }\r\n return graph;\r\n },\r\n {\r\n entities: [] as Array<{ name: string; entityType: string; observations: string[] }>,\r\n relations: [] as Array<{ from: string; to: string; relationType: string }>\r\n },\r\n );\r\n } catch (error) {\r\n if (error instanceof Error && 'code' in error && (error as NodeJS.ErrnoException).code === 'ENOENT') {\r\n return { entities: [], relations: [] };\r\n }\r\n throw error;\r\n }\r\n}\r\n\r\n/**\r\n * Save observation data as JSON (for Orama restore / export).\r\n */\r\nexport async function saveObservationsJson(\r\n projectDir: string,\r\n observations: unknown[],\r\n): Promise<void> {\r\n const filePath = path.join(projectDir, 'observations.json');\r\n await atomicWriteFile(filePath, JSON.stringify(observations, null, 2));\r\n}\r\n\r\n/**\r\n * Load observation data from JSON.\r\n */\r\nexport async function loadObservationsJson(projectDir: string): Promise<unknown[]> {\r\n const filePath = path.join(projectDir, 'observations.json');\r\n try {\r\n const data = await fs.readFile(filePath, 'utf-8');\r\n return JSON.parse(data);\r\n } catch (error) {\r\n if (error instanceof Error && 'code' in error && (error as NodeJS.ErrnoException).code === 'ENOENT') {\r\n return [];\r\n }\r\n throw error;\r\n }\r\n}\r\n\r\n/**\r\n * Save the next observation ID counter (legacy JSON format).\r\n */\r\nexport async function saveIdCounter(projectDir: string, nextId: number): Promise<void> {\r\n const filePath = path.join(projectDir, 'counter.json');\r\n await atomicWriteFile(filePath, JSON.stringify({ nextId }));\r\n}\r\n\r\n/**\r\n * Load the next observation ID counter (legacy JSON format).\r\n * For runtime use, prefer the SQLite meta table via SqliteBackend.\r\n */\r\nexport async function loadIdCounter(projectDir: string): Promise<number> {\r\n const filePath = path.join(projectDir, 'counter.json');\r\n try {\r\n const data = await fs.readFile(filePath, 'utf-8');\r\n return JSON.parse(data).nextId ?? 1;\r\n } catch {\r\n return 1;\r\n }\r\n}\r\n\r\n/**\r\n * Save mini-skills data as JSON (migration source only).\r\n */\r\nexport async function saveMiniSkillsJson(\r\n projectDir: string,\r\n skills: unknown[],\r\n): Promise<void> {\r\n const filePath = path.join(projectDir, 'mini-skills.json');\r\n await atomicWriteFile(filePath, JSON.stringify(skills, null, 2));\r\n}\r\n\r\n/**\r\n * Load mini-skills data from JSON (migration source only).\r\n */\r\nexport async function loadMiniSkillsJson(projectDir: string): Promise<unknown[]> {\r\n const filePath = path.join(projectDir, 'mini-skills.json');\r\n try {\r\n const data = await fs.readFile(filePath, 'utf-8');\r\n const parsed = JSON.parse(data);\r\n return Array.isArray(parsed) ? parsed : [];\r\n } catch (error) {\r\n if (error instanceof Error && 'code' in error && (error as NodeJS.ErrnoException).code === 'ENOENT') {\r\n return [];\r\n }\r\n throw error;\r\n }\r\n}\r\n\r\n/**\r\n * Load the mini-skills ID counter (legacy JSON format).\r\n */\r\nexport async function loadMiniSkillsCounter(projectDir: string): Promise<number> {\r\n const filePath = path.join(projectDir, 'mini-skills-counter.json');\r\n try {\r\n const data = await fs.readFile(filePath, 'utf-8');\r\n return JSON.parse(data).nextId ?? 1;\r\n } catch {\r\n return 1;\r\n }\r\n}\r\n\r\n/**\r\n * Save the mini-skills ID counter (legacy JSON format).\r\n */\r\nexport async function saveMiniSkillsCounter(projectDir: string, nextId: number): Promise<void> {\r\n const filePath = path.join(projectDir, 'mini-skills-counter.json');\r\n await atomicWriteFile(filePath, JSON.stringify({ nextId }));\r\n}\r\n\r\n/**\r\n * Save sessions data as JSON (migration source only).\r\n */\r\nexport async function saveSessionsJson(\r\n projectDir: string,\r\n sessions: unknown[],\r\n): Promise<void> {\r\n const filePath = path.join(projectDir, 'sessions.json');\r\n await atomicWriteFile(filePath, JSON.stringify(sessions, null, 2));\r\n}\r\n\r\n/**\r\n * Load sessions data from JSON (migration source only).\r\n */\r\nexport async function loadSessionsJson(projectDir: string): Promise<unknown[]> {\r\n const filePath = path.join(projectDir, 'sessions.json');\r\n try {\r\n const data = await fs.readFile(filePath, 'utf-8');\r\n return JSON.parse(data);\r\n } catch (error) {\r\n if (error instanceof Error && 'code' in error && (error as NodeJS.ErrnoException).code === 'ENOENT') {\r\n return [];\r\n }\r\n throw error;\r\n }\r\n}\r\n","/**\r\n * Persistence Layer — Runtime + Migration\r\n *\r\n * Runtime responsibilities:\r\n * - Data directory resolution (flat global ~/.memorix/data/)\r\n * - Orama DB file path helpers\r\n * - Legacy per-project subdirectory migration\r\n *\r\n * JSON I/O helpers have been moved to persistence-json.ts.\r\n * They are re-exported here for backward compatibility during the transition.\r\n *\r\n * SQLite is the sole canonical runtime store.\r\n * JSON/JSONL files are only used for migration, export/import, and debug.\r\n */\r\n\r\nimport { promises as fs } from 'node:fs';\r\nimport path from 'node:path';\r\nimport os from 'node:os';\r\n\r\n// ── Re-export JSON helpers for backward compat ────────────────────\r\nexport {\r\n getGraphFilePath,\r\n saveGraphJsonl,\r\n loadGraphJsonl,\r\n saveObservationsJson,\r\n loadObservationsJson,\r\n saveIdCounter,\r\n loadIdCounter,\r\n saveMiniSkillsJson,\r\n loadMiniSkillsJson,\r\n loadMiniSkillsCounter,\r\n saveMiniSkillsCounter,\r\n saveSessionsJson,\r\n loadSessionsJson,\r\n} from './persistence-json.js';\r\n\r\n/** Default base data directory — overridable via MEMORIX_DATA_DIR env var */\r\nfunction resolveDefaultDataDir(): string {\r\n return process.env.MEMORIX_DATA_DIR || path.join(os.homedir(), '.memorix', 'data');\r\n}\r\n\r\n/**\r\n * Sanitize a projectId for use as a directory name.\r\n * Used only during migration to locate legacy per-project subdirectories.\r\n */\r\nfunction sanitizeProjectId(projectId: string): string {\r\n return projectId.replace(/\\//g, '--').replace(/[<>:\"|?*\\\\]/g, '_');\r\n}\r\n\r\n/**\r\n * Get the data directory for Memorix storage.\r\n *\r\n * Returns the FLAT global directory (~/.memorix/data/) regardless of projectId.\r\n * projectId is stored as metadata inside observations, not used for directory partitioning.\r\n * This ensures all IDEs share the same data directory even if they detect different projectIds.\r\n *\r\n * @param _projectId - Ignored for directory purposes (kept for API compat)\r\n */\r\nexport async function getProjectDataDir(_projectId: string, baseDir?: string): Promise<string> {\r\n // All projects share one flat data directory — projectId is metadata only\r\n const base = baseDir ?? resolveDefaultDataDir();\r\n await fs.mkdir(base, { recursive: true });\r\n return base;\r\n}\r\n\r\n/**\r\n * Get the base data directory (parent of all project dirs).\r\n */\r\nexport function getBaseDataDir(baseDir?: string): string {\r\n return baseDir ?? resolveDefaultDataDir();\r\n}\r\n\r\n/**\r\n * List all project data directories.\r\n * Used for cross-project (global) search.\r\n */\r\nexport async function listProjectDirs(baseDir?: string): Promise<string[]> {\r\n const base = baseDir ?? resolveDefaultDataDir();\r\n try {\r\n const entries = await fs.readdir(base, { withFileTypes: true });\r\n return entries\r\n .filter((e) => e.isDirectory())\r\n .map((e) => path.join(base, e.name));\r\n } catch {\r\n return [];\r\n }\r\n}\r\n\r\n/**\r\n * Migrate legacy per-project subdirectories into the flat base directory.\r\n *\r\n * Before v0.9.6, data was stored in per-project subdirectories:\r\n * ~/.memorix/data/AVIDS2--memorix/observations.json\r\n * ~/.memorix/data/local--myproject/observations.json\r\n *\r\n * This caused data fragmentation when different IDEs detected different projectIds.\r\n * Now all data lives in ~/.memorix/data/ directly.\r\n *\r\n * Migration:\r\n * 1. Scan all subdirectories under base dir\r\n * 2. Merge observations from all subdirs into base dir (remap IDs to avoid collision)\r\n * 3. Merge graph.jsonl (deduplicate entities by name)\r\n * 4. Move subdirectories to .migrated-subdirs/ backup\r\n */\r\nexport async function migrateSubdirsToFlat(baseDir?: string): Promise<boolean> {\r\n const base = baseDir ?? resolveDefaultDataDir();\r\n await fs.mkdir(base, { recursive: true });\r\n\r\n // Find all subdirectories that contain observations.json\r\n let entries: import('node:fs').Dirent[];\r\n try {\r\n entries = await fs.readdir(base, { withFileTypes: true });\r\n } catch {\r\n return false;\r\n }\r\n\r\n const dataDirs = entries\r\n .filter((e) => e.isDirectory() && !e.name.startsWith('.'))\r\n .map((e) => path.join(base, e.name));\r\n\r\n if (dataDirs.length === 0) return false;\r\n\r\n // Check which subdirs actually have observation data\r\n const subdirData: Array<{ dir: string; obs: any[]; graph: { entities: any[]; relations: any[] } }> = [];\r\n for (const dir of dataDirs) {\r\n const obsPath = path.join(dir, 'observations.json');\r\n try {\r\n const data = await fs.readFile(obsPath, 'utf-8');\r\n const obs = JSON.parse(data);\r\n if (Array.isArray(obs) && obs.length > 0) {\r\n // Also try to load graph\r\n let graph = { entities: [] as any[], relations: [] as any[] };\r\n try {\r\n const graphData = await fs.readFile(path.join(dir, 'graph.jsonl'), 'utf-8');\r\n const lines = graphData.split('\\n').filter((l: string) => l.trim());\r\n for (const line of lines) {\r\n const item = JSON.parse(line);\r\n if (item.type === 'entity') graph.entities.push(item);\r\n if (item.type === 'relation') graph.relations.push(item);\r\n }\r\n } catch { /* no graph */ }\r\n subdirData.push({ dir, obs, graph });\r\n }\r\n } catch { /* no observations */ }\r\n }\r\n\r\n if (subdirData.length === 0) return false;\r\n\r\n // Load existing base-level data (if any)\r\n let baseObs: any[] = [];\r\n try {\r\n const data = await fs.readFile(path.join(base, 'observations.json'), 'utf-8');\r\n baseObs = JSON.parse(data);\r\n if (!Array.isArray(baseObs)) baseObs = [];\r\n } catch { /* no existing base data */ }\r\n\r\n let baseGraph = { entities: [] as any[], relations: [] as any[] };\r\n try {\r\n const graphData = await fs.readFile(path.join(base, 'graph.jsonl'), 'utf-8');\r\n const lines = graphData.split('\\n').filter((l: string) => l.trim());\r\n for (const line of lines) {\r\n const item = JSON.parse(line);\r\n if (item.type === 'entity') baseGraph.entities.push(item);\r\n if (item.type === 'relation') baseGraph.relations.push(item);\r\n }\r\n } catch { /* no graph */ }\r\n\r\n // Merge all observations: collect, sort by createdAt, remap IDs\r\n const allObs: any[] = [...baseObs];\r\n for (const { obs } of subdirData) {\r\n for (const o of obs) {\r\n // Deduplicate by title+createdAt+projectId (same observation from migration overlap)\r\n const isDuplicate = allObs.some(\r\n (existing) => existing.title === o.title && existing.createdAt === o.createdAt,\r\n );\r\n if (!isDuplicate) {\r\n allObs.push(o);\r\n }\r\n }\r\n }\r\n\r\n // Sort by createdAt then remap IDs sequentially\r\n allObs.sort((a, b) => (a.createdAt || '').localeCompare(b.createdAt || ''));\r\n for (let i = 0; i < allObs.length; i++) {\r\n allObs[i].id = i + 1;\r\n }\r\n\r\n // Merge graphs (deduplicate entities by name)\r\n const entityMap = new Map<string, any>();\r\n for (const e of baseGraph.entities) entityMap.set(e.name, e);\r\n for (const { graph } of subdirData) {\r\n for (const e of graph.entities) {\r\n if (!entityMap.has(e.name)) {\r\n entityMap.set(e.name, e);\r\n } else {\r\n // Merge observations lists\r\n const existing = entityMap.get(e.name);\r\n const obsSet = new Set([...(existing.observations || []), ...(e.observations || [])]);\r\n existing.observations = [...obsSet];\r\n }\r\n }\r\n }\r\n\r\n const relationSet = new Set<string>();\r\n const mergedRelations: any[] = [];\r\n for (const rel of [...baseGraph.relations, ...subdirData.flatMap((d) => d.graph.relations)]) {\r\n const key = `${rel.from}|${rel.to}|${rel.relationType}`;\r\n if (!relationSet.has(key)) {\r\n relationSet.add(key);\r\n mergedRelations.push(rel);\r\n }\r\n }\r\n\r\n // Write merged data to base directory\r\n await fs.writeFile(path.join(base, 'observations.json'), JSON.stringify(allObs, null, 2), 'utf-8');\r\n await fs.writeFile(\r\n path.join(base, 'counter.json'),\r\n JSON.stringify({ nextId: allObs.length + 1 }),\r\n 'utf-8',\r\n );\r\n\r\n // Write merged graph\r\n const graphLines = [\r\n ...[...entityMap.values()].map((e) => JSON.stringify({ type: 'entity', name: e.name, entityType: e.entityType, observations: e.observations })),\r\n ...mergedRelations.map((r) => JSON.stringify({ type: 'relation', from: r.from, to: r.to, relationType: r.relationType })),\r\n ];\r\n if (graphLines.length > 0) {\r\n await fs.writeFile(path.join(base, 'graph.jsonl'), graphLines.join('\\n'), 'utf-8');\r\n }\r\n\r\n // Also merge sessions if present\r\n let allSessions: any[] = [];\r\n try {\r\n const data = await fs.readFile(path.join(base, 'sessions.json'), 'utf-8');\r\n allSessions = JSON.parse(data);\r\n if (!Array.isArray(allSessions)) allSessions = [];\r\n } catch { /* no sessions */ }\r\n for (const { dir } of subdirData) {\r\n try {\r\n const data = await fs.readFile(path.join(dir, 'sessions.json'), 'utf-8');\r\n const sessions = JSON.parse(data);\r\n if (Array.isArray(sessions)) allSessions.push(...sessions);\r\n } catch { /* no sessions */ }\r\n }\r\n if (allSessions.length > 0) {\r\n await fs.writeFile(path.join(base, 'sessions.json'), JSON.stringify(allSessions, null, 2), 'utf-8');\r\n }\r\n\r\n // Move subdirectories to backup\r\n const backupDir = path.join(base, '.migrated-subdirs');\r\n await fs.mkdir(backupDir, { recursive: true });\r\n for (const { dir } of subdirData) {\r\n const dirName = path.basename(dir);\r\n try {\r\n await fs.rename(dir, path.join(backupDir, dirName));\r\n } catch {\r\n // If rename fails (cross-device), try to just leave it\r\n // The important thing is the merged data is written\r\n }\r\n }\r\n\r\n // Also move remaining empty subdirectories\r\n for (const dir of dataDirs) {\r\n const dirName = path.basename(dir);\r\n try {\r\n await fs.access(dir);\r\n await fs.rename(dir, path.join(backupDir, dirName));\r\n } catch { /* already moved or doesn't exist */ }\r\n }\r\n\r\n return true;\r\n}\r\n\r\n/**\r\n * Get the file path for the Orama database file.\r\n */\r\nexport function getDbFilePath(projectDir: string): string {\r\n return path.join(projectDir, 'memorix.msp');\r\n}\r\n\r\n/**\r\n * Check if a database file exists for the given project.\r\n */\r\nexport async function hasExistingData(projectDir: string): Promise<boolean> {\r\n try {\r\n await fs.access(getDbFilePath(projectDir));\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n","/**\r\n * GraphSqliteStore — SQLite-backed knowledge graph store.\r\n *\r\n * Replaces graph.jsonl as the canonical runtime graph store.\r\n * graph.jsonl is now only a migration source / export artifact.\r\n */\r\n\r\nimport type { Entity, Relation } from '../types.js';\r\nimport { getDatabase } from './sqlite-db.js';\r\nimport { loadGraphJsonl } from './persistence.js';\r\nimport path from 'node:path';\r\nimport fs from 'node:fs';\r\n\r\nexport interface GraphStore {\r\n init(dataDir: string): Promise<void>;\r\n loadEntities(): Entity[];\r\n loadRelations(): Relation[];\r\n insertEntities(entities: Entity[]): void;\r\n insertRelations(relations: Relation[]): void;\r\n deleteEntities(names: string[]): void;\r\n deleteRelations(relations: Relation[]): void;\r\n addObservations(updates: { entityName: string; contents: string[] }[]): void;\r\n deleteObservations(deletions: { entityName: string; observations: string[] }[]): void;\r\n replaceAll(entities: Entity[], relations: Relation[]): void;\r\n close(): void;\r\n}\r\n\r\nfunction safeJsonParse(val: string | null | undefined, fallback: any): any {\r\n if (val == null || val === '') return fallback;\r\n try { return JSON.parse(val); } catch { return fallback; }\r\n}\r\n\r\nfunction rowToEntity(row: any): Entity {\r\n return {\r\n name: row.name,\r\n entityType: row.entityType || '',\r\n observations: safeJsonParse(row.observations, []),\r\n };\r\n}\r\n\r\nfunction entityToRow(entity: Entity): Record<string, unknown> {\r\n return {\r\n name: entity.name,\r\n entityType: entity.entityType || '',\r\n observations: JSON.stringify(entity.observations ?? []),\r\n };\r\n}\r\n\r\nexport class GraphSqliteStore implements GraphStore {\r\n private db: any = null;\r\n private dataDir: string = '';\r\n\r\n private stmtInsertEntity: any = null;\r\n private stmtUpdateEntityObs: any = null;\r\n private stmtDeleteEntity: any = null;\r\n private stmtSelectAllEntities: any = null;\r\n private stmtSelectEntityByName: any = null;\r\n\r\n private stmtInsertRelation: any = null;\r\n private stmtDeleteRelation: any = null;\r\n private stmtDeleteRelationsByEntity: any = null;\r\n private stmtSelectAllRelations: any = null;\r\n\r\n async init(dataDir: string): Promise<void> {\r\n this.dataDir = dataDir;\r\n this.db = getDatabase(dataDir);\r\n\r\n // Prepare entity statements\r\n this.stmtInsertEntity = this.db.prepare(\r\n `INSERT OR REPLACE INTO graph_entities (name, entityType, observations) VALUES (@name, @entityType, @observations)`\r\n );\r\n this.stmtUpdateEntityObs = this.db.prepare(\r\n `UPDATE graph_entities SET observations = @observations WHERE name = @name`\r\n );\r\n this.stmtDeleteEntity = this.db.prepare(`DELETE FROM graph_entities WHERE name = ?`);\r\n this.stmtSelectAllEntities = this.db.prepare(`SELECT * FROM graph_entities`);\r\n this.stmtSelectEntityByName = this.db.prepare(`SELECT * FROM graph_entities WHERE name = ?`);\r\n\r\n // Prepare relation statements\r\n this.stmtInsertRelation = this.db.prepare(\r\n `INSERT OR IGNORE INTO graph_relations (from_entity, to_entity, relationType) VALUES (@from, @to, @relationType)`\r\n );\r\n this.stmtDeleteRelation = this.db.prepare(\r\n `DELETE FROM graph_relations WHERE from_entity = ? AND to_entity = ? AND relationType = ?`\r\n );\r\n this.stmtDeleteRelationsByEntity = this.db.prepare(\r\n `DELETE FROM graph_relations WHERE from_entity = ? OR to_entity = ?`\r\n );\r\n this.stmtSelectAllRelations = this.db.prepare(`SELECT * FROM graph_relations`);\r\n\r\n // One-time migration from graph.jsonl\r\n await this.migrateFromJsonlIfNeeded();\r\n }\r\n\r\n private async migrateFromJsonlIfNeeded(): Promise<void> {\r\n const count = this.db.prepare(`SELECT COUNT(*) AS cnt FROM graph_entities`).get();\r\n if (count.cnt > 0) return;\r\n\r\n const jsonlPath = path.join(this.dataDir, 'graph.jsonl');\r\n if (!fs.existsSync(jsonlPath)) return;\r\n\r\n try {\r\n const data = await loadGraphJsonl(this.dataDir);\r\n if (data.entities.length === 0 && data.relations.length === 0) return;\r\n\r\n console.error(`[memorix] Migrating graph from JSONL to SQLite (${data.entities.length} entities, ${data.relations.length} relations)...`);\r\n\r\n const insertAll = this.db.transaction(() => {\r\n for (const entity of data.entities) {\r\n this.stmtInsertEntity.run(entityToRow(entity));\r\n }\r\n for (const rel of data.relations) {\r\n this.stmtInsertRelation.run({ from: rel.from, to: rel.to, relationType: rel.relationType });\r\n }\r\n });\r\n insertAll();\r\n\r\n console.error(`[memorix] Graph migration complete.`);\r\n } catch (err) {\r\n console.error(`[memorix] Graph JSONL->SQLite migration failed (non-fatal): ${err}`);\r\n }\r\n }\r\n\r\n loadEntities(): Entity[] {\r\n return this.stmtSelectAllEntities.all().map(rowToEntity);\r\n }\r\n\r\n loadRelations(): Relation[] {\r\n return this.stmtSelectAllRelations.all().map((row: any) => ({\r\n from: row.from_entity,\r\n to: row.to_entity,\r\n relationType: row.relationType,\r\n }));\r\n }\r\n\r\n insertEntities(entities: Entity[]): void {\r\n const insertAll = this.db.transaction(() => {\r\n for (const entity of entities) {\r\n this.stmtInsertEntity.run(entityToRow(entity));\r\n }\r\n });\r\n insertAll();\r\n }\r\n\r\n insertRelations(relations: Relation[]): void {\r\n const insertAll = this.db.transaction(() => {\r\n for (const rel of relations) {\r\n this.stmtInsertRelation.run({ from: rel.from, to: rel.to, relationType: rel.relationType });\r\n }\r\n });\r\n insertAll();\r\n }\r\n\r\n deleteEntities(names: string[]): void {\r\n const deleteAll = this.db.transaction(() => {\r\n for (const name of names) {\r\n this.stmtDeleteRelationsByEntity.run(name, name);\r\n this.stmtDeleteEntity.run(name);\r\n }\r\n });\r\n deleteAll();\r\n }\r\n\r\n deleteRelations(relations: Relation[]): void {\r\n const deleteAll = this.db.transaction(() => {\r\n for (const rel of relations) {\r\n this.stmtDeleteRelation.run(rel.from, rel.to, rel.relationType);\r\n }\r\n });\r\n deleteAll();\r\n }\r\n\r\n addObservations(updates: { entityName: string; contents: string[] }[]): void {\r\n const updateAll = this.db.transaction(() => {\r\n for (const u of updates) {\r\n const row = this.stmtSelectEntityByName.get(u.entityName);\r\n if (!row) continue;\r\n const existing: string[] = safeJsonParse(row.observations, []);\r\n const newObs = u.contents.filter(c => !existing.includes(c));\r\n if (newObs.length > 0) {\r\n existing.push(...newObs);\r\n this.stmtUpdateEntityObs.run({ name: u.entityName, observations: JSON.stringify(existing) });\r\n }\r\n }\r\n });\r\n updateAll();\r\n }\r\n\r\n deleteObservations(deletions: { entityName: string; observations: string[] }[]): void {\r\n const deleteAll = this.db.transaction(() => {\r\n for (const d of deletions) {\r\n const row = this.stmtSelectEntityByName.get(d.entityName);\r\n if (!row) continue;\r\n const existing: string[] = safeJsonParse(row.observations, []);\r\n const filtered = existing.filter(o => !d.observations.includes(o));\r\n this.stmtUpdateEntityObs.run({ name: d.entityName, observations: JSON.stringify(filtered) });\r\n }\r\n });\r\n deleteAll();\r\n }\r\n\r\n /**\r\n * Atomically replace all entities and relations.\r\n * Used by KnowledgeGraphManager.save() for full-state persistence.\r\n */\r\n replaceAll(entities: Entity[], relations: Relation[]): void {\r\n const replaceAll = this.db.transaction(() => {\r\n this.db.prepare('DELETE FROM graph_relations').run();\r\n this.db.prepare('DELETE FROM graph_entities').run();\r\n for (const entity of entities) {\r\n this.stmtInsertEntity.run(entityToRow(entity));\r\n }\r\n for (const rel of relations) {\r\n this.stmtInsertRelation.run({ from: rel.from, to: rel.to, relationType: rel.relationType });\r\n }\r\n });\r\n replaceAll();\r\n }\r\n\r\n close(): void {\r\n // DB handle is managed by sqlite-db singleton — nothing to close here\r\n }\r\n}\r\n\r\n// ── Singleton ──────────────────────────────────────────────────────\r\n\r\nlet _graphStore: GraphSqliteStore | null = null;\r\nlet _graphDataDir: string | null = null;\r\n\r\nexport async function initGraphStore(dataDir: string): Promise<GraphSqliteStore> {\r\n if (_graphStore && _graphDataDir === dataDir) return _graphStore;\r\n _graphStore = new GraphSqliteStore();\r\n await _graphStore.init(dataDir);\r\n _graphDataDir = dataDir;\r\n return _graphStore;\r\n}\r\n\r\nexport function getGraphStore(): GraphSqliteStore {\r\n if (!_graphStore) throw new Error('[memorix] GraphStore not initialized — call initGraphStore() first');\r\n return _graphStore;\r\n}\r\n\r\nexport function resetGraphStore(): void {\r\n if (_graphStore) {\r\n try { _graphStore.close(); } catch { /* best-effort */ }\r\n }\r\n _graphStore = null;\r\n _graphDataDir = null;\r\n}\r\n","/**\r\n * Knowledge Graph Manager\r\n *\r\n * Manages the Entity-Relation knowledge graph.\r\n * Source: MCP Official Memory Server v0.6.3 (complete rewrite with same API).\r\n *\r\n * Key differences from official implementation:\r\n * - Uses per-project JSONL files (official uses single file)\r\n * - Async initialization with persistence layer\r\n * - Project-scoped operations\r\n */\r\n\r\nimport type { Entity, Relation, KnowledgeGraph } from '../types.js';\r\nimport { initGraphStore, getGraphStore } from '../store/graph-store.js';\r\n\r\nexport class KnowledgeGraphManager {\r\n private entities: Entity[] = [];\r\n private relations: Relation[] = [];\r\n private projectDir: string;\r\n private initialized = false;\r\n /** Index: lowercase entity name → Entity for O(1) lookups */\r\n private entityIndex = new Map<string, Entity>();\r\n\r\n constructor(projectDir: string) {\r\n this.projectDir = projectDir;\r\n }\r\n\r\n /** Rebuild the entity name index */\r\n private rebuildIndex(): void {\r\n this.entityIndex.clear();\r\n for (const e of this.entities) {\r\n this.entityIndex.set(e.name.toLowerCase(), e);\r\n }\r\n }\r\n\r\n /** Load graph from SQLite on first access */\r\n async init(): Promise<void> {\r\n if (this.initialized) return;\r\n await initGraphStore(this.projectDir);\r\n const store = getGraphStore();\r\n this.entities = store.loadEntities();\r\n this.relations = store.loadRelations();\r\n this.rebuildIndex();\r\n this.initialized = true;\r\n }\r\n\r\n /** Find entity by name (case-insensitive, O(1)) */\r\n findEntityByName(name: string): Entity | undefined {\r\n return this.entityIndex.get(name.toLowerCase());\r\n }\r\n\r\n /** Get all entity names as a Set (lowercase, for fast membership checks) */\r\n getEntityNameSet(): Set<string> {\r\n return new Set(this.entityIndex.keys());\r\n }\r\n\r\n /** Persist current state to SQLite */\r\n private async save(): Promise<void> {\r\n const store = getGraphStore();\r\n store.replaceAll(this.entities, this.relations);\r\n }\r\n\r\n /** Create new entities (skip duplicates by name) */\r\n async createEntities(entities: Entity[]): Promise<Entity[]> {\r\n await this.init();\r\n const newEntities = entities.filter(\r\n (e) => !this.entityIndex.has(e.name.toLowerCase()),\r\n );\r\n this.entities.push(...newEntities);\r\n if (newEntities.length > 0) this.rebuildIndex();\r\n await this.save();\r\n return newEntities;\r\n }\r\n\r\n /** Create new relations (skip duplicates) */\r\n async createRelations(relations: Relation[]): Promise<Relation[]> {\r\n await this.init();\r\n const newRelations = relations.filter(\r\n (r) =>\r\n !this.relations.some(\r\n (existing) =>\r\n existing.from === r.from &&\r\n existing.to === r.to &&\r\n existing.relationType === r.relationType,\r\n ),\r\n );\r\n this.relations.push(...newRelations);\r\n await this.save();\r\n return newRelations;\r\n }\r\n\r\n /** Add observations to existing entities */\r\n async addObservations(\r\n observations: { entityName: string; contents: string[] }[],\r\n ): Promise<{ entityName: string; addedObservations: string[] }[]> {\r\n await this.init();\r\n const results = observations.map((o) => {\r\n const entity = this.entities.find((e) => e.name === o.entityName);\r\n if (!entity) {\r\n throw new Error(`Entity with name ${o.entityName} not found`);\r\n }\r\n const newObs = o.contents.filter((c) => !entity.observations.includes(c));\r\n entity.observations.push(...newObs);\r\n return { entityName: o.entityName, addedObservations: newObs };\r\n });\r\n await this.save();\r\n return results;\r\n }\r\n\r\n /** Delete entities and their associated relations */\r\n async deleteEntities(entityNames: string[]): Promise<void> {\r\n await this.init();\r\n this.entities = this.entities.filter((e) => !entityNames.includes(e.name));\r\n this.relations = this.relations.filter(\r\n (r) => !entityNames.includes(r.from) && !entityNames.includes(r.to),\r\n );\r\n this.rebuildIndex();\r\n await this.save();\r\n }\r\n\r\n /** Delete specific observations from entities */\r\n async deleteObservations(\r\n deletions: { entityName: string; observations: string[] }[],\r\n ): Promise<void> {\r\n await this.init();\r\n for (const d of deletions) {\r\n const entity = this.entities.find((e) => e.name === d.entityName);\r\n if (entity) {\r\n entity.observations = entity.observations.filter(\r\n (o) => !d.observations.includes(o),\r\n );\r\n }\r\n }\r\n await this.save();\r\n }\r\n\r\n /** Delete specific relations */\r\n async deleteRelations(relations: Relation[]): Promise<void> {\r\n await this.init();\r\n this.relations = this.relations.filter(\r\n (r) =>\r\n !relations.some(\r\n (del) =>\r\n r.from === del.from &&\r\n r.to === del.to &&\r\n r.relationType === del.relationType,\r\n ),\r\n );\r\n await this.save();\r\n }\r\n\r\n /** Get all entity names (for Formation Pipeline entity resolution) */\r\n getEntityNames(): string[] {\r\n return this.entities.map(e => e.name);\r\n }\r\n\r\n /** Read the entire graph */\r\n async readGraph(): Promise<KnowledgeGraph> {\r\n await this.init();\r\n return { entities: this.entities, relations: this.relations };\r\n }\r\n\r\n /** Search nodes by query string (upgraded from official's basic includes) */\r\n async searchNodes(query: string): Promise<KnowledgeGraph> {\r\n await this.init();\r\n const lowerQuery = query.toLowerCase();\r\n\r\n const filteredEntities = this.entities.filter(\r\n (e) =>\r\n e.name.toLowerCase().includes(lowerQuery) ||\r\n e.entityType.toLowerCase().includes(lowerQuery) ||\r\n e.observations.some((o) => o.toLowerCase().includes(lowerQuery)),\r\n );\r\n\r\n const filteredNames = new Set(filteredEntities.map((e) => e.name));\r\n\r\n const filteredRelations = this.relations.filter(\r\n (r) => filteredNames.has(r.from) && filteredNames.has(r.to),\r\n );\r\n\r\n return { entities: filteredEntities, relations: filteredRelations };\r\n }\r\n\r\n /** Open specific nodes by name */\r\n async openNodes(names: string[]): Promise<KnowledgeGraph> {\r\n await this.init();\r\n\r\n const filteredEntities = this.entities.filter((e) => names.includes(e.name));\r\n const filteredNames = new Set(filteredEntities.map((e) => e.name));\r\n\r\n const filteredRelations = this.relations.filter(\r\n (r) => filteredNames.has(r.from) && filteredNames.has(r.to),\r\n );\r\n\r\n return { entities: filteredEntities, relations: filteredRelations };\r\n }\r\n}\r\n","/**\r\n * Memorix Core Types\r\n *\r\n * Data model sources:\r\n * - Entity/Relation/KnowledgeGraph: MCP Official Memory Server (v0.6.3)\r\n * - Observation/ObservationType: claude-mem Progressive Disclosure\r\n * - UnifiedRule/RuleSource: Memorix original (rules sync)\r\n *\r\n * Designed for extensibility: new agent formats (Kiro, Copilot, Antigravity)\r\n * can be added by extending RuleSource and adding format adapters.\r\n */\r\n\r\n// ============================================================\r\n// Knowledge Graph (adopted from MCP Official Memory Server)\r\n// ============================================================\r\n\r\n/** A node in the knowledge graph representing a concept, component, or config */\r\nexport interface Entity {\r\n name: string;\r\n entityType: string;\r\n observations: string[];\r\n}\r\n\r\n/** A directed edge between two entities */\r\nexport interface Relation {\r\n from: string;\r\n to: string;\r\n relationType: string;\r\n}\r\n\r\n/** The complete knowledge graph */\r\nexport interface KnowledgeGraph {\r\n entities: Entity[];\r\n relations: Relation[];\r\n}\r\n\r\n// ============================================================\r\n// Observation (adopted from claude-mem Progressive Disclosure)\r\n// ============================================================\r\n\r\n/**\r\n * Observation type classification using claude-mem's icon-based legend system.\r\n *\r\n * Icon mapping:\r\n * [SESSION] session-request — User's original goal\r\n * [GOTCHA] gotcha — Critical pitfall / trap\r\n * [FIX] problem-solution — Bug fix or workaround\r\n * [INFO] how-it-works — Technical explanation\r\n * [CHANGE] what-changed — Code/architecture change\r\n * [DISCOVERY] discovery — New learning or insight\r\n * [WHY] why-it-exists — Design rationale\r\n * [DECISION] decision — Architecture decision\r\n * [TRADEOFF] trade-off — Deliberate compromise\r\n * [REASONING] reasoning — Why this approach was chosen (System 2 reasoning trace)\r\n */\r\nexport type ObservationType =\r\n | 'session-request'\r\n | 'gotcha'\r\n | 'problem-solution'\r\n | 'how-it-works'\r\n | 'what-changed'\r\n | 'discovery'\r\n | 'why-it-exists'\r\n | 'decision'\r\n | 'trade-off'\r\n | 'reasoning';\r\n\r\n/** Map from ObservationType to display icon */\r\nexport const OBSERVATION_ICONS: Record<ObservationType, string> = {\r\n 'session-request': '[SESSION]',\r\n 'gotcha': '[GOTCHA]',\r\n 'problem-solution': '[FIX]',\r\n 'how-it-works': '[INFO]',\r\n 'what-changed': '[CHANGE]',\r\n 'discovery': '[DISCOVERY]',\r\n 'why-it-exists': '[WHY]',\r\n 'decision': '[DECISION]',\r\n 'trade-off': '[TRADEOFF]',\r\n 'reasoning': '[REASONING]',\r\n};\r\n\r\n/** Observation lifecycle status */\r\nexport type ObservationStatus = 'active' | 'resolved' | 'archived';\r\n\r\n/** Progress tracking for task/feature observations */\r\nexport interface ProgressInfo {\r\n feature: string;\r\n status: 'in-progress' | 'completed' | 'blocked';\r\n completion?: number;\r\n}\r\n\r\n/** A rich observation record attached to an entity */\r\nexport interface Observation {\r\n id: number;\r\n entityName: string;\r\n type: ObservationType;\r\n title: string;\r\n narrative: string;\r\n facts: string[];\r\n filesModified: string[];\r\n concepts: string[];\r\n tokens: number;\r\n createdAt: string;\r\n updatedAt?: string;\r\n projectId: string;\r\n /** Whether the observation contains causal language (because, due to, etc.) */\r\n hasCausalLanguage?: boolean;\r\n /** Optional topic key for upsert — same project+topicKey updates existing observation */\r\n topicKey?: string;\r\n /** How many times this observation was revised via topic key upsert (starts at 1) */\r\n revisionCount?: number;\r\n /** Session ID this observation belongs to */\r\n sessionId?: string;\r\n /** Lifecycle status: active (default) → resolved → archived */\r\n status?: ObservationStatus;\r\n /** ID of the observation that superseded this one (set when auto-resolved by topicKey upsert) */\r\n supersededBy?: number;\r\n /** Progress tracking for task/feature observations */\r\n progress?: ProgressInfo;\r\n /** Origin of this observation: agent (IDE hooks/MCP), git (commit ingest), manual (CLI) */\r\n source?: 'agent' | 'git' | 'manual';\r\n /** Git commit hash if source is 'git' */\r\n commitHash?: string;\r\n /** Related commit hashes — links reasoning memories to the commits they explain */\r\n relatedCommits?: string[];\r\n /** Related entity names — explicit cross-references to other memory entities */\r\n relatedEntities?: string[];\r\n /** Provenance detail: how this observation entered the system */\r\n sourceDetail?: 'explicit' | 'hook' | 'git-ingest';\r\n /** Value category from formation pipeline evaluation */\r\n valueCategory?: 'core' | 'contextual' | 'ephemeral';\r\n /** Phase 4a: Agent ID that created this observation (team attribution) */\r\n createdByAgentId?: string;\r\n /** Phase 4a: Monotonic write generation — snapshot of storage_generation at write time (watermark coherence) */\r\n writeGeneration?: number;\r\n}\r\n\r\n// ============================================================\r\n// Session Lifecycle (inspired by Engram's session management)\r\n// ============================================================\r\n\r\n/** A coding session tracked by Memorix */\r\nexport interface Session {\r\n id: string;\r\n projectId: string;\r\n startedAt: string;\r\n endedAt?: string;\r\n summary?: string;\r\n status: 'active' | 'completed';\r\n /** Agent/IDE that started this session */\r\n agent?: string;\r\n}\r\n\r\n// ============================================================\r\n// Compact Engine (adopted from claude-mem 3-layer workflow)\r\n// ============================================================\r\n\r\n/** L1 index entry — lightweight, ~50-100 tokens per result */\r\nexport interface IndexEntry {\r\n id: number;\r\n time: string;\r\n type: ObservationType;\r\n icon: string;\r\n title: string;\r\n tokens: number;\r\n /** Relevance score from search (time-decayed). Used by compact engine. */\r\n score?: number;\r\n /** Project that owns this observation. Needed to disambiguate global results. */\r\n projectId?: string;\r\n /** Origin of the memory for source-aware retrieval and display. */\r\n source?: 'agent' | 'git' | 'manual';\r\n /** Provenance detail for source-aware display */\r\n sourceDetail?: 'explicit' | 'hook' | 'git-ingest';\r\n /** Value category for source-aware ranking */\r\n valueCategory?: 'core' | 'contextual' | 'ephemeral';\r\n /** Explainable recall: why this result matched. */\r\n matchedFields?: string[];\r\n /** Entity name — used for entity-affinity scoring and workstream deduplication. */\r\n entityName?: string;\r\n /** Document type: observation or mini-skill (Phase 3a) */\r\n documentType?: DocumentType;\r\n /** Knowledge layer for layer-aware ranking (Phase 3a) */\r\n knowledgeLayer?: KnowledgeLayer;\r\n}\r\n\r\n/** Explicit reference to an observation, optionally scoped to a project. */\r\nexport interface ObservationRef {\r\n id: number;\r\n projectId?: string;\r\n}\r\n\r\n/** L2 timeline context — observations around an anchor */\r\nexport interface TimelineContext {\r\n anchorId: number;\r\n anchorEntry: IndexEntry | null;\r\n before: IndexEntry[];\r\n after: IndexEntry[];\r\n}\r\n\r\n/** Search options for the compact engine */\r\nexport interface SearchOptions {\r\n query: string;\r\n limit?: number;\r\n type?: ObservationType;\r\n projectId?: string;\r\n since?: string;\r\n until?: string;\r\n /** Token budget — trim results to fit within this many tokens (0 = unlimited) */\r\n maxTokens?: number;\r\n /** Filter by observation status. Default: 'active' (only show active memories) */\r\n status?: ObservationStatus | 'all';\r\n /** Filter by observation source: 'agent', 'git', 'manual', or undefined for all */\r\n source?: 'agent' | 'git' | 'manual';\r\n}\r\n\r\n/** Topic key family heuristics for suggesting stable topic keys */\r\nexport const TOPIC_KEY_FAMILIES: Record<string, string[]> = {\r\n 'architecture': ['architecture', 'design', 'adr', 'structure', 'pattern'],\r\n 'bug': ['bugfix', 'fix', 'error', 'regression', 'crash', 'problem-solution'],\r\n 'decision': ['decision', 'trade-off', 'choice', 'strategy'],\r\n 'config': ['config', 'setup', 'env', 'environment', 'deployment'],\r\n 'discovery': ['discovery', 'learning', 'insight', 'gotcha'],\r\n 'pattern': ['pattern', 'convention', 'standard', 'best-practice'],\r\n};\r\n\r\n// ============================================================\r\n// Orama Document Schema\r\n// ============================================================\r\n\r\n/** The document shape stored in Orama */\r\nexport interface MemorixDocument {\r\n id: string;\r\n observationId: number;\r\n entityName: string;\r\n type: string;\r\n title: string;\r\n narrative: string;\r\n facts: string;\r\n filesModified: string;\r\n concepts: string;\r\n tokens: number;\r\n createdAt: string;\r\n projectId: string;\r\n /** Number of times this observation was returned in search results */\r\n accessCount: number;\r\n /** ISO timestamp of last access via search/detail */\r\n lastAccessedAt: string;\r\n /** Lifecycle status: active, resolved, archived */\r\n status: string;\r\n /** Origin: agent, git, manual */\r\n source: string;\r\n /** Provenance detail: explicit, hook, or git-ingest */\r\n sourceDetail?: string;\r\n /** Value category from formation evaluation */\r\n valueCategory?: string;\r\n /** Optional vector embedding for semantic/hybrid retrieval */\r\n embedding?: number[];\r\n /** Document type: observation or mini-skill (Phase 3a) */\r\n documentType?: DocumentType;\r\n /** Knowledge layer for layer-aware ranking (Phase 3a) */\r\n knowledgeLayer?: KnowledgeLayer;\r\n}\r\n\r\n// ============================================================\r\n// Rules System (Memorix original — extensible for new agents)\r\n// ============================================================\r\n\r\n/**\r\n * Supported agent/IDE rule sources.\r\n * All 7 major AI IDEs are supported.\r\n */\r\nexport type RuleSource =\r\n | 'cursor'\r\n | 'claude-code'\r\n | 'codex'\r\n | 'windsurf'\r\n | 'antigravity'\r\n | 'gemini-cli'\r\n | 'copilot'\r\n | 'kiro'\r\n | 'trae'\r\n | 'memorix';\r\n\r\n/** A parsed rule in the unified intermediate representation */\r\nexport interface UnifiedRule {\r\n id: string;\r\n content: string;\r\n description?: string;\r\n source: RuleSource;\r\n scope: 'global' | 'project' | 'path-specific';\r\n paths?: string[];\r\n alwaysApply?: boolean;\r\n priority: number;\r\n hash: string;\r\n}\r\n\r\n/**\r\n * Format adapter interface — implement this for each agent/IDE.\r\n * Adding a new agent (e.g., Kiro) only requires implementing this interface.\r\n */\r\nexport interface RuleFormatAdapter {\r\n /** Unique identifier for this agent format */\r\n readonly source: RuleSource;\r\n\r\n /** File paths/globs this adapter can parse */\r\n readonly filePatterns: string[];\r\n\r\n /** Parse rule files into unified representation */\r\n parse(filePath: string, content: string): UnifiedRule[];\r\n\r\n /** Generate rule file content from unified representation */\r\n generate(rules: UnifiedRule[]): { filePath: string; content: string }[];\r\n}\r\n\r\n// ============================================================\r\n// Project Identity\r\n// ============================================================\r\n\r\nexport interface ProjectInfo {\r\n id: string;\r\n name: string;\r\n gitRemote?: string;\r\n rootPath: string;\r\n}\r\n\r\n/**\r\n * Diagnostic failure info from project detection.\r\n * Tells callers exactly WHY detection failed so they can report actionable errors.\r\n */\r\nexport type DetectionFailureReason =\r\n | 'path_not_found'\r\n | 'not_a_directory'\r\n | 'no_git'\r\n | 'git_worktree_error'\r\n | 'git_safe_directory'\r\n | 'remote_resolve_failed';\r\n\r\nexport interface DetectionFailure {\r\n reason: DetectionFailureReason;\r\n path: string;\r\n detail: string;\r\n}\r\n\r\nexport interface DetectionResult {\r\n project: ProjectInfo | null;\r\n failure: DetectionFailure | null;\r\n}\r\n\r\n// ============================================================\r\n// Memorix Server Configuration\r\n// ============================================================\r\n\r\nexport interface MemorixConfig {\r\n dataDir: string;\r\n projectId: string;\r\n projectName: string;\r\n enableEmbeddings: boolean;\r\n enableRulesSync: boolean;\r\n watchRuleFiles: boolean;\r\n}\r\n\r\nexport const DEFAULT_CONFIG: Partial<MemorixConfig> = {\r\n enableEmbeddings: false,\r\n enableRulesSync: false,\r\n watchRuleFiles: false,\r\n};\r\n\r\n// ============================================================\r\n// Workspace Sync — Cross-Agent workspace migration\r\n// ============================================================\r\n\r\n/** Supported agent targets for workspace sync */\r\nexport type AgentTarget = 'windsurf' | 'cursor' | 'claude-code' | 'codex' | 'copilot' | 'antigravity' | 'gemini-cli' | 'kiro' | 'opencode' | 'trae';\r\n\r\n/** A unified MCP server entry across all agent config formats */\r\nexport interface MCPServerEntry {\r\n name: string;\r\n /** Command for stdio transport */\r\n command: string;\r\n /** Args for stdio transport */\r\n args: string[];\r\n /** Environment variables */\r\n env?: Record<string, string> | null;\r\n /** URL for HTTP/SSE transport (Codex uses `url`, Windsurf uses `serverUrl`) */\r\n url?: string;\r\n /** HTTP headers (Windsurf uses `headers` for HTTP transport) */\r\n headers?: Record<string, string>;\r\n /** Whether this server is disabled */\r\n disabled?: boolean;\r\n}\r\n\r\n/** Unified workflow entry */\r\nexport interface WorkflowEntry {\r\n name: string;\r\n description: string;\r\n content: string;\r\n source: AgentTarget;\r\n filePath: string;\r\n}\r\n\r\n/** A skill folder discovered from an agent's skills directory */\r\nexport interface SkillEntry {\r\n name: string;\r\n description: string;\r\n sourcePath: string;\r\n sourceAgent: AgentTarget;\r\n}\r\n\r\n/** Conflict when two agents have a skill with the same folder name */\r\nexport interface SkillConflict {\r\n name: string;\r\n kept: SkillEntry;\r\n skipped: SkillEntry;\r\n}\r\n\r\n/** Result of a workspace sync operation */\r\nexport interface WorkspaceSyncResult {\r\n mcpServers: {\r\n scanned: MCPServerEntry[];\r\n generated: { filePath: string; content: string }[];\r\n };\r\n workflows: {\r\n scanned: WorkflowEntry[];\r\n generated: { filePath: string; content: string }[];\r\n };\r\n rules: {\r\n scanned: number;\r\n generated: number;\r\n };\r\n skills: {\r\n scanned: SkillEntry[];\r\n conflicts: SkillConflict[];\r\n copied: string[];\r\n skipped: string[];\r\n };\r\n}\r\n\r\n// ============================================================\r\n// Mini-Skills — Promoted memories that never decay\r\n// ============================================================\r\n\r\n/** A mini-skill promoted from one or more observations */\r\nexport interface MiniSkill {\r\n id: number;\r\n /** Observation IDs this mini-skill was derived from (live refs, best-effort) */\r\n sourceObservationIds: number[];\r\n /** Entity the source observations belong to */\r\n sourceEntity: string;\r\n /** Short title for the skill */\r\n title: string;\r\n /** What the agent should do (imperative instruction) */\r\n instruction: string;\r\n /** When this skill should be applied (scenario description) */\r\n trigger: string;\r\n /** Key facts extracted from source observations */\r\n facts: string[];\r\n /** Project this skill belongs to */\r\n projectId: string;\r\n /** ISO timestamp */\r\n createdAt: string;\r\n /** How many times this skill was injected in session_start */\r\n usedCount: number;\r\n /** Classification tags */\r\n tags: string[];\r\n /** Frozen source observation content at promote time (JSON, immutable provenance proof) */\r\n sourceSnapshot?: string;\r\n /** ISO timestamp of last modification (Phase 3a: set once at creation) */\r\n updatedAt?: string;\r\n}\r\n\r\n// ============================================================\r\n// Source Snapshot — immutable provenance proof for promoted knowledge\r\n// ============================================================\r\n\r\n/** A single observation entry within a source snapshot */\r\nexport interface SnapshotObservation {\r\n id: number;\r\n title: string;\r\n type: string;\r\n narrative: string;\r\n facts: string[];\r\n entityName: string;\r\n projectId: string;\r\n createdAt: string;\r\n /** Frozen source detail for provenance (explicit / hook / git-ingest) */\r\n sourceDetail?: string;\r\n}\r\n\r\n/** Frozen source content captured at promote time */\r\nexport interface SourceSnapshot {\r\n observations: SnapshotObservation[];\r\n promotedAt: string;\r\n}\r\n\r\n// ============================================================\r\n// Knowledge Layer — Phase 3a retrieval classification\r\n// ============================================================\r\n\r\n/** Classification of knowledge for layer-aware ranking */\r\nexport type KnowledgeLayer = 'project-truth' | 'promoted' | 'evidence';\r\n\r\n/** Document type discriminator for Orama index */\r\nexport type DocumentType = 'observation' | 'mini-skill';\r\n\r\n// ============================================================\r\n// Typed Memory Reference — Phase 3a reference protocol\r\n// ============================================================\r\n\r\n/** A typed reference to a memory object (observation or mini-skill) */\r\nexport interface MemoryRef {\r\n kind: 'obs' | 'skill';\r\n id: number;\r\n projectId?: string;\r\n}\r\n\r\n/** MCP config format adapter interface */\r\nexport interface MCPConfigAdapter {\r\n readonly source: AgentTarget;\r\n /** Parse MCP server entries from a config file */\r\n parse(content: string): MCPServerEntry[];\r\n /** Generate config file content from MCP server entries */\r\n generate(servers: MCPServerEntry[]): string;\r\n /** Get the default config file path for this agent */\r\n getConfigPath(projectRoot?: string): string;\r\n}\r\n","/**\r\n * MiniSkillStore — persistence abstraction for mini-skills.\r\n *\r\n * Backends:\r\n * - MiniSkillSqliteStore — canonical store, uses shared DB handle from sqlite-db.ts\r\n * - MiniSkillGracefulDegrade — no-op fallback when SQLite is unavailable\r\n *\r\n * Phase 2 debt-zero: SQLite is the only canonical store for mini-skills.\r\n * JSON files are migration source only. No writable JSON fallback exists.\r\n */\r\n\r\nimport type { MiniSkill } from '../types.js';\r\nimport { getDatabase } from './sqlite-db.js';\r\nimport {\r\n loadMiniSkillsJson,\r\n} from './persistence.js';\r\nimport path from 'node:path';\r\nimport fs from 'node:fs';\r\n\r\n// ── Interface ───────────────────────────────────────────────────────\r\n\r\nexport interface MiniSkillStore {\r\n init(dataDir: string): Promise<void>;\r\n loadAll(): Promise<MiniSkill[]>;\r\n loadByProject(projectId: string): Promise<MiniSkill[]>;\r\n insert(skill: MiniSkill): Promise<void>;\r\n update(skill: MiniSkill): Promise<void>;\r\n remove(id: number): Promise<void>;\r\n loadIdCounter(): Promise<number>;\r\n saveIdCounter(nextId: number): Promise<void>;\r\n /**\r\n * Atomic create: allocate ID + insert skill + bump counter in one transaction.\r\n * Prevents concurrent promotes from receiving the same ID.\r\n */\r\n atomicInsertWithId(skill: Omit<MiniSkill, 'id'>): Promise<MiniSkill>;\r\n ensureFresh(): Promise<boolean>;\r\n getGeneration(): number;\r\n getBackendName(): 'sqlite' | 'degraded';\r\n}\r\n\r\n// ── Row <-> MiniSkill serialization ─────────────────────────────────\r\n\r\nfunction skillToRow(skill: MiniSkill): Record<string, unknown> {\r\n return {\r\n id: skill.id,\r\n sourceObservationIds: JSON.stringify(skill.sourceObservationIds ?? []),\r\n sourceEntity: skill.sourceEntity ?? 'unknown',\r\n title: skill.title,\r\n instruction: skill.instruction ?? '',\r\n trigger_desc: skill.trigger ?? '',\r\n facts: JSON.stringify(skill.facts ?? []),\r\n projectId: skill.projectId,\r\n createdAt: skill.createdAt,\r\n usedCount: skill.usedCount ?? 0,\r\n tags: JSON.stringify(skill.tags ?? []),\r\n sourceSnapshot: skill.sourceSnapshot ?? '',\r\n updatedAt: skill.updatedAt ?? null,\r\n };\r\n}\r\n\r\nfunction rowToSkill(row: any): MiniSkill {\r\n return {\r\n id: row.id,\r\n sourceObservationIds: safeJsonParse(row.sourceObservationIds, []),\r\n sourceEntity: row.sourceEntity ?? 'unknown',\r\n title: row.title,\r\n instruction: row.instruction ?? '',\r\n trigger: row.trigger_desc ?? '',\r\n facts: safeJsonParse(row.facts, []),\r\n projectId: row.projectId,\r\n createdAt: row.createdAt,\r\n usedCount: row.usedCount ?? 0,\r\n tags: safeJsonParse(row.tags, []),\r\n sourceSnapshot: row.sourceSnapshot || undefined,\r\n updatedAt: row.updatedAt || undefined,\r\n };\r\n}\r\n\r\nfunction safeJsonParse(val: string | null | undefined, fallback: any): any {\r\n if (val == null || val === '') return fallback;\r\n try { return JSON.parse(val); } catch { return fallback; }\r\n}\r\n\r\n// ── SQLite Backend ──────────────────────────────────────────────────\r\n\r\nexport class MiniSkillSqliteStore implements MiniSkillStore {\r\n private db: any = null;\r\n private dataDir: string = '';\r\n private knownGeneration: number = 0;\r\n\r\n private stmtInsert: any = null;\r\n private stmtDelete: any = null;\r\n private stmtSelectAll: any = null;\r\n private stmtSelectByProject: any = null;\r\n private stmtGetMeta: any = null;\r\n private stmtSetMeta: any = null;\r\n private stmtSelectGeneration: any = null;\r\n private stmtBumpGeneration: any = null;\r\n\r\n async init(dataDir: string): Promise<void> {\r\n this.dataDir = dataDir;\r\n this.db = getDatabase(dataDir);\r\n\r\n // Prepare statements\r\n this.stmtInsert = this.db.prepare(`\r\n INSERT OR REPLACE INTO mini_skills\r\n (id, sourceObservationIds, sourceEntity, title, instruction, trigger_desc,\r\n facts, projectId, createdAt, usedCount, tags, sourceSnapshot, updatedAt)\r\n VALUES\r\n (@id, @sourceObservationIds, @sourceEntity, @title, @instruction, @trigger_desc,\r\n @facts, @projectId, @createdAt, @usedCount, @tags, @sourceSnapshot, @updatedAt)\r\n `);\r\n this.stmtDelete = this.db.prepare(`DELETE FROM mini_skills WHERE id = ?`);\r\n this.stmtSelectAll = this.db.prepare(`SELECT * FROM mini_skills`);\r\n this.stmtSelectByProject = this.db.prepare(`SELECT * FROM mini_skills WHERE projectId = ?`);\r\n this.stmtGetMeta = this.db.prepare(`SELECT value FROM meta WHERE key = ?`);\r\n this.stmtSetMeta = this.db.prepare(`INSERT OR REPLACE INTO meta (key, value) VALUES (?, ?)`);\r\n this.stmtSelectGeneration = this.db.prepare(`SELECT value FROM meta WHERE key = 'mini_skills_generation'`);\r\n this.stmtBumpGeneration = this.db.prepare(`UPDATE meta SET value = CAST(CAST(value AS INTEGER) + 1 AS TEXT) WHERE key = 'mini_skills_generation'`);\r\n\r\n // Read initial generation\r\n this.knownGeneration = this.readGeneration();\r\n\r\n // One-time migration from mini-skills.json\r\n await this.migrateFromJsonIfNeeded();\r\n }\r\n\r\n private readGeneration(): number {\r\n const row = this.stmtSelectGeneration.get();\r\n return row ? parseInt(row.value, 10) : 0;\r\n }\r\n\r\n private bumpGeneration(): void {\r\n this.stmtBumpGeneration.run();\r\n this.knownGeneration = this.readGeneration();\r\n }\r\n\r\n // ── Migration ────────────────────────────────────────────────────\r\n\r\n private async migrateFromJsonIfNeeded(): Promise<void> {\r\n const count = this.db.prepare(`SELECT COUNT(*) AS cnt FROM mini_skills`).get();\r\n if (count.cnt > 0) return;\r\n\r\n const jsonPath = path.join(this.dataDir, 'mini-skills.json');\r\n if (!fs.existsSync(jsonPath)) return;\r\n\r\n try {\r\n const raw = fs.readFileSync(jsonPath, 'utf-8');\r\n const skills: MiniSkill[] = JSON.parse(raw);\r\n if (!Array.isArray(skills) || skills.length === 0) return;\r\n\r\n console.error(`[memorix] Migrating ${skills.length} mini-skills from JSON to SQLite...`);\r\n\r\n const insertMany = this.db.transaction((list: MiniSkill[]) => {\r\n for (const skill of list) {\r\n this.stmtInsert.run(skillToRow(skill));\r\n }\r\n });\r\n insertMany(skills);\r\n\r\n // Migrate counter\r\n const counterPath = path.join(this.dataDir, 'mini-skills-counter.json');\r\n if (fs.existsSync(counterPath)) {\r\n try {\r\n const counterData = JSON.parse(fs.readFileSync(counterPath, 'utf-8'));\r\n const nextId = counterData.nextId ?? (Math.max(...skills.map(s => s.id)) + 1);\r\n this.stmtSetMeta.run('mini_skills_next_id', String(nextId));\r\n } catch {\r\n this.stmtSetMeta.run('mini_skills_next_id', String(Math.max(...skills.map(s => s.id)) + 1));\r\n }\r\n } else {\r\n this.stmtSetMeta.run('mini_skills_next_id', String(Math.max(...skills.map(s => s.id)) + 1));\r\n }\r\n\r\n this.bumpGeneration();\r\n console.error(`[memorix] Mini-skills migration complete. ${skills.length} skills now in SQLite.`);\r\n } catch (err) {\r\n console.error(`[memorix] Mini-skills JSON->SQLite migration failed (non-fatal): ${err}`);\r\n }\r\n }\r\n\r\n // ── Public read ──────────────────────────────────────────────────\r\n\r\n async loadAll(): Promise<MiniSkill[]> {\r\n return this.stmtSelectAll.all().map(rowToSkill);\r\n }\r\n\r\n async loadByProject(projectId: string): Promise<MiniSkill[]> {\r\n return this.stmtSelectByProject.all(projectId).map(rowToSkill);\r\n }\r\n\r\n async loadIdCounter(): Promise<number> {\r\n const row = this.stmtGetMeta.get('mini_skills_next_id');\r\n return row ? parseInt(row.value, 10) : 1;\r\n }\r\n\r\n // ── Public write (each bumps generation) ─────────────────────────\r\n\r\n async insert(skill: MiniSkill): Promise<void> {\r\n this.stmtInsert.run(skillToRow(skill));\r\n this.bumpGeneration();\r\n }\r\n\r\n async update(skill: MiniSkill): Promise<void> {\r\n this.stmtInsert.run(skillToRow(skill)); // INSERT OR REPLACE\r\n this.bumpGeneration();\r\n }\r\n\r\n async remove(id: number): Promise<void> {\r\n this.stmtDelete.run(id);\r\n this.bumpGeneration();\r\n }\r\n\r\n async saveIdCounter(nextId: number): Promise<void> {\r\n this.stmtSetMeta.run('mini_skills_next_id', String(nextId));\r\n }\r\n\r\n /**\r\n * Atomic create: allocate ID + insert + bump counter in a single SQLite transaction.\r\n * SQLite serializes write transactions, so concurrent calls are safely sequenced.\r\n */\r\n async atomicInsertWithId(skillWithoutId: Omit<MiniSkill, 'id'>): Promise<MiniSkill> {\r\n const result = this.db.transaction(() => {\r\n // 1. Read current counter inside the transaction\r\n const row = this.stmtGetMeta.get('mini_skills_next_id');\r\n const nextId = row ? parseInt(row.value, 10) : 1;\r\n\r\n // 2. Build the full skill with the allocated ID\r\n const skill: MiniSkill = { ...skillWithoutId, id: nextId } as MiniSkill;\r\n\r\n // 3. Insert\r\n this.stmtInsert.run(skillToRow(skill));\r\n\r\n // 4. Bump counter\r\n this.stmtSetMeta.run('mini_skills_next_id', String(nextId + 1));\r\n\r\n // 5. Bump generation\r\n this.stmtBumpGeneration.run();\r\n this.knownGeneration = this.readGeneration();\r\n\r\n return skill;\r\n })();\r\n return result;\r\n }\r\n\r\n // ── Freshness ────────────────────────────────────────────────────\r\n\r\n async ensureFresh(): Promise<boolean> {\r\n const remoteGen = this.readGeneration();\r\n if (remoteGen > this.knownGeneration) {\r\n this.knownGeneration = remoteGen;\r\n return true;\r\n }\r\n return false;\r\n }\r\n\r\n getGeneration(): number {\r\n return this.knownGeneration;\r\n }\r\n\r\n getBackendName(): 'sqlite' | 'degraded' {\r\n return 'sqlite';\r\n }\r\n}\r\n\r\n// ── Graceful Degrade Fallback ────────────────────────────────────────\r\n//\r\n// Phase 2 debt-zero rule: mini-skills have NO writable JSON fallback.\r\n// In JSON-only environments (no better-sqlite3), reads return empty\r\n// and writes are no-ops with a warning. This prevents a parallel\r\n// canonical JSON write path from existing alongside SQLite.\r\n\r\nexport class MiniSkillGracefulDegrade implements MiniSkillStore {\r\n private warned = false;\r\n\r\n private warn(): void {\r\n if (!this.warned) {\r\n console.error('[memorix] MiniSkillStore: SQLite unavailable — mini-skills are disabled (read-only empty). Install better-sqlite3 for full functionality.');\r\n this.warned = true;\r\n }\r\n }\r\n\r\n async init(_dataDir: string): Promise<void> {\r\n this.warn();\r\n }\r\n\r\n async loadAll(): Promise<MiniSkill[]> { return []; }\r\n async loadByProject(_projectId: string): Promise<MiniSkill[]> { return []; }\r\n async loadIdCounter(): Promise<number> { return 1; }\r\n\r\n async insert(_skill: MiniSkill): Promise<void> { this.warn(); }\r\n async update(_skill: MiniSkill): Promise<void> { this.warn(); }\r\n async remove(_id: number): Promise<void> { this.warn(); }\r\n async saveIdCounter(_nextId: number): Promise<void> { /* no-op */ }\r\n async atomicInsertWithId(skillWithoutId: Omit<MiniSkill, 'id'>): Promise<MiniSkill> {\r\n this.warn();\r\n return { ...skillWithoutId, id: 0 } as MiniSkill;\r\n }\r\n\r\n async ensureFresh(): Promise<boolean> { return false; }\r\n getGeneration(): number { return 0; }\r\n getBackendName(): 'sqlite' | 'degraded' { return 'degraded'; }\r\n}\r\n\r\n// ── Singleton access ────────────────────────────────────────────────\r\n\r\nlet _store: MiniSkillStore | null = null;\r\nlet _storeDataDir: string | null = null;\r\n\r\nexport function isMiniSkillStoreInitialized(): boolean {\r\n return _store !== null;\r\n}\r\n\r\nexport function getMiniSkillStore(): MiniSkillStore {\r\n if (!_store) {\r\n throw new Error('[memorix] MiniSkillStore not initialized — call initMiniSkillStore() first');\r\n }\r\n return _store;\r\n}\r\n\r\nexport function resetMiniSkillStore(): void {\r\n _store = null;\r\n _storeDataDir = null;\r\n}\r\n\r\nexport async function initMiniSkillStore(dataDir: string): Promise<MiniSkillStore> {\r\n if (_store && _storeDataDir === dataDir) return _store;\r\n\r\n _store = null;\r\n _storeDataDir = null;\r\n\r\n // Try SQLite first\r\n try {\r\n const store = new MiniSkillSqliteStore();\r\n await store.init(dataDir);\r\n _store = store;\r\n _storeDataDir = dataDir;\r\n return store;\r\n } catch (err) {\r\n console.error(`[memorix] MiniSkillSqliteStore unavailable, running in degraded read-only mode: ${err instanceof Error ? err.message : err}`);\r\n }\r\n\r\n // Fallback: graceful degrade (no writable JSON backend per debt-zero rule)\r\n const store = new MiniSkillGracefulDegrade();\r\n await store.init(dataDir);\r\n _store = store;\r\n _storeDataDir = dataDir;\r\n return store;\r\n}\r\n","/**\r\n * Token Budget Manager\r\n *\r\n * Provides token counting and budget management for Progressive Disclosure.\r\n * Source: gpt-tokenizer (737 stars, JS port of OpenAI's tiktoken)\r\n *\r\n * Used by the Compact Engine to determine which layer of detail\r\n * fits within the caller's token budget.\r\n */\r\n\r\nimport { countTokens, isWithinTokenLimit } from 'gpt-tokenizer';\r\n\r\n/**\r\n * Count tokens in a string.\r\n */\r\nexport function countTextTokens(text: string): number {\r\n return countTokens(text);\r\n}\r\n\r\n/**\r\n * Check if text fits within a token limit.\r\n * Returns the token count if within limit, false otherwise.\r\n */\r\nexport function fitsInBudget(text: string, limit: number): number | false {\r\n return isWithinTokenLimit(text, limit);\r\n}\r\n\r\n/**\r\n * Truncate text to fit within a token budget.\r\n * Truncates at sentence boundaries when possible.\r\n */\r\nexport function truncateToTokenBudget(text: string, budget: number): string {\r\n if (fitsInBudget(text, budget) !== false) {\r\n return text;\r\n }\r\n\r\n // Binary search for the right length\r\n const sentences = text.split(/(?<=[.!?])\\s+/);\r\n let result = '';\r\n\r\n for (const sentence of sentences) {\r\n const candidate = result ? `${result} ${sentence}` : sentence;\r\n if (fitsInBudget(candidate, budget) === false) {\r\n break;\r\n }\r\n result = candidate;\r\n }\r\n\r\n // If no complete sentence fits, truncate by characters\r\n if (!result) {\r\n // Rough estimate: 1 token ≈ 4 chars for English, ≈ 1.5 chars for Chinese\r\n const estimatedChars = budget * 2;\r\n result = text.slice(0, estimatedChars);\r\n // Refine\r\n while (fitsInBudget(result, budget) === false && result.length > 0) {\r\n result = result.slice(0, Math.floor(result.length * 0.9));\r\n }\r\n if (result.length < text.length) {\r\n result += '...';\r\n }\r\n }\r\n\r\n return result;\r\n}\r\n\r\n/**\r\n * Estimate the token cost of an IndexEntry line.\r\n * Used to predict compact index size.\r\n */\r\nexport function estimateIndexEntryTokens(title: string): number {\r\n // Format: \"| #ID | Time | Icon | Title | ~Tokens |\"\r\n // Overhead is roughly 15 tokens for formatting\r\n return countTextTokens(title) + 15;\r\n}\r\n","/**\r\n * Mini-Skills Engine — Promoted memories that never decay\r\n *\r\n * Converts important observations into permanent, actionable \"mini-skills\"\r\n * that are automatically injected into agent context during session_start.\r\n *\r\n * Unlike generic SKILL.md files from marketplaces, mini-skills are:\r\n * - Derived from YOUR project's actual memories (gotchas, decisions, fixes)\r\n * - Immune from retention decay (permanent knowledge)\r\n * - Auto-injected at session start (agents proactively apply them)\r\n * - Cross-IDE shared (stored in ~/.memorix/data/ alongside observations)\r\n *\r\n * Lifecycle: observation → memorix_promote → mini-skill → session_start injection\r\n */\r\n\r\nimport type { MiniSkill, Observation, SourceSnapshot, SnapshotObservation, KnowledgeLayer, DocumentType, MemorixDocument } from '../types.js';\r\nimport { getMiniSkillStore } from '../store/mini-skill-store.js';\r\nimport { countTextTokens } from '../compact/token-budget.js';\r\n\r\n// Hard filter: command execution logs are not promotable knowledge\r\nconst COMMAND_LOG_TITLE = /^(Ran:|Command:|Executed:)\\s/i;\r\n\r\n// ── Promote observations to mini-skills ──────────────────────────\r\n\r\nexport interface PromoteOptions {\r\n /** Override auto-generated trigger description */\r\n trigger?: string;\r\n /** Override auto-generated instruction */\r\n instruction?: string;\r\n /** Extra tags */\r\n tags?: string[];\r\n /** Bypass R2 (no command logs) and R3 (has content) validation. Cannot bypass R1 (sources must exist). */\r\n force?: boolean;\r\n}\r\n\r\n/** Provenance status of a mini-skill relative to its source observations */\r\nexport type ProvenanceStatus =\r\n | 'verified' // all source observations exist and are active\r\n | 'partial' // some source observations exist\r\n | 'snapshot-only' // no sources available, but snapshot exists\r\n | 'legacy'; // no snapshot AND no sources (unverifiable)\r\n\r\n/**\r\n * Promote one or more observations into a mini-skill.\r\n * The source observations are NOT deleted — they remain in the observation store\r\n * but the mini-skill is the permanent, never-decaying version.\r\n */\r\nexport async function promoteToMiniSkill(\r\n projectDir: string,\r\n projectId: string,\r\n observations: Observation[],\r\n options?: PromoteOptions,\r\n): Promise<MiniSkill> {\r\n // ── Promote-time validation ────────────────────────────────────\r\n // R1a: Sources must exist (cannot be bypassed)\r\n if (observations.length === 0) {\r\n throw new Error('Cannot promote: no source observations provided');\r\n }\r\n\r\n // R1b: All sources must be active — stale/archived knowledge must never be\r\n // permanently promoted. This check is NOT bypassable by force=true.\r\n const nonActive = observations.filter(o => (o.status ?? 'active') !== 'active');\r\n if (nonActive.length > 0) {\r\n throw new Error(\r\n `Cannot promote: ${nonActive.length} observation(s) are not active. ` +\r\n `Blocked: ${nonActive.map(o => `#${o.id} (${o.status ?? 'unknown'})`).join(', ')}. ` +\r\n `Only active observations can be promoted to permanent knowledge.`,\r\n );\r\n }\r\n\r\n if (!options?.force) {\r\n // R2: No command-log noise\r\n const commandLogs = observations.filter(o => COMMAND_LOG_TITLE.test(o.title));\r\n if (commandLogs.length > 0) {\r\n throw new Error(\r\n `Cannot promote command execution logs — use a knowledge observation instead. ` +\r\n `Blocked: ${commandLogs.map(o => `#${o.id} \"${o.title.substring(0, 60)}\"`).join(', ')}. ` +\r\n `Use force=true to override.`,\r\n );\r\n }\r\n\r\n // R3: Has substantive content\r\n const hasContent = observations.some(\r\n o => (o.narrative && o.narrative.trim().length > 0) ||\r\n (o.facts && o.facts.length > 0 && o.facts.some(f => f.trim().length > 0)),\r\n );\r\n if (!hasContent) {\r\n throw new Error(\r\n 'Cannot promote: source observations have no substantive content (empty narrative and facts). ' +\r\n 'Use force=true to override.',\r\n );\r\n }\r\n }\r\n\r\n // ── Freeze source snapshot (immutable provenance proof) ────────\r\n const snapshot = createSourceSnapshot(observations);\r\n const snapshotJson = JSON.stringify(snapshot);\r\n\r\n const store = getMiniSkillStore();\r\n\r\n // Auto-generate content from observations\r\n const title = generateTitle(observations);\r\n const instruction = options?.instruction || generateInstruction(observations);\r\n const trigger = options?.trigger || generateTrigger(observations);\r\n const facts = extractFacts(observations);\r\n const tags = [\r\n ...(options?.tags || []),\r\n ...extractTags(observations),\r\n ];\r\n\r\n const now = new Date().toISOString();\r\n\r\n // Atomic: ID allocation + insert + counter bump in a single SQLite transaction.\r\n // Prevents concurrent promotes from receiving the same ID.\r\n const skill = await store.atomicInsertWithId({\r\n sourceObservationIds: observations.map(o => o.id),\r\n sourceEntity: observations[0]?.entityName || 'unknown',\r\n title,\r\n instruction,\r\n trigger,\r\n facts,\r\n projectId,\r\n createdAt: now,\r\n usedCount: 0,\r\n tags: [...new Set(tags)],\r\n sourceSnapshot: snapshotJson,\r\n updatedAt: now,\r\n });\r\n\r\n return skill;\r\n}\r\n\r\n// ── Load & query mini-skills ─────────────────────────────────────\r\n\r\n/**\r\n * Load all mini-skills for a project.\r\n */\r\nexport async function loadMiniSkills(\r\n projectDir: string,\r\n projectId?: string,\r\n): Promise<MiniSkill[]> {\r\n const store = getMiniSkillStore();\r\n if (!projectId) return store.loadAll();\r\n return store.loadByProject(projectId);\r\n}\r\n\r\n/**\r\n * Load all mini-skills (unfiltered).\r\n */\r\nexport async function loadAllMiniSkills(projectDir: string): Promise<MiniSkill[]> {\r\n return getMiniSkillStore().loadAll();\r\n}\r\n\r\n/**\r\n * Delete a mini-skill by ID.\r\n */\r\nexport async function deleteMiniSkill(\r\n projectDir: string,\r\n skillId: number,\r\n): Promise<boolean> {\r\n const store = getMiniSkillStore();\r\n const all = await store.loadAll();\r\n const exists = all.some(s => s.id === skillId);\r\n if (!exists) return false;\r\n await store.remove(skillId);\r\n return true;\r\n}\r\n\r\n/**\r\n * Increment usedCount for skills that were injected in session_start.\r\n */\r\nexport async function recordMiniSkillUsage(\r\n projectDir: string,\r\n skillIds: number[],\r\n): Promise<void> {\r\n if (skillIds.length === 0) return;\r\n const store = getMiniSkillStore();\r\n const existing = await store.loadAll();\r\n for (const skill of existing) {\r\n if (skillIds.includes(skill.id)) {\r\n skill.usedCount++;\r\n await store.update(skill);\r\n }\r\n }\r\n}\r\n\r\n// ── Format mini-skills for session injection ─────────────────────\r\n\r\n/**\r\n * Format mini-skills for injection into session_start context.\r\n * Returns a markdown string ready to append to session context.\r\n */\r\nexport function formatMiniSkillsForInjection(skills: MiniSkill[]): string {\r\n if (skills.length === 0) return '';\r\n\r\n const lines = [\r\n `## [SESSION] Project Mini-Skills (${skills.length} active)`,\r\n '',\r\n ];\r\n\r\n for (const skill of skills) {\r\n lines.push(`### ${skill.title}`);\r\n lines.push(`**Do**: ${skill.instruction}`);\r\n lines.push(`**When**: ${skill.trigger}`);\r\n if (skill.facts.length > 0) {\r\n for (const fact of skill.facts) {\r\n lines.push(`- ${fact}`);\r\n }\r\n }\r\n lines.push('');\r\n }\r\n\r\n return lines.join('\\n');\r\n}\r\n\r\n// ── Auto-generation helpers ──────────────────────────────────────\r\n\r\nfunction generateTitle(observations: Observation[]): string {\r\n if (observations.length === 1) {\r\n return observations[0].title;\r\n }\r\n // Multiple observations — use the first one's title as base\r\n return observations[0].title;\r\n}\r\n\r\nfunction generateInstruction(observations: Observation[]): string {\r\n // Convert narrative into imperative instruction\r\n const obs = observations[0];\r\n const narrative = obs.narrative || '';\r\n\r\n // For gotchas, flip to \"avoid\" instruction\r\n if (obs.type === 'gotcha') {\r\n return `Avoid: ${narrative.split('\\n')[0]}`;\r\n }\r\n // For decisions, state the chosen approach\r\n if (obs.type === 'decision') {\r\n return `Follow: ${narrative.split('\\n')[0]}`;\r\n }\r\n // For problem-solution, state the solution\r\n if (obs.type === 'problem-solution') {\r\n return `Apply fix: ${narrative.split('\\n')[0]}`;\r\n }\r\n // Default: use narrative as-is\r\n return narrative.split('\\n')[0] || obs.title;\r\n}\r\n\r\nfunction generateTrigger(observations: Observation[]): string {\r\n const obs = observations[0];\r\n\r\n // Use entity name + file paths as trigger context\r\n const parts: string[] = [];\r\n if (obs.entityName && obs.entityName !== 'unknown') {\r\n parts.push(`Working on ${obs.entityName}`);\r\n }\r\n if (obs.filesModified.length > 0) {\r\n parts.push(`touching ${obs.filesModified.slice(0, 3).join(', ')}`);\r\n }\r\n if (obs.concepts.length > 0) {\r\n parts.push(`involving ${obs.concepts.slice(0, 3).join(', ')}`);\r\n }\r\n\r\n return parts.length > 0 ? parts.join('; ') : `Related to ${obs.title}`;\r\n}\r\n\r\nfunction extractFacts(observations: Observation[]): string[] {\r\n const facts = new Set<string>();\r\n for (const obs of observations) {\r\n for (const f of obs.facts) {\r\n facts.add(f);\r\n }\r\n }\r\n return [...facts].slice(0, 10);\r\n}\r\n\r\nfunction extractTags(observations: Observation[]): string[] {\r\n const tags = new Set<string>();\r\n for (const obs of observations) {\r\n tags.add(obs.type);\r\n for (const c of obs.concepts) {\r\n if (c.length <= 30) tags.add(c.toLowerCase());\r\n }\r\n }\r\n return [...tags].slice(0, 10);\r\n}\r\n\r\n// ── Provenance helpers (Phase 3a) ────────────────────────────────\r\n\r\n/**\r\n * Create an immutable source snapshot from observations at promote time.\r\n * Contains the minimum field set needed for self-contained provenance proof.\r\n */\r\nfunction createSourceSnapshot(observations: Observation[]): SourceSnapshot {\r\n return {\r\n observations: observations.map((o): SnapshotObservation => ({\r\n id: o.id,\r\n title: o.title,\r\n type: o.type,\r\n narrative: o.narrative,\r\n facts: [...o.facts],\r\n entityName: o.entityName,\r\n projectId: o.projectId,\r\n createdAt: o.createdAt,\r\n sourceDetail: o.sourceDetail,\r\n })),\r\n promotedAt: new Date().toISOString(),\r\n };\r\n}\r\n\r\n/**\r\n * Resolve the provenance status of a mini-skill by checking whether its\r\n * source observations still exist.\r\n *\r\n * @param skill The mini-skill to check\r\n * @param getObservationById Lookup function: (id) => Observation | undefined\r\n */\r\nexport function resolveProvenanceStatus(\r\n skill: MiniSkill,\r\n getObservationById: (id: number) => { id: number; status?: string } | undefined,\r\n): ProvenanceStatus {\r\n const ids = skill.sourceObservationIds;\r\n if (ids.length === 0) {\r\n return skill.sourceSnapshot ? 'snapshot-only' : 'legacy';\r\n }\r\n const found = ids.filter(id => {\r\n const obs = getObservationById(id);\r\n return obs && (obs.status ?? 'active') === 'active';\r\n });\r\n if (found.length === ids.length) return 'verified';\r\n if (found.length > 0) return 'partial';\r\n return skill.sourceSnapshot ? 'snapshot-only' : 'legacy';\r\n}\r\n\r\n// ── Knowledge Layer helpers (Phase 3a) ───────────────────────────\r\n\r\n/**\r\n * Resolve the knowledge layer for a document based on its type and source.\r\n * This is computed at index time — NOT stored in SQLite.\r\n */\r\nexport function resolveKnowledgeLayer(\r\n documentType: DocumentType,\r\n sourceDetail?: string,\r\n source?: string,\r\n): KnowledgeLayer {\r\n if (documentType === 'mini-skill') return 'promoted';\r\n if (sourceDetail === 'git-ingest' || source === 'git') return 'evidence';\r\n return 'project-truth';\r\n}\r\n\r\n/**\r\n * Convert a MiniSkill into a MemorixDocument for Orama indexing.\r\n * The document carries documentType='mini-skill' and knowledgeLayer='promoted'.\r\n */\r\nexport function miniSkillToDocument(skill: MiniSkill): MemorixDocument {\r\n const content = skill.instruction + '\\n' + skill.facts.join('\\n');\r\n return {\r\n id: `skill:${encodeURIComponent(skill.projectId)}:${skill.id}`,\r\n observationId: skill.id,\r\n entityName: skill.sourceEntity,\r\n type: 'mini-skill',\r\n title: skill.title,\r\n narrative: skill.instruction,\r\n facts: skill.facts.join('\\n'),\r\n filesModified: '',\r\n concepts: skill.tags.join(', '),\r\n tokens: countTextTokens(content),\r\n createdAt: skill.createdAt,\r\n projectId: skill.projectId,\r\n accessCount: skill.usedCount,\r\n lastAccessedAt: '',\r\n status: 'active',\r\n source: 'agent',\r\n sourceDetail: 'explicit',\r\n valueCategory: 'core',\r\n documentType: 'mini-skill',\r\n knowledgeLayer: 'promoted',\r\n };\r\n}\r\n","/**\r\n * memorix.yml Configuration Loader\r\n *\r\n * Loads YAML configuration from project-level and user-level paths.\r\n * This is the platform-grade config format — Memorix as a central hub,\r\n * not just an MCP plugin.\r\n *\r\n * Priority chain (highest wins):\r\n * 1. Environment variables\r\n * 2. ./memorix.yml (project-level, in project root)\r\n * 3. ~/.memorix/memorix.yml (user-level, global defaults)\r\n * 4. ~/.memorix/config.json (legacy, backward compat)\r\n * 5. Hardcoded defaults\r\n *\r\n * Inspired by: Cipher's cipher.yml, Docker's docker-compose.yml\r\n */\r\n\r\nimport { existsSync, readFileSync } from 'node:fs';\r\nimport { join } from 'node:path';\r\nimport { homedir } from 'node:os';\r\n\r\n// ─── Types ───────────────────────────────────────────────────────────\r\n\r\nexport interface MemorixYamlConfig {\r\n /** LLM provider configuration */\r\n llm?: {\r\n provider?: 'openai' | 'anthropic' | 'openrouter' | string;\r\n model?: string;\r\n apiKey?: string;\r\n baseUrl?: string;\r\n };\r\n\r\n /** Embedding / vector search configuration */\r\n embedding?: {\r\n provider?: 'off' | 'api' | 'fastembed' | 'transformers' | 'auto';\r\n model?: string;\r\n apiKey?: string;\r\n baseUrl?: string;\r\n dimensions?: number;\r\n };\r\n\r\n /** Git-Memory pipeline configuration */\r\n git?: {\r\n /** Auto-install post-commit hook on first run (default: false) */\r\n autoHook?: boolean;\r\n /** Ingest commits as memories on post-commit (default: true when hook installed) */\r\n ingestOnCommit?: boolean;\r\n /** Maximum diff size (chars) to include in memory (default: 500) */\r\n maxDiffSize?: number;\r\n /** Skip merge commits (default: true) */\r\n skipMergeCommits?: boolean;\r\n /** File patterns to exclude from git memory (glob) */\r\n excludePatterns?: string[];\r\n /** Additional commit message patterns to treat as noise (regex strings) */\r\n noiseKeywords?: string[];\r\n };\r\n\r\n /** Behavior settings */\r\n behavior?: {\r\n /** Session start injection mode */\r\n sessionInject?: 'full' | 'minimal' | 'silent';\r\n /** Show sync advisory on first search */\r\n syncAdvisory?: boolean;\r\n /** Auto-archive expired memories on startup */\r\n autoCleanup?: boolean;\r\n /** Formation Pipeline mode */\r\n formationMode?: 'active' | 'shadow' | 'fallback';\r\n };\r\n\r\n /** MCP server mode configuration (when Memorix runs as hub) */\r\n server?: {\r\n /** Transport: stdio (default) or http */\r\n transport?: 'stdio' | 'http';\r\n /** HTTP port (only for http transport) */\r\n port?: number;\r\n /** Enable Web Dashboard */\r\n dashboard?: boolean;\r\n /** Dashboard port (default: 3210) */\r\n dashboardPort?: number;\r\n };\r\n\r\n /** Autonomous Agent Team settings */\n team?: {\r\n /** Enable autonomous Agent Team features */\n enabled?: boolean;\r\n /** Shared workspace memory collection */\r\n workspaceCollection?: string;\r\n };\r\n\r\n /** Additional MCP servers to aggregate (Memorix as hub) */\r\n mcpServers?: Record<string, {\r\n type?: 'stdio' | 'sse';\r\n command?: string;\r\n args?: string[];\r\n env?: Record<string, string>;\r\n url?: string;\r\n }>;\r\n}\r\n\r\n// ─── Loader ──────────────────────────────────────────────────────────\r\n\r\n// Per-project config cache — keyed by resolved projectRoot string.\r\n// null key = user-level-only config (no project root).\r\nconst configCache = new Map<string | null, MemorixYamlConfig>();\r\n\r\n/** Stored project root — set once by server init, used by all no-arg loadYamlConfig() calls */\r\nlet globalProjectRoot: string | null = null;\r\n\r\n/**\r\n * Set the project root for YAML config resolution.\r\n * Call this once during server init so all config getters\r\n * (which call loadYamlConfig() without args) pick up project-level memorix.yml.\r\n *\r\n * In HTTP mode, this is called per-session/switchProject — the Map cache\r\n * preserves configs for all projects simultaneously.\r\n */\r\nexport function initProjectRoot(root: string): void {\r\n globalProjectRoot = root;\r\n // Invalidate this project's cache entry so file changes are picked up\r\n configCache.delete(root);\r\n}\r\n\r\n/**\r\n * Load memorix.yml from project root and/or user home.\r\n * Project-level overrides user-level (shallow merge per top-level key).\r\n */\r\nexport function loadYamlConfig(projectRoot?: string | null): MemorixYamlConfig {\r\n // When null is explicitly passed, skip global fallback (user-level config only).\r\n // When undefined (no arg), fall back to globally-initialized project root.\r\n const resolvedRoot = projectRoot === null ? null : (projectRoot ?? globalProjectRoot ?? null);\r\n\r\n // Per-project cache hit\r\n const cached = configCache.get(resolvedRoot ?? null);\r\n if (cached) return cached;\r\n\r\n const userYaml = join(homedir(), '.memorix', 'memorix.yml');\r\n const projectYaml = resolvedRoot ? join(resolvedRoot, 'memorix.yml') : null;\r\n\r\n let userConfig: MemorixYamlConfig = {};\r\n let projectConfig: MemorixYamlConfig = {};\r\n\r\n // Load user-level config\r\n if (existsSync(userYaml)) {\r\n try {\r\n userConfig = parseYaml(readFileSync(userYaml, 'utf-8'));\r\n } catch (err) {\r\n console.error(`[memorix] Warning: Failed to parse ${userYaml}: ${err}`);\r\n }\r\n }\r\n\r\n // Load project-level config (overrides user-level)\r\n if (projectYaml && existsSync(projectYaml)) {\r\n try {\r\n projectConfig = parseYaml(readFileSync(projectYaml, 'utf-8'));\r\n } catch (err) {\r\n console.error(`[memorix] Warning: Failed to parse ${projectYaml}: ${err}`);\r\n }\r\n }\r\n\r\n // Shallow merge: project-level top keys override user-level\r\n const merged: MemorixYamlConfig = {\r\n ...userConfig,\r\n ...projectConfig,\r\n // Deep merge for nested objects where both exist\r\n llm: { ...userConfig.llm, ...projectConfig.llm },\r\n embedding: { ...userConfig.embedding, ...projectConfig.embedding },\r\n git: { ...userConfig.git, ...projectConfig.git },\r\n behavior: { ...userConfig.behavior, ...projectConfig.behavior },\r\n server: { ...userConfig.server, ...projectConfig.server },\r\n team: { ...userConfig.team, ...projectConfig.team },\r\n };\r\n configCache.set(resolvedRoot ?? null, merged);\r\n\r\n return merged;\r\n}\r\n\r\n/**\r\n * Reset cached YAML config (for testing or project switching).\r\n * Invalidates all cached entries, or a specific projectRoot if provided.\r\n */\r\nexport function resetYamlConfigCache(projectRoot?: string | null): void {\r\n if (projectRoot !== undefined) {\r\n configCache.delete(projectRoot ?? null);\r\n } else {\r\n configCache.clear();\r\n }\r\n}\r\n\r\n/**\r\n * Parse YAML string using gray-matter's internal js-yaml.\r\n * gray-matter is already a dependency — no new deps needed.\r\n */\r\nfunction parseYaml(content: string): MemorixYamlConfig {\r\n // gray-matter uses js-yaml internally; we import it from there\r\n // But for simplicity and reliability, use a basic YAML parser\r\n // that handles the flat config structure we need.\r\n try {\r\n // Dynamic import of js-yaml through gray-matter's dependency\r\n // eslint-disable-next-line @typescript-eslint/no-require-imports\r\n const yaml = require('js-yaml');\r\n return yaml.load(content) as MemorixYamlConfig ?? {};\r\n } catch {\r\n // Fallback: try gray-matter which wraps js-yaml\r\n try {\r\n const matter = require('gray-matter');\r\n const parsed = matter(`---\\n${content}\\n---`);\r\n return (parsed.data as MemorixYamlConfig) ?? {};\r\n } catch {\r\n console.error('[memorix] YAML parse failed — check memorix.yml syntax');\r\n return {};\r\n }\r\n }\r\n}\r\n","/**\r\n * .env Loader for Memorix\r\n *\r\n * Loads secrets from project-level .env file.\r\n * This is the \"secrets-only\" complement to memorix.yml (behavior config).\r\n *\r\n * Design principle:\r\n * memorix.yml = behavior configuration (structured YAML)\r\n * .env = secrets only (API keys, base URLs, tokens)\r\n *\r\n * Priority (highest wins):\r\n * 1. System environment variables (from MCP host `env` field or shell)\r\n * 2. Project .env file (./ .env in project root)\r\n * 3. User .env file (~/.memorix/.env) — advanced, not promoted\r\n *\r\n * Unlike Cipher which puts EVERYTHING in .env (178 lines of flat config),\r\n * Memorix only uses .env for sensitive values. Structured settings stay in YAML.\r\n */\r\n\r\nimport { existsSync, readFileSync } from 'node:fs';\r\nimport { join } from 'node:path';\r\nimport { homedir } from 'node:os';\r\nimport { parse } from 'dotenv';\r\n\r\n// ─── State ───\r\n\r\nlet dotenvLoaded = false;\r\nlet dotenvProjectRoot: string | null = null;\r\n\r\n/** Track which .env files were loaded (for diagnostics) */\r\nconst loadedEnvFiles: string[] = [];\r\n/** Track keys injected by .env so project switches can cleanly restore process.env */\r\nconst injectedKeys = new Set<string>();\r\n\r\nfunction loadEnvFile(filePath: string): void {\r\n if (!existsSync(filePath)) return;\r\n\r\n const parsed = parse(readFileSync(filePath, 'utf-8'));\r\n for (const [key, value] of Object.entries(parsed)) {\r\n if (!(key in process.env)) {\r\n process.env[key] = value;\r\n injectedKeys.add(key);\r\n }\r\n }\r\n\r\n loadedEnvFiles.push(filePath);\r\n}\r\n\r\ninterface DotenvLoadOptions {\r\n userHomeDir?: string;\r\n}\r\n\r\n// ─── Public API ───\r\n\r\n/**\r\n * Load .env files into process.env.\r\n * Called once during startup. Does NOT override existing env vars.\r\n *\r\n * @param projectRoot - Project root directory (for project-level .env)\r\n */\r\nexport function loadDotenv(projectRoot?: string, options: DotenvLoadOptions = {}): void {\r\n if (dotenvLoaded && dotenvProjectRoot === (projectRoot ?? null)) return;\r\n\r\n loadedEnvFiles.length = 0;\r\n\r\n // Loading order = priority order (with override: false, first value wins).\r\n // System env vars already exist in process.env, so they always win.\r\n\r\n // 1. Project-level .env — highest .env priority, load first\r\n if (projectRoot) {\r\n loadEnvFile(join(projectRoot, '.env'));\r\n }\r\n\r\n // 2. User-level .env (~/.memorix/.env) — lowest .env priority, load second\r\n // (override: false means it only fills in keys not already set)\r\n loadEnvFile(join(options.userHomeDir ?? homedir(), '.memorix', '.env'));\r\n\r\n dotenvLoaded = true;\r\n dotenvProjectRoot = projectRoot ?? null;\r\n}\r\n\r\n/**\r\n * Reset dotenv state (for testing or project switch).\r\n */\r\nexport function resetDotenv(): void {\r\n for (const key of injectedKeys) {\r\n delete process.env[key];\r\n }\r\n injectedKeys.clear();\r\n dotenvLoaded = false;\r\n dotenvProjectRoot = null;\r\n loadedEnvFiles.length = 0;\r\n}\r\n\r\n/**\r\n * Get list of .env files that were loaded (for diagnostics).\r\n */\r\nexport function getLoadedEnvFiles(): readonly string[] {\r\n return loadedEnvFiles;\r\n}\r\n\r\n// ─── Supported .env variables ───\r\n// These are the ONLY variables Memorix reads from .env.\r\n// All are secrets or endpoint URLs — no behavior config.\r\n//\r\n// MEMORIX_LLM_API_KEY — LLM provider API key\r\n// MEMORIX_LLM_BASE_URL — Custom LLM endpoint\r\n// MEMORIX_EMBEDDING_API_KEY — Embedding API key (falls back to LLM key)\r\n// MEMORIX_EMBEDDING_BASE_URL — Custom embedding endpoint\r\n// MEMORIX_API_KEY — Unified fallback key (for both LLM + embedding)\r\n// OPENAI_API_KEY — OpenAI compatibility (lowest priority)\r\n// ANTHROPIC_API_KEY — Anthropic compatibility\r\n// OPENROUTER_API_KEY — OpenRouter compatibility\r\n","/**\r\n * Unified Configuration Reader\r\n *\r\n * Priority chain (highest wins):\r\n * 1. Environment variables (from MCP JSON `env` field or system env)\r\n * 2. memorix.yml (project-level ./memorix.yml > user-level ~/.memorix/memorix.yml)\r\n * 3. ~/.memorix/config.json (legacy, written by `memorix configure` TUI)\r\n * 4. Hardcoded defaults\r\n *\r\n * This ensures both YAML platform config and TUI config take effect,\r\n * while env vars can still override for advanced users.\r\n */\r\n\r\nimport { existsSync, readFileSync } from 'node:fs';\r\nimport { join } from 'node:path';\r\nimport { homedir } from 'node:os';\r\nimport { loadYamlConfig, type MemorixYamlConfig } from './config/yaml-loader.js';\r\nexport { loadDotenv, resetDotenv, getLoadedEnvFiles } from './config/dotenv-loader.js';\r\n\r\n// ─── Types ───────────────────────────────────────────────────────────\r\n\r\nexport interface MemorixConfig {\r\n llm?: {\r\n provider?: string;\r\n apiKey?: string;\r\n model?: string;\r\n baseUrl?: string;\r\n };\r\n embedding?: string;\r\n embeddingApi?: {\r\n apiKey?: string;\r\n baseUrl?: string;\r\n model?: string;\r\n dimensions?: number;\r\n };\r\n}\r\n\r\n// ─── Singleton ───────────────────────────────────────────────────────\r\n\r\nlet cachedConfig: MemorixConfig | null = null;\r\n\r\n/**\r\n * Load config from ~/.memorix/config.json.\r\n * Cached after first load. Returns empty object on failure.\r\n */\r\nexport function loadFileConfig(): MemorixConfig {\r\n if (cachedConfig !== null) return cachedConfig;\r\n\r\n const configPath = join(homedir(), '.memorix', 'config.json');\r\n try {\r\n if (existsSync(configPath)) {\r\n cachedConfig = JSON.parse(readFileSync(configPath, 'utf-8'));\r\n return cachedConfig!;\r\n }\r\n } catch {\r\n // Corrupt or unreadable — ignore\r\n }\r\n cachedConfig = {};\r\n return cachedConfig;\r\n}\r\n\r\n/**\r\n * Reset cached config (for testing).\r\n */\r\nexport function resetConfigCache(): void {\r\n cachedConfig = null;\r\n}\r\n\r\n// ─── Resolved Getters (env > config.json > default) ──────────────────\r\n\r\n/** LLM API key: env > memorix.yml > config.json > generic env fallbacks */\r\nexport function getLLMApiKey(): string | undefined {\r\n return (\r\n process.env.MEMORIX_LLM_API_KEY || // LLM-specific (优先级最高)\r\n process.env.MEMORIX_API_KEY || // Unified API key (fallback)\r\n loadYamlConfig().llm?.apiKey ||\r\n loadFileConfig().llm?.apiKey ||\r\n process.env.OPENAI_API_KEY ||\r\n process.env.ANTHROPIC_API_KEY ||\r\n process.env.OPENROUTER_API_KEY ||\r\n undefined\r\n );\r\n}\r\n\r\n/** LLM provider: env > memorix.yml > config.json > auto-detect */\r\nexport function getLLMProvider(): string {\r\n if (process.env.MEMORIX_LLM_PROVIDER) return process.env.MEMORIX_LLM_PROVIDER;\r\n const yml = loadYamlConfig();\r\n if (yml.llm?.provider) return yml.llm.provider;\r\n const cfg = loadFileConfig();\r\n if (cfg.llm?.provider) return cfg.llm.provider;\r\n // Auto-detect from env var names\r\n if (process.env.ANTHROPIC_API_KEY && !process.env.OPENAI_API_KEY) return 'anthropic';\r\n if (process.env.OPENROUTER_API_KEY && !process.env.OPENAI_API_KEY) return 'openrouter';\r\n return 'openai';\r\n}\r\n\r\n/** LLM model: env > memorix.yml > config.json > provider default */\r\nexport function getLLMModel(providerDefault: string): string {\r\n return process.env.MEMORIX_LLM_MODEL || loadYamlConfig().llm?.model || loadFileConfig().llm?.model || providerDefault;\r\n}\r\n\r\n/** LLM base URL: env > memorix.yml > config.json > provider default */\r\nexport function getLLMBaseUrl(providerDefault: string): string {\r\n return process.env.MEMORIX_LLM_BASE_URL || loadYamlConfig().llm?.baseUrl || loadFileConfig().llm?.baseUrl || providerDefault;\r\n}\r\n\r\n/** Embedding mode: env > memorix.yml > config.json > 'off' */\r\nexport function getEmbeddingMode(): 'off' | 'fastembed' | 'transformers' | 'api' | 'auto' {\r\n const env = process.env.MEMORIX_EMBEDDING?.toLowerCase()?.trim();\r\n if (env === 'fastembed' || env === 'transformers' || env === 'api' || env === 'auto') return env;\r\n const yml = loadYamlConfig();\r\n const ymlEmb = yml.embedding?.provider;\r\n if (ymlEmb === 'fastembed' || ymlEmb === 'transformers' || ymlEmb === 'api' || ymlEmb === 'auto') return ymlEmb;\r\n const cfg = loadFileConfig();\r\n if (cfg.embedding === 'fastembed' || cfg.embedding === 'transformers' || cfg.embedding === 'api' || cfg.embedding === 'auto') {\r\n return cfg.embedding;\r\n }\r\n return 'off';\r\n}\r\n\r\n/** Embedding API key: env > memorix.yml > config.json > LLM key fallback */\r\nexport function getEmbeddingApiKey(): string | undefined {\r\n return (\r\n process.env.MEMORIX_EMBEDDING_API_KEY || // Embedding-specific (优先级最高)\r\n process.env.MEMORIX_API_KEY || // Unified API key (fallback)\r\n process.env.MEMORIX_LLM_API_KEY ||\r\n loadYamlConfig().embedding?.apiKey ||\r\n loadFileConfig().embeddingApi?.apiKey ||\r\n loadYamlConfig().llm?.apiKey ||\r\n loadFileConfig().llm?.apiKey ||\r\n process.env.OPENAI_API_KEY ||\r\n undefined\r\n );\r\n}\r\n\r\n/** Embedding base URL: env > memorix.yml > config.json > LLM URL fallback */\r\nexport function getEmbeddingBaseUrl(): string {\r\n return (\r\n process.env.MEMORIX_EMBEDDING_BASE_URL ||\r\n loadYamlConfig().embedding?.baseUrl ||\r\n loadFileConfig().embeddingApi?.baseUrl ||\r\n process.env.MEMORIX_LLM_BASE_URL ||\r\n loadYamlConfig().llm?.baseUrl ||\r\n loadFileConfig().llm?.baseUrl ||\r\n 'https://api.openai.com/v1'\r\n );\r\n}\r\n\r\n/** Embedding model: env > memorix.yml > config.json > default */\r\nexport function getEmbeddingModel(): string {\r\n return (\r\n process.env.MEMORIX_EMBEDDING_MODEL ||\r\n loadYamlConfig().embedding?.model ||\r\n loadFileConfig().embeddingApi?.model ||\r\n 'text-embedding-3-small'\r\n );\r\n}\r\n\r\n/** Embedding dimensions override: env > memorix.yml > config.json > null (auto-detect) */\r\nexport function getEmbeddingDimensions(): number | null {\r\n const envDim = process.env.MEMORIX_EMBEDDING_DIMENSIONS;\r\n if (envDim) return parseInt(envDim, 10);\r\n const ymlDim = loadYamlConfig().embedding?.dimensions;\r\n if (ymlDim) return ymlDim;\r\n const cfgDim = loadFileConfig().embeddingApi?.dimensions;\r\n if (cfgDim) return cfgDim;\r\n return null;\r\n}\r\n\r\n// ─── YAML-specific getters (new config sections) ────────────────────\r\n\r\n/** Git-Memory pipeline config */\r\nexport function getGitConfig(): NonNullable<MemorixYamlConfig['git']> {\r\n return loadYamlConfig().git ?? {};\r\n}\r\n\r\n/** Server config */\r\nexport function getServerConfig(): NonNullable<MemorixYamlConfig['server']> {\r\n return loadYamlConfig().server ?? {};\r\n}\r\n\r\n/** Team config */\r\nexport function getTeamConfig(): NonNullable<MemorixYamlConfig['team']> {\r\n return loadYamlConfig().team ?? {};\r\n}\r\n\r\n/** Get the full resolved YAML config (for status display) */\r\nexport { loadYamlConfig } from './config/yaml-loader.js';\r\n","/**\r\n * FastEmbed Provider\r\n *\r\n * Local ONNX-based embedding using fastembed (Qdrant).\r\n * Model: BAAI/bge-small-en-v1.5 (384 dimensions, ~30MB)\r\n *\r\n * This is an optional dependency — if fastembed is not installed,\r\n * the provider module gracefully falls back to fulltext-only search.\r\n *\r\n * Persistent disk cache: embeddings are saved to ~/.memorix/data/.embedding-cache.json\r\n * so server restarts don't need to regenerate them (saves minutes of CPU on 500+ obs).\r\n */\r\n\r\nimport { createHash } from 'node:crypto';\r\nimport { readFile, writeFile, mkdir } from 'node:fs/promises';\r\nimport { join } from 'node:path';\r\nimport { homedir } from 'node:os';\r\nimport type { EmbeddingProvider } from './provider.js';\r\n\r\nconst CACHE_DIR = process.env.MEMORIX_DATA_DIR || join(homedir(), '.memorix', 'data');\r\nconst CACHE_FILE = join(CACHE_DIR, '.embedding-cache.json');\r\n\r\n// In-memory cache keyed by text hash → embedding\r\nconst cache = new Map<string, number[]>();\r\nconst MAX_CACHE_SIZE = 5000;\r\nlet diskCacheDirty = false;\r\n\r\nfunction textHash(text: string): string {\r\n return createHash('sha256').update(text).digest('hex').slice(0, 16);\r\n}\r\n\r\nasync function loadDiskCache(): Promise<void> {\r\n try {\r\n const raw = await readFile(CACHE_FILE, 'utf-8');\r\n const entries: [string, number[]][] = JSON.parse(raw);\r\n for (const [k, v] of entries) cache.set(k, v);\r\n console.error(`[memorix] Loaded ${entries.length} cached embeddings from disk`);\r\n } catch {\r\n // No cache file or corrupt — start fresh\r\n }\r\n}\r\n\r\nasync function saveDiskCache(): Promise<void> {\r\n if (!diskCacheDirty) return;\r\n try {\r\n await mkdir(CACHE_DIR, { recursive: true });\r\n const entries = Array.from(cache.entries());\r\n await writeFile(CACHE_FILE, JSON.stringify(entries));\r\n diskCacheDirty = false;\r\n } catch {\r\n // Ignore write errors — cache is an optimization, not critical\r\n }\r\n}\r\n\r\nexport class FastEmbedProvider implements EmbeddingProvider {\r\n readonly name = 'fastembed-bge-small';\r\n readonly dimensions = 384;\r\n\r\n private model: { embed: (docs: string[], batchSize?: number) => AsyncGenerator<number[][]>; queryEmbed: (query: string) => Promise<number[]> };\r\n\r\n private constructor(model: FastEmbedProvider['model']) {\r\n this.model = model;\r\n }\r\n\r\n /**\r\n * Initialize the FastEmbed provider.\r\n * Downloads model on first use (~30MB), cached locally after.\r\n * Loads persistent embedding cache from disk.\r\n */\r\n static async create(): Promise<FastEmbedProvider> {\r\n // Dynamic import — throws if fastembed is not installed\r\n const { EmbeddingModel, FlagEmbedding } = await import('fastembed');\r\n const model = await FlagEmbedding.init({\r\n model: EmbeddingModel.BGESmallENV15,\r\n });\r\n // Load disk cache before returning — subsequent embedBatch calls will hit cache\r\n await loadDiskCache();\r\n return new FastEmbedProvider(model);\r\n }\r\n\r\n async embed(text: string): Promise<number[]> {\r\n const hash = textHash(text);\r\n const cached = cache.get(hash);\r\n if (cached) return cached;\r\n\r\n const raw = await this.model.queryEmbed(text);\r\n // Ensure plain number[] (fastembed may return Float32Array)\r\n const result = Array.from(raw) as number[];\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 this.cacheSet(hash, 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 (by hash)\r\n for (let i = 0; i < texts.length; i++) {\r\n const hash = textHash(texts[i]);\r\n const cached = cache.get(hash);\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 console.error(`[memorix] Embedding ${uncachedTexts.length}/${texts.length} uncached texts (${texts.length - uncachedTexts.length} from cache)`);\r\n let batchIdx = 0;\r\n for await (const batch of this.model.embed(uncachedTexts, 64)) {\r\n for (const vec of batch) {\r\n const originalIdx = uncachedIndices[batchIdx];\r\n const plain = Array.from(vec) as number[];\r\n results[originalIdx] = plain;\r\n this.cacheSet(textHash(uncachedTexts[batchIdx]), plain);\r\n batchIdx++;\r\n }\r\n }\r\n // Persist cache to disk after batch operations\r\n await saveDiskCache();\r\n }\r\n\r\n return results;\r\n }\r\n\r\n private cacheSet(hash: string, value: number[]): void {\r\n // Evict oldest entries if cache is full\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(hash, value);\r\n diskCacheDirty = true;\r\n }\r\n}\r\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","/**\r\n * API Embedding Provider\r\n *\r\n * Remote embedding via any OpenAI-compatible /v1/embeddings endpoint.\r\n * Works with OpenAI, DashScope/Qwen, Ollama-compatible gateways, and similar providers.\r\n */\r\n\r\nimport { createHash } from 'node:crypto';\r\nimport { readFile, writeFile, mkdir } from 'node:fs/promises';\r\nimport { join } from 'node:path';\r\nimport { homedir } from 'node:os';\r\nimport type { EmbeddingProvider } from './provider.js';\r\n\r\nconst CACHE_DIR = process.env.MEMORIX_DATA_DIR || join(homedir(), '.memorix', 'data');\r\nconst CACHE_FILE = join(CACHE_DIR, '.embedding-api-cache.json');\r\nconst DIMS_CACHE_FILE = join(CACHE_DIR, '.embedding-dims-cache.json');\r\n\r\nconst cache = new Map<string, number[]>();\r\nconst MAX_CACHE_SIZE = 10000;\r\nlet diskCacheDirty = false;\r\nlet diskSaveTimer: ReturnType<typeof setTimeout> | null = null;\r\nlet diskCacheLoaded = false;\r\nlet diskCacheLoadPromise: Promise<void> | null = null;\r\n\r\nconst MAX_INPUT_CHARS = 32000;\r\nconst MAX_CONCURRENCY = 4;\r\nconst DISK_SAVE_DEBOUNCE_MS = 5000;\r\n\r\nconst DEFAULT_MAX_BATCH_SIZE = 2048;\r\nconst DASHSCOPE_MAX_BATCH_SIZE = 10;\r\nconst MAX_RETRIES = 3;\r\nconst BASE_DELAY_MS = 500;\r\n\r\nfunction normalizeText(text: string): string {\r\n return text.replace(/\\s+/g, ' ').trim().slice(0, MAX_INPUT_CHARS);\r\n}\r\n\r\nfunction cacheNamespace(config: Pick<APIEmbeddingConfig, 'baseUrl' | 'model' | 'requestedDimensions'>): string {\r\n return [\r\n 'v2',\r\n config.baseUrl.replace(/\\/+$/, ''),\r\n config.model,\r\n config.requestedDimensions ?? 'native',\r\n ].join('|');\r\n}\r\n\r\nfunction textHash(text: string, namespace: string): string {\r\n return createHash('sha256').update(`${namespace}\\u0000${text}`).digest('hex').slice(0, 16);\r\n}\r\n\r\nasync function loadDiskCache(): Promise<void> {\r\n if (diskCacheLoaded) return;\r\n try {\r\n const raw = await readFile(CACHE_FILE, 'utf-8');\r\n const entries: [string, number[]][] = JSON.parse(raw);\r\n for (const [k, v] of entries) cache.set(k, v);\r\n console.error(`[memorix] Loaded ${entries.length} cached API embeddings from disk`);\r\n } catch {\r\n // No cache file or corrupt cache; start fresh.\r\n }\r\n diskCacheLoaded = true;\r\n}\r\n\r\n/** Start loading disk cache in background (non-blocking). */\r\nfunction startDiskCacheLoad(): void {\r\n if (diskCacheLoaded || diskCacheLoadPromise) return;\r\n diskCacheLoadPromise = loadDiskCache().catch(() => {});\r\n}\r\n\r\n/** Ensure disk cache is loaded (await if still in progress). */\r\nasync function ensureDiskCacheLoaded(): Promise<void> {\r\n if (diskCacheLoaded) return;\r\n if (diskCacheLoadPromise) { await diskCacheLoadPromise; return; }\r\n await loadDiskCache();\r\n}\r\n\r\nfunction dimsCacheKey(config: Pick<APIEmbeddingConfig, 'baseUrl' | 'model' | 'requestedDimensions'>): string {\r\n return [\r\n config.baseUrl.replace(/\\/+$/, ''),\r\n config.model,\r\n config.requestedDimensions ?? 'native',\r\n ].join('|');\r\n}\r\n\r\n/** Load cached probe dimensions from disk. Returns null if not cached. */\r\nasync function loadCachedDims(config: Pick<APIEmbeddingConfig, 'baseUrl' | 'model' | 'requestedDimensions'>): Promise<number | null> {\r\n try {\r\n const raw = await readFile(DIMS_CACHE_FILE, 'utf-8');\r\n const data = JSON.parse(raw);\r\n\r\n const key = dimsCacheKey(config);\r\n\r\n if (Array.isArray(data.entries)) {\r\n const entry = data.entries.find((candidate: unknown) =>\r\n typeof candidate === 'object' &&\r\n candidate !== null &&\r\n 'key' in candidate &&\r\n 'dimensions' in candidate &&\r\n (candidate as { key?: string }).key === key &&\r\n typeof (candidate as { dimensions?: unknown }).dimensions === 'number',\r\n ) as { dimensions: number } | undefined;\r\n if (entry) return entry.dimensions;\r\n }\r\n\r\n if (\r\n data.baseUrl === config.baseUrl &&\r\n data.model === config.model &&\r\n typeof data.dimensions === 'number' &&\r\n (data.requestedDimensions ?? null) === (config.requestedDimensions ?? null)\r\n ) {\r\n return data.dimensions;\r\n }\r\n\r\n if (\r\n data.baseUrl === config.baseUrl &&\r\n data.model === config.model &&\r\n typeof data.dimensions === 'number' &&\r\n (config.requestedDimensions ?? null) === null &&\r\n !('requestedDimensions' in data)\r\n ) {\r\n return data.dimensions;\r\n }\r\n } catch { /* no cache or corrupt */ }\r\n return null;\r\n}\r\n\r\n/** Persist probe dimensions for fast subsequent starts. */\r\nasync function saveCachedDims(config: Pick<APIEmbeddingConfig, 'baseUrl' | 'model' | 'requestedDimensions'>, dimensions: number): Promise<void> {\r\n try {\r\n await mkdir(CACHE_DIR, { recursive: true });\r\n const key = dimsCacheKey(config);\r\n let entries: Array<{ key: string; baseUrl: string; model: string; requestedDimensions: number | null; dimensions: number; ts: number }> = [];\r\n\r\n try {\r\n const raw = await readFile(DIMS_CACHE_FILE, 'utf-8');\r\n const data = JSON.parse(raw);\r\n if (Array.isArray(data.entries)) {\r\n entries = data.entries.filter((entry: unknown) =>\r\n typeof entry === 'object' &&\r\n entry !== null &&\r\n 'key' in entry &&\r\n typeof (entry as { key?: unknown }).key === 'string',\r\n ) as typeof entries;\r\n } else if (\r\n data &&\r\n typeof data === 'object' &&\r\n typeof data.baseUrl === 'string' &&\r\n typeof data.model === 'string' &&\r\n typeof data.dimensions === 'number'\r\n ) {\r\n entries = [{\r\n key: dimsCacheKey({\r\n baseUrl: data.baseUrl,\r\n model: data.model,\r\n requestedDimensions: data.requestedDimensions ?? null,\r\n }),\r\n baseUrl: data.baseUrl,\r\n model: data.model,\r\n requestedDimensions: data.requestedDimensions ?? null,\r\n dimensions: data.dimensions,\r\n ts: typeof data.ts === 'number' ? data.ts : Date.now(),\r\n }];\r\n }\r\n } catch {\r\n // no existing cache\r\n }\r\n\r\n const nextEntry = {\r\n key,\r\n baseUrl: config.baseUrl,\r\n model: config.model,\r\n requestedDimensions: config.requestedDimensions ?? null,\r\n dimensions,\r\n ts: Date.now(),\r\n };\r\n\r\n entries = entries.filter((entry) => entry.key !== key);\r\n entries.push(nextEntry);\r\n\r\n await writeFile(DIMS_CACHE_FILE, JSON.stringify({ entries }));\r\n } catch { /* best-effort */ }\r\n}\r\n\r\nasync function saveDiskCacheNow(): Promise<void> {\r\n if (!diskCacheDirty) return;\r\n try {\r\n await mkdir(CACHE_DIR, { recursive: true });\r\n const entries = Array.from(cache.entries());\r\n await writeFile(CACHE_FILE, JSON.stringify(entries));\r\n diskCacheDirty = false;\r\n } catch {\r\n // Cache persistence is best-effort only.\r\n }\r\n}\r\n\r\nfunction scheduleDiskSave(): void {\r\n if (diskSaveTimer) clearTimeout(diskSaveTimer);\r\n diskSaveTimer = setTimeout(() => {\r\n saveDiskCacheNow().catch(() => {});\r\n diskSaveTimer = null;\r\n }, DISK_SAVE_DEBOUNCE_MS);\r\n}\r\n\r\nfunction cacheSet(hash: 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(hash, value);\r\n diskCacheDirty = true;\r\n}\r\n\r\ninterface EmbeddingAPIResponse {\r\n object: string;\r\n data: Array<{\r\n object: string;\r\n index: number;\r\n embedding: number[];\r\n }>;\r\n model: string;\r\n usage?: {\r\n prompt_tokens: number;\r\n total_tokens: number;\r\n };\r\n}\r\n\r\ninterface APIEmbeddingConfig {\r\n apiKey: string;\r\n baseUrl: string;\r\n model: string;\r\n requestedDimensions: number | null;\r\n}\r\n\r\nfunction getPreferredBatchSize(config: APIEmbeddingConfig): number {\r\n if (/dashscope\\.aliyuncs\\.com/i.test(config.baseUrl)) {\r\n return DASHSCOPE_MAX_BATCH_SIZE;\r\n }\r\n return DEFAULT_MAX_BATCH_SIZE;\r\n}\r\n\r\nfunction parseBatchLimit(error: unknown): number | null {\r\n if (!(error instanceof Error)) return null;\r\n\r\n const explicit = error.message.match(/should not be larger than\\s+(\\d+)/i);\r\n if (explicit) return parseInt(explicit[1], 10);\r\n\r\n if (/batch size/i.test(error.message)) {\r\n const fallback = error.message.match(/(\\d+)/);\r\n if (fallback) return parseInt(fallback[1], 10);\r\n }\r\n\r\n return null;\r\n}\r\n\r\nexport class APIEmbeddingProvider implements EmbeddingProvider {\r\n readonly name: string;\r\n readonly dimensions: number;\r\n\r\n private config: APIEmbeddingConfig;\r\n private readonly cacheKeyNamespace: string;\r\n private totalTokensUsed = 0;\r\n private totalApiCalls = 0;\r\n\r\n private constructor(config: APIEmbeddingConfig, detectedDimensions: number) {\r\n this.config = config;\r\n this.cacheKeyNamespace = cacheNamespace(config);\r\n this.dimensions = detectedDimensions;\r\n this.name = `api-${config.model.replace(/\\//g, '-')}`;\r\n }\r\n\r\n static async create(): Promise<APIEmbeddingProvider> {\r\n const config = APIEmbeddingProvider.resolveConfig();\r\n\r\n // Start loading the 45MB+ embedding cache in the background (non-blocking).\r\n // It will be awaited on first embed() call if not yet ready.\r\n startDiskCacheLoad();\r\n\r\n // Try cached dimensions first to avoid a network probe on cold start\r\n let probeDimensions = await loadCachedDims(config);\r\n if (probeDimensions !== null) {\r\n console.error(`[memorix] API embedding: ${config.model} @ ${config.baseUrl} (${probeDimensions}d) [cached dims]`);\r\n } else {\r\n probeDimensions = await APIEmbeddingProvider.probeAPI(config);\r\n console.error(`[memorix] API embedding: ${config.model} @ ${config.baseUrl} (${probeDimensions}d)`);\r\n // Persist for next cold start\r\n saveCachedDims(config, probeDimensions).catch(() => {});\r\n }\r\n if (config.requestedDimensions) {\r\n console.error(`[memorix] Dimension shortening: ${config.requestedDimensions}d requested`);\r\n }\r\n\r\n return new APIEmbeddingProvider(config, probeDimensions);\r\n }\r\n\r\n private static resolveConfig(): APIEmbeddingConfig {\r\n let apiKey: string | undefined;\r\n let baseUrl: string;\r\n let model: string;\r\n let requestedDimensions: number | null;\r\n\r\n try {\r\n const cfg = require('../config.js');\r\n apiKey = cfg.getEmbeddingApiKey();\r\n baseUrl = cfg.getEmbeddingBaseUrl();\r\n model = cfg.getEmbeddingModel();\r\n requestedDimensions = cfg.getEmbeddingDimensions();\r\n } catch {\r\n apiKey =\r\n process.env.MEMORIX_EMBEDDING_API_KEY ||\r\n process.env.MEMORIX_API_KEY ||\r\n process.env.MEMORIX_LLM_API_KEY ||\r\n process.env.OPENAI_API_KEY;\r\n baseUrl =\r\n process.env.MEMORIX_EMBEDDING_BASE_URL ||\r\n process.env.MEMORIX_LLM_BASE_URL ||\r\n 'https://api.openai.com/v1';\r\n model = process.env.MEMORIX_EMBEDDING_MODEL || 'text-embedding-3-small';\r\n const dimStr = process.env.MEMORIX_EMBEDDING_DIMENSIONS;\r\n requestedDimensions = dimStr ? parseInt(dimStr, 10) : null;\r\n }\r\n\r\n if (!apiKey) {\r\n throw new Error(\r\n 'No API key for embedding. Set MEMORIX_EMBEDDING_API_KEY, MEMORIX_LLM_API_KEY, or OPENAI_API_KEY, or run `memorix configure`.',\r\n );\r\n }\r\n\r\n baseUrl = baseUrl.replace(/\\/+$/, '');\r\n\r\n return { apiKey, baseUrl, model, requestedDimensions };\r\n }\r\n\r\n private static async probeAPI(config: APIEmbeddingConfig): Promise<number> {\r\n const body: Record<string, unknown> = {\r\n model: config.model,\r\n input: 'dimension probe',\r\n };\r\n if (config.requestedDimensions) {\r\n body.dimensions = config.requestedDimensions;\r\n }\r\n\r\n const response = await fetchWithRetry(\r\n `${config.baseUrl}/embeddings`,\r\n config.apiKey,\r\n body,\r\n );\r\n\r\n if (response.data.length === 0 || !response.data[0].embedding) {\r\n throw new Error('API probe returned no embeddings; check model name and API key');\r\n }\r\n\r\n return response.data[0].embedding.length;\r\n }\r\n\r\n async embed(text: string): Promise<number[]> {\r\n const normalized = normalizeText(text);\r\n const hash = textHash(normalized, this.cacheKeyNamespace);\r\n\r\n // Fast path: cache already loaded (warm process) — instant lookup\r\n if (diskCacheLoaded) {\r\n const cached = cache.get(hash);\r\n if (cached) return cached;\r\n }\r\n\r\n // Cold-start path: cache is still loading in background.\r\n // Race the cache completion (may have a hit) against the API call.\r\n // Whichever resolves first with a valid embedding wins.\r\n const apiCall = async (): Promise<number[]> => {\r\n const body: Record<string, unknown> = {\r\n model: this.config.model,\r\n input: normalized,\r\n };\r\n if (this.config.requestedDimensions) {\r\n body.dimensions = this.config.requestedDimensions;\r\n }\r\n const response = await fetchWithRetry(\r\n `${this.config.baseUrl}/embeddings`,\r\n this.config.apiKey,\r\n body,\r\n );\r\n const embedding = response.data[0].embedding;\r\n if (embedding.length !== this.dimensions) {\r\n throw new Error(`Expected ${this.dimensions}d, got ${embedding.length}d; dimension mismatch`);\r\n }\r\n this.trackUsage(response);\r\n return embedding;\r\n };\r\n\r\n let embedding: number[];\r\n\r\n if (!diskCacheLoaded && diskCacheLoadPromise) {\r\n // Race: cache load + lookup vs API call\r\n const cacheRace = diskCacheLoadPromise.then(() => {\r\n const cached = cache.get(hash);\r\n if (cached) return cached;\r\n return null; // miss — let API win\r\n });\r\n\r\n const result = await Promise.race([\r\n cacheRace,\r\n apiCall().then(v => ({ __api: true, v } as const)),\r\n ]);\r\n\r\n if (result && typeof result === 'object' && '__api' in result) {\r\n // API finished first\r\n embedding = result.v;\r\n } else if (result) {\r\n // Cache hit won the race\r\n return result as number[];\r\n } else {\r\n // Cache loaded but missed — await the API call\r\n embedding = await apiCall();\r\n }\r\n } else {\r\n // No cache loading — just call API\r\n embedding = await apiCall();\r\n }\r\n\r\n cacheSet(hash, embedding);\r\n scheduleDiskSave();\r\n return embedding;\r\n }\r\n\r\n async embedBatch(texts: string[]): Promise<number[][]> {\r\n await ensureDiskCacheLoaded();\r\n const normalizedTexts = texts.map(normalizeText);\r\n const results: number[][] = new Array(texts.length);\r\n const uncachedIndices: number[] = [];\r\n const uncachedTexts: string[] = [];\r\n\r\n for (let i = 0; i < normalizedTexts.length; i++) {\r\n const hash = textHash(normalizedTexts[i], this.cacheKeyNamespace);\r\n const cached = cache.get(hash);\r\n if (cached) {\r\n results[i] = cached;\r\n } else {\r\n uncachedIndices.push(i);\r\n uncachedTexts.push(normalizedTexts[i]);\r\n }\r\n }\r\n\r\n if (uncachedTexts.length === 0) return results;\r\n\r\n const cacheHitRate = ((texts.length - uncachedTexts.length) / texts.length * 100).toFixed(1);\r\n console.error(\r\n `[memorix] API embedding ${uncachedTexts.length}/${texts.length} texts (cache hit: ${cacheHitRate}%)`,\r\n );\r\n\r\n const processChunk = async (chunkTexts: string[], chunkIndices: number[]): Promise<void> => {\r\n if (chunkTexts.length === 0) return;\r\n\r\n const body: Record<string, unknown> = {\r\n model: this.config.model,\r\n input: chunkTexts,\r\n };\r\n if (this.config.requestedDimensions) {\r\n body.dimensions = this.config.requestedDimensions;\r\n }\r\n\r\n try {\r\n const response = await fetchWithRetry(\r\n `${this.config.baseUrl}/embeddings`,\r\n this.config.apiKey,\r\n body,\r\n );\r\n\r\n this.trackUsage(response);\r\n\r\n for (const item of response.data) {\r\n const originalIdx = chunkIndices[item.index];\r\n results[originalIdx] = item.embedding;\r\n cacheSet(textHash(normalizedTexts[originalIdx], this.cacheKeyNamespace), item.embedding);\r\n }\r\n } catch (error) {\r\n const providerLimit = parseBatchLimit(error);\r\n const fallbackSize = providerLimit ?? Math.ceil(chunkTexts.length / 2);\r\n\r\n if (chunkTexts.length > 1 && fallbackSize < chunkTexts.length) {\r\n console.error(\r\n `[memorix] Embedding batch too large for provider, retrying in chunks of ${fallbackSize}`,\r\n );\r\n for (let start = 0; start < chunkTexts.length; start += fallbackSize) {\r\n await processChunk(\r\n chunkTexts.slice(start, start + fallbackSize),\r\n chunkIndices.slice(start, start + fallbackSize),\r\n );\r\n }\r\n return;\r\n }\r\n\r\n throw error;\r\n }\r\n };\r\n\r\n const preferredBatchSize = getPreferredBatchSize(this.config);\r\n const chunks: { texts: string[]; indices: number[] }[] = [];\r\n for (let batchStart = 0; batchStart < uncachedTexts.length; batchStart += preferredBatchSize) {\r\n chunks.push({\r\n texts: uncachedTexts.slice(batchStart, batchStart + preferredBatchSize),\r\n indices: uncachedIndices.slice(batchStart, batchStart + preferredBatchSize),\r\n });\r\n }\r\n\r\n for (let ci = 0; ci < chunks.length; ci += MAX_CONCURRENCY) {\r\n const concurrentChunks = chunks.slice(ci, ci + MAX_CONCURRENCY);\r\n await Promise.all(concurrentChunks.map((chunk) => processChunk(chunk.texts, chunk.indices)));\r\n }\r\n\r\n scheduleDiskSave();\r\n return results;\r\n }\r\n\r\n getStats(): { totalTokens: number; totalApiCalls: number; cacheSize: number } {\r\n return {\r\n totalTokens: this.totalTokensUsed,\r\n totalApiCalls: this.totalApiCalls,\r\n cacheSize: cache.size,\r\n };\r\n }\r\n\r\n private trackUsage(response: EmbeddingAPIResponse): void {\r\n this.totalApiCalls++;\r\n if (response.usage) {\r\n this.totalTokensUsed += response.usage.total_tokens;\r\n }\r\n }\r\n}\r\n\r\nasync function fetchWithRetry(\r\n url: string,\r\n apiKey: string,\r\n body: Record<string, unknown>,\r\n attempt = 0,\r\n): Promise<EmbeddingAPIResponse> {\r\n const controller = new AbortController();\r\n const timeout = setTimeout(() => controller.abort(), 10_000);\r\n let response: Response;\r\n try {\r\n response = await fetch(url, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n 'Authorization': `Bearer ${apiKey}`,\r\n },\r\n body: JSON.stringify(body),\r\n signal: controller.signal,\r\n });\r\n } catch (err: unknown) {\r\n clearTimeout(timeout);\r\n if (err instanceof Error && err.name === 'AbortError') {\r\n throw new Error(`Embedding API timeout after 10s: ${url}`);\r\n }\r\n throw err;\r\n }\r\n clearTimeout(timeout);\r\n\r\n if (response.ok) {\r\n return response.json() as Promise<EmbeddingAPIResponse>;\r\n }\r\n\r\n if ((response.status === 429 || response.status >= 500) && attempt < MAX_RETRIES) {\r\n const delay = BASE_DELAY_MS * Math.pow(2, attempt);\r\n const retryAfter = response.headers.get('retry-after');\r\n const waitMs = retryAfter ? parseInt(retryAfter, 10) * 1000 : delay;\r\n console.error(`[memorix] Embedding API ${response.status}, retry ${attempt + 1}/${MAX_RETRIES} in ${waitMs}ms`);\r\n await new Promise(resolve => setTimeout(resolve, waitMs));\r\n return fetchWithRetry(url, apiKey, body, attempt + 1);\r\n }\r\n\r\n const errorText = await response.text().catch(() => 'unknown error');\r\n throw new Error(`Embedding API error (${response.status}): ${errorText}`);\r\n}\r\n","/**\r\n * Embedding Provider — Abstraction Layer\r\n *\r\n * Extensible embedding interface. **Disabled by default** to minimize resource usage.\r\n *\r\n * Environment variable MEMORIX_EMBEDDING controls which provider to use:\r\n * - MEMORIX_EMBEDDING=off (default) → no embedding, BM25 fulltext search only (~50MB RAM)\r\n * - MEMORIX_EMBEDDING=fastembed → local ONNX inference (384-dim bge-small, ~300MB RAM)\r\n * - MEMORIX_EMBEDDING=transformers → pure JS WASM inference (384-dim MiniLM, ~500MB RAM)\r\n * - MEMORIX_EMBEDDING=api → remote API via OpenAI-compatible /v1/embeddings (zero local RAM)\r\n * - MEMORIX_EMBEDDING=auto → try configured API → fastembed → transformers → off\r\n *\r\n * API mode env vars (MEMORIX_EMBEDDING=api):\r\n * - MEMORIX_EMBEDDING_API_KEY → API key (fallback: MEMORIX_LLM_API_KEY → OPENAI_API_KEY)\r\n * - MEMORIX_EMBEDDING_BASE_URL → base URL (fallback: MEMORIX_LLM_BASE_URL)\r\n * - MEMORIX_EMBEDDING_MODEL → model (default: text-embedding-3-small)\r\n * - MEMORIX_EMBEDDING_DIMENSIONS → optional dimension override\r\n *\r\n * Resource impact of local embedding:\r\n * - First load: 90%+ CPU for 5-30 seconds (model initialization)\r\n * - Steady state: 300-500MB RAM (model in memory)\r\n * - Per-query: 10-50ms CPU (embedding generation)\r\n *\r\n * Most users don't need vector search — BM25 fulltext is sufficient for keyword matching.\r\n * Vector search is useful for semantic similarity (e.g., \"auth\" matches \"authentication\").\r\n *\r\n * Architecture inspired by Mem0's multi-provider embedding design.\r\n */\r\n\r\nexport interface EmbeddingProvider {\r\n /** Provider name for logging/cache keys */\r\n readonly name: string;\r\n /** Vector dimensions (e.g., 384 for bge-small) */\r\n readonly dimensions: number;\r\n /** Generate embedding for a single text */\r\n embed(text: string): Promise<number[]>;\r\n /** Generate embeddings for multiple texts (batch) */\r\n embedBatch(texts: string[]): Promise<number[][]>;\r\n}\r\n\r\n/** Singleton provider instance (null = not available) */\r\nlet provider: EmbeddingProvider | null = null;\r\nlet initPromise: Promise<EmbeddingProvider | null> | null = null;\r\n\r\ntype EmbeddingMode = 'off' | 'fastembed' | 'transformers' | 'api' | 'auto';\r\ntype ProviderKind = 'api' | 'fastembed' | 'transformers' | 'unknown';\r\n\r\n/**\r\n * Tracks whether the last init attempt resulted in a temporary failure\r\n * (mode != 'off' but provider returned null). When true, the next\r\n * getEmbeddingProvider() call will retry instead of returning cached null.\r\n */\r\nlet lastInitWasTemporaryFailure = false;\r\n\r\n/**\r\n * Get configured embedding mode from environment.\r\n * Default is 'off' to minimize resource usage.\r\n */\r\nfunction getEmbeddingMode(): EmbeddingMode {\r\n // Unified: env vars > config.json > 'off'\r\n try {\r\n const { getEmbeddingMode: cfgMode } = require('../config.js');\r\n return cfgMode();\r\n } catch {\r\n // Fallback if config module not available\r\n const env = process.env.MEMORIX_EMBEDDING?.toLowerCase()?.trim();\r\n if (env === 'fastembed' || env === 'transformers' || env === 'api' || env === 'auto') return env;\r\n return 'off';\r\n }\r\n}\r\n\r\nfunction hasAPIEmbeddingConfig(): boolean {\r\n try {\r\n const {\r\n getEmbeddingApiKey,\r\n getEmbeddingBaseUrl,\r\n getEmbeddingModel,\r\n } = require('../config.js');\r\n\r\n return Boolean(\r\n getEmbeddingApiKey?.() &&\r\n getEmbeddingBaseUrl?.() &&\r\n getEmbeddingModel?.(),\r\n );\r\n } catch {\r\n return Boolean(\r\n process.env.MEMORIX_EMBEDDING_API_KEY ||\r\n process.env.MEMORIX_API_KEY ||\r\n process.env.MEMORIX_LLM_API_KEY ||\r\n process.env.OPENAI_API_KEY,\r\n );\r\n }\r\n}\r\n\r\nfunction getProviderKind(candidate: EmbeddingProvider): ProviderKind {\r\n if (candidate.name.startsWith('api-')) return 'api';\r\n if (candidate.name.startsWith('fastembed-')) return 'fastembed';\r\n if (candidate.name.startsWith('transformers-')) return 'transformers';\r\n return 'unknown';\r\n}\r\n\r\nfunction isTemporaryEmbeddingFailure(error: unknown): boolean {\r\n if (!(error instanceof Error)) return false;\r\n return (\r\n /embedding api timeout/i.test(error.message) ||\r\n /embedding api error \\((402|429|5\\d\\d)\\)/i.test(error.message) ||\r\n /quota exceeded/i.test(error.message) ||\r\n /account balance/i.test(error.message) ||\r\n /fetch failed/i.test(error.message) ||\r\n /econnreset/i.test(error.message) ||\r\n /econnrefused/i.test(error.message) ||\r\n /temporarily unavailable/i.test(error.message)\r\n );\r\n}\r\n\r\nfunction markTemporaryFailure(reason: unknown): void {\r\n provider = null;\r\n initPromise = null;\r\n lastInitWasTemporaryFailure = true;\r\n lastFailureTimestamp = Date.now();\r\n const message = reason instanceof Error ? reason.message : String(reason);\r\n console.error(`[memorix] Embedding provider temporarily unavailable at runtime: ${message}`);\r\n}\r\n\r\nasync function createFastEmbedProvider(): Promise<EmbeddingProvider | null> {\r\n try {\r\n const { FastEmbedProvider } = await import('./fastembed-provider.js');\r\n return await FastEmbedProvider.create();\r\n } catch (e) {\r\n console.error(`[memorix] Failed to load fastembed: ${e instanceof Error ? e.message : e}`);\r\n console.error('[memorix] Install with: npm install fastembed');\r\n return null;\r\n }\r\n}\r\n\r\nasync function createTransformersProvider(): Promise<EmbeddingProvider | null> {\r\n try {\r\n const { TransformersProvider } = await import('./transformers-provider.js');\r\n return await TransformersProvider.create();\r\n } catch (e) {\r\n console.error(`[memorix] Failed to load transformers: ${e instanceof Error ? e.message : e}`);\r\n console.error('[memorix] Install with: npm install @huggingface/transformers');\r\n return null;\r\n }\r\n}\r\n\r\nasync function createAPIProvider(): Promise<EmbeddingProvider | null> {\r\n try {\r\n const { APIEmbeddingProvider } = await import('./api-provider.js');\r\n return await APIEmbeddingProvider.create();\r\n } catch (e) {\r\n console.error(`[memorix] Failed to init API embedding: ${e instanceof Error ? e.message : e}`);\r\n return null;\r\n }\r\n}\r\n\r\nasync function createLocalFallbackProvider(): Promise<EmbeddingProvider | null> {\r\n const fastembed = await createFastEmbedProvider();\r\n if (fastembed) return fastembed;\r\n\r\n const transformers = await createTransformersProvider();\r\n if (transformers) return transformers;\r\n\r\n return null;\r\n}\r\n\r\nfunction wrapProvider(candidate: EmbeddingProvider): EmbeddingProvider {\r\n const kind = getProviderKind(candidate);\r\n\r\n return {\r\n name: candidate.name,\r\n dimensions: candidate.dimensions,\r\n async embed(text: string): Promise<number[]> {\r\n try {\r\n return await candidate.embed(text);\r\n } catch (error) {\r\n if (kind === 'api' && getEmbeddingMode() === 'auto' && isTemporaryEmbeddingFailure(error)) {\r\n console.error('[memorix] API embedding temporarily unavailable — switching to local fallback provider');\r\n const fallback = await createLocalFallbackProvider();\r\n if (fallback) {\r\n provider = wrapProvider(fallback);\r\n console.error(`[memorix] Embedding fallback activated: ${provider.name} (${provider.dimensions}d)`);\r\n return provider.embed(text);\r\n }\r\n }\r\n\r\n if (isTemporaryEmbeddingFailure(error)) {\r\n markTemporaryFailure(error);\r\n }\r\n throw error;\r\n }\r\n },\r\n async embedBatch(texts: string[]): Promise<number[][]> {\r\n try {\r\n return await candidate.embedBatch(texts);\r\n } catch (error) {\r\n if (kind === 'api' && getEmbeddingMode() === 'auto' && isTemporaryEmbeddingFailure(error)) {\r\n console.error('[memorix] API embedding temporarily unavailable — switching to local fallback provider');\r\n const fallback = await createLocalFallbackProvider();\r\n if (fallback) {\r\n provider = wrapProvider(fallback);\r\n console.error(`[memorix] Embedding fallback activated: ${provider.name} (${provider.dimensions}d)`);\r\n return provider.embedBatch(texts);\r\n }\r\n }\r\n\r\n if (isTemporaryEmbeddingFailure(error)) {\r\n markTemporaryFailure(error);\r\n }\r\n throw error;\r\n }\r\n },\r\n };\r\n}\r\n\r\n/** Minimum interval between retry attempts after a temporary failure (ms). */\r\nconst RETRY_COOLDOWN_MS = 30_000;\r\nlet lastFailureTimestamp = 0;\r\n\r\n/**\r\n * Get the embedding provider. Returns null if disabled or unavailable.\r\n * Lazy-initialized on first call. Concurrent callers share the same Promise.\r\n *\r\n * Recovery semantics:\r\n * - mode === 'off' → permanently null (no retry)\r\n * - mode === 'auto' and NO local provider installed → permanently null (no retry)\r\n * - provider init failed due to network/API/temp error → retry after cooldown\r\n *\r\n * Controlled by MEMORIX_EMBEDDING environment variable (default: off).\r\n */\r\nexport async function getEmbeddingProvider(): Promise<EmbeddingProvider | null> {\r\n // If we already have a successfully initialized provider, return it immediately\r\n if (provider) return provider;\r\n\r\n // If a previous attempt failed temporarily, allow retry after cooldown\r\n if (lastInitWasTemporaryFailure) {\r\n const elapsed = Date.now() - lastFailureTimestamp;\r\n if (elapsed < RETRY_COOLDOWN_MS) {\r\n // Still within cooldown — return cached null without retrying\r\n return null;\r\n }\r\n // Cooldown expired — clear cached promise to allow retry\r\n initPromise = null;\r\n lastInitWasTemporaryFailure = false;\r\n }\r\n\r\n if (initPromise) return initPromise;\r\n\r\n initPromise = (async () => {\r\n const mode = getEmbeddingMode();\r\n\r\n // Explicit OFF — skip all embedding initialization (permanent, no retry)\r\n if (mode === 'off') {\r\n console.error('[memorix] Embedding disabled (MEMORIX_EMBEDDING=off) — using BM25 fulltext search');\r\n return null;\r\n }\r\n\r\n // Explicit fastembed\r\n if (mode === 'fastembed') {\r\n const initialized = await createFastEmbedProvider();\r\n if (!initialized) return null;\r\n provider = wrapProvider(initialized);\r\n console.error(`[memorix] Embedding provider: ${provider.name} (${provider.dimensions}d)`);\r\n return provider;\r\n }\r\n\r\n // Explicit transformers\r\n if (mode === 'transformers') {\r\n const initialized = await createTransformersProvider();\r\n if (!initialized) return null;\r\n provider = wrapProvider(initialized);\r\n console.error(`[memorix] Embedding provider: ${provider.name} (${provider.dimensions}d)`);\r\n return provider;\r\n }\r\n\r\n // API mode: remote embedding via OpenAI-compatible endpoint\r\n if (mode === 'api') {\r\n const initialized = await createAPIProvider();\r\n if (!initialized) return null;\r\n provider = wrapProvider(initialized);\r\n console.error(`[memorix] Embedding provider: ${provider.name} (${provider.dimensions}d)`);\r\n return provider;\r\n }\r\n\r\n // Auto mode: try configured API first, then local fallbacks\r\n if (hasAPIEmbeddingConfig()) {\r\n const initialized = await createAPIProvider();\r\n if (initialized) {\r\n provider = wrapProvider(initialized);\r\n console.error(`[memorix] Embedding provider: ${provider.name} (${provider.dimensions}d)`);\r\n return provider;\r\n }\r\n }\r\n\r\n const localFallback = await createLocalFallbackProvider();\r\n if (localFallback) {\r\n provider = wrapProvider(localFallback);\r\n console.error(`[memorix] Embedding provider: ${provider.name} (${provider.dimensions}d)`);\r\n return provider;\r\n }\r\n\r\n console.error('[memorix] No embedding provider available — using BM25 fulltext search');\r\n return null;\r\n })();\r\n\r\n // After the init promise resolves, decide whether to cache or allow retry\r\n const result = await initPromise;\r\n if (result === null && !isEmbeddingExplicitlyDisabled()) {\r\n // Temporary failure — mark for retry and record timestamp\r\n const mode = getEmbeddingMode();\r\n // 'auto' mode with no local providers installed is permanent (not retryable)\r\n if (mode === 'api' || mode === 'fastembed' || mode === 'transformers') {\r\n lastInitWasTemporaryFailure = true;\r\n lastFailureTimestamp = Date.now();\r\n console.error(`[memorix] Embedding provider temporarily unavailable — will retry after ${RETRY_COOLDOWN_MS / 1000}s`);\r\n }\r\n // 'auto' with no providers → permanent null, no retry needed\r\n }\r\n\r\n return result;\r\n}\r\n\r\n/**\r\n * Check if vector search is available.\r\n */\r\nexport async function isVectorSearchAvailable(): Promise<boolean> {\r\n const p = await getEmbeddingProvider();\r\n return p !== null;\r\n}\r\n\r\n/**\r\n * Check if embedding is explicitly disabled by configuration (mode === 'off').\r\n *\r\n * When true, there is no provider to backfill from and observations can be\r\n * safely removed from the vector-missing queue.\r\n *\r\n * When false, the provider MAY still be null due to initialization failure,\r\n * API error, or missing dependencies — in those cases the observation should\r\n * stay in the backfill queue for later retry.\r\n */\r\nexport function isEmbeddingExplicitlyDisabled(): boolean {\r\n return getEmbeddingMode() === 'off';\r\n}\r\n\r\n/**\r\n * Reset provider (for testing).\r\n */\r\nexport function resetProvider(): void {\r\n provider = null;\r\n initPromise = null;\r\n lastInitWasTemporaryFailure = false;\r\n lastFailureTimestamp = 0;\r\n}\r\n","/**\r\n * Project Affinity Scoring\r\n *\r\n * Prevents cross-project memory pollution by scoring search results\r\n * based on how well they match the current project context.\r\n *\r\n * Inspired by mcp-memory-service's memory-scorer.js:\r\n * - High affinity: content mentions project name → full score\r\n * - Medium affinity: related concepts but no direct mention → 0.7x\r\n * - Low affinity: no project reference → 0.3x (heavily penalized)\r\n *\r\n * This runs AFTER projectId filtering, as a second layer of defense\r\n * against memories that were stored under the correct projectId but\r\n * contain content about a different project (e.g., discussing Memorix\r\n * development while in a test project workspace).\r\n */\r\n\r\nexport interface AffinityContext {\r\n /** Current project name (e.g., \"for_memmcp_test\", \"memorix\") */\r\n projectName: string;\r\n /** Current project ID (e.g., \"local/for_memmcp_test\", \"AVIDS2/memorix\") */\r\n projectId: string;\r\n /** Optional: keywords that indicate project relevance */\r\n projectKeywords?: string[];\r\n}\r\n\r\nexport interface MemoryContent {\r\n title: string;\r\n narrative?: string;\r\n facts?: string[];\r\n concepts?: string[];\r\n entityName?: string;\r\n filesModified?: string[];\r\n}\r\n\r\nexport interface AffinityResult {\r\n /** Affinity score 0-1 (1 = high affinity, 0 = no affinity) */\r\n score: number;\r\n /** Affinity level for debugging */\r\n level: 'high' | 'medium' | 'low' | 'none';\r\n /** Reason for the score */\r\n reason: string;\r\n}\r\n\r\n/**\r\n * Calculate project affinity score for a memory.\r\n *\r\n * @param memory - The memory content to evaluate\r\n * @param context - Current project context\r\n * @returns AffinityResult with score, level, and reason\r\n */\r\nexport function calculateProjectAffinity(\r\n memory: MemoryContent,\r\n context: AffinityContext,\r\n): AffinityResult {\r\n const projectName = context.projectName.toLowerCase();\r\n const projectId = context.projectId.toLowerCase();\r\n \r\n // Extract base name from projectId (e.g., \"memorix\" from \"AVIDS2/memorix\")\r\n const projectBaseName = projectId.split('/').pop() ?? projectName;\r\n \r\n // Build searchable content string\r\n const contentParts = [\r\n memory.title,\r\n memory.narrative ?? '',\r\n memory.entityName ?? '',\r\n ...(memory.facts ?? []),\r\n ...(memory.concepts ?? []),\r\n ...(memory.filesModified ?? []),\r\n ];\r\n const content = contentParts.join(' ').toLowerCase();\r\n \r\n // Check for direct project name mention\r\n if (content.includes(projectName) || content.includes(projectBaseName)) {\r\n return { score: 1.0, level: 'high', reason: 'project_name_in_content' };\r\n }\r\n \r\n // Check for project keywords (if provided)\r\n if (context.projectKeywords && context.projectKeywords.length > 0) {\r\n const keywordsLower = context.projectKeywords.map(k => k.toLowerCase());\r\n const matchedKeywords = keywordsLower.filter(k => content.includes(k));\r\n if (matchedKeywords.length >= 2) {\r\n return { score: 0.9, level: 'high', reason: `keywords_matched: ${matchedKeywords.join(', ')}` };\r\n }\r\n if (matchedKeywords.length === 1) {\r\n return { score: 0.7, level: 'medium', reason: `keyword_matched: ${matchedKeywords[0]}` };\r\n }\r\n }\r\n \r\n // Check for file paths that suggest project relevance\r\n const files = memory.filesModified ?? [];\r\n if (files.some(f => f.toLowerCase().includes(projectName) || f.toLowerCase().includes(projectBaseName))) {\r\n return { score: 0.85, level: 'high', reason: 'project_in_file_path' };\r\n }\r\n \r\n // Check entity name\r\n if (memory.entityName) {\r\n const entityLower = memory.entityName.toLowerCase();\r\n if (entityLower.includes(projectName) || entityLower.includes(projectBaseName)) {\r\n return { score: 0.8, level: 'high', reason: 'project_in_entity' };\r\n }\r\n }\r\n \r\n // Check concepts for project-related terms\r\n const concepts = memory.concepts ?? [];\r\n if (concepts.some(c => c.toLowerCase().includes(projectName) || c.toLowerCase().includes(projectBaseName))) {\r\n return { score: 0.75, level: 'medium', reason: 'project_in_concepts' };\r\n }\r\n \r\n // No project reference found — this memory might be about a different project\r\n // Apply penalty but don't completely filter (might still be relevant)\r\n return { score: 0.65, level: 'low', reason: 'no_project_reference' };\r\n}\r\n\r\n/**\r\n * Apply project affinity scoring to search results.\r\n *\r\n * @param results - Search results with scores\r\n * @param memories - Full memory content for each result (keyed by ID)\r\n * @param context - Current project context\r\n * @param options - Scoring options\r\n * @returns Results with adjusted scores, sorted by affinity-weighted score\r\n */\r\nexport function applyProjectAffinity<T extends { id: number; score: number }>(\r\n results: T[],\r\n memories: Map<number, MemoryContent>,\r\n context: AffinityContext,\r\n options: {\r\n /** Minimum affinity score to include (default: 0, include all) */\r\n minAffinity?: number;\r\n /** Whether to filter out low-affinity results entirely (default: false) */\r\n filterLowAffinity?: boolean;\r\n } = {},\r\n): T[] {\r\n const { minAffinity = 0, filterLowAffinity = false } = options;\r\n \r\n // Calculate affinity for each result\r\n const withAffinity = results.map(result => {\r\n const memory = memories.get(result.id);\r\n if (!memory) {\r\n // No memory content available — assume medium affinity\r\n return { ...result, affinity: 0.5, affinityLevel: 'medium' as const };\r\n }\r\n \r\n const { score: affinityScore, level } = calculateProjectAffinity(memory, context);\r\n return {\r\n ...result,\r\n score: result.score * affinityScore, // Apply affinity as multiplier\r\n affinity: affinityScore,\r\n affinityLevel: level,\r\n };\r\n });\r\n \r\n // Filter by minimum affinity if requested\r\n let filtered = withAffinity;\r\n if (filterLowAffinity) {\r\n filtered = withAffinity.filter(r => r.affinity >= 0.5);\r\n } else if (minAffinity > 0) {\r\n filtered = withAffinity.filter(r => r.affinity >= minAffinity);\r\n }\r\n \r\n // Re-sort by affinity-weighted score\r\n filtered.sort((a, b) => b.score - a.score);\r\n \r\n // Return without the extra affinity fields (keep original shape)\r\n return filtered.map(({ affinity: _, affinityLevel: __, ...rest }) => rest as T);\r\n}\r\n\r\n/**\r\n * Extract project keywords from project name and common patterns.\r\n * Used to improve affinity detection for projects with distinctive names.\r\n */\r\nexport function extractProjectKeywords(projectName: string, projectId: string): string[] {\r\n const keywords: string[] = [projectName];\r\n \r\n // Add base name from projectId\r\n const baseName = projectId.split('/').pop();\r\n if (baseName && baseName !== projectName) {\r\n keywords.push(baseName);\r\n }\r\n \r\n // Add common variations\r\n const variations = [\r\n projectName.replace(/-/g, '_'),\r\n projectName.replace(/_/g, '-'),\r\n projectName.replace(/[_-]/g, ''),\r\n ];\r\n for (const v of variations) {\r\n if (v !== projectName && !keywords.includes(v)) {\r\n keywords.push(v);\r\n }\r\n }\r\n \r\n return keywords.filter(k => k.length > 2);\r\n}\r\n","/**\r\n * Intent-Aware Recall — Query Intent Detection\r\n *\r\n * Detects the underlying intent of a search query (why/when/how/what)\r\n * and returns type-specific boosting factors to improve recall precision.\r\n *\r\n * Inspired by MemCP's intent routing architecture.\r\n * Uses fast keyword/pattern matching (no LLM needed).\r\n */\r\n\r\nimport type { ObservationType } from '../types.js';\r\n\r\n// ─── Types ───\r\n\r\nexport type QueryIntent = 'why' | 'when' | 'how' | 'what_changed' | 'problem' | 'general';\r\n\r\nexport interface IntentResult {\r\n /** Detected intent category */\r\n intent: QueryIntent;\r\n /** Confidence score 0-1 */\r\n confidence: number;\r\n /** Observation type → boost multiplier (applied to search scores) */\r\n typeBoosts: Partial<Record<ObservationType, number>>;\r\n /** Field weight overrides for Orama search (optional) */\r\n fieldBoosts?: Record<string, number>;\r\n /** Whether to prefer chronological ordering over relevance */\r\n preferChronological: boolean;\r\n /** Source → boost multiplier for source-aware retrieval */\r\n sourceBoosts?: Partial<Record<'agent' | 'git' | 'manual', number>>;\r\n}\r\n\r\n// ─── Intent Patterns ───\r\n\r\ninterface IntentPattern {\r\n intent: QueryIntent;\r\n patterns: RegExp[];\r\n /** Higher weight = stronger match when multiple intents match */\r\n weight: number;\r\n}\r\n\r\nconst INTENT_PATTERNS: IntentPattern[] = [\r\n {\r\n intent: 'why',\r\n patterns: [\r\n /\\bwhy\\b/i,\r\n /\\breason(?:s|ing)?\\b/i,\r\n /\\brationale\\b/i,\r\n /\\bmotivat(?:ion|ed)\\b/i,\r\n /\\bjustif(?:y|ication)\\b/i,\r\n /\\bchose|chosen|picked\\b/i,\r\n /\\bdecid(?:e[ds]?|ing)\\b/i,\r\n /\\btrade-?off\\b/i,\r\n /为什么/,\r\n /原因/,\r\n /理由/,\r\n /为何/,\r\n ],\r\n weight: 1.0,\r\n },\r\n {\r\n intent: 'when',\r\n patterns: [\r\n /\\bwhen\\b/i,\r\n /\\btimeline\\b/i,\r\n /\\bhistory\\b/i,\r\n /\\blast\\s+(week|month|time|session)\\b/i,\r\n /\\brecent(?:ly)?\\b/i,\r\n /\\byesterday\\b/i,\r\n /\\btoday\\b/i,\r\n /\\bchronolog/i,\r\n /什么时候/,\r\n /何时/,\r\n /最近/,\r\n /上次/,\r\n ],\r\n weight: 0.9,\r\n },\r\n {\r\n intent: 'how',\r\n patterns: [\r\n /\\bhow\\s+(does|do|to|is|can|did|should|would)\\b/i,\r\n /\\barchitecture\\b/i,\r\n /\\bmechanism\\b/i,\r\n /\\bimplement(?:ation|ed|ing)?\\b/i,\r\n /\\bwork(?:s|ing|ed)?\\b/i,\r\n /\\bexplain\\b/i,\r\n /\\bunderstand\\b/i,\r\n /怎么/,\r\n /如何/,\r\n /机制/,\r\n /原理/,\r\n /架构/,\r\n ],\r\n weight: 0.85,\r\n },\r\n {\r\n intent: 'what_changed',\r\n patterns: [\r\n /\\bwhat\\s+changed\\b/i,\r\n /\\bwhat\\s+was\\s+(modified|updated|changed)\\b/i,\r\n /\\bdiff(?:erence)?\\b/i,\r\n /\\bchangelog\\b/i,\r\n /\\bmodifi(?:ed|cation)\\b/i,\r\n /\\bupdat(?:e[ds]?|ing)\\b/i,\r\n /\\brefactor(?:ed|ing)?\\b/i,\r\n /改了/,\r\n /修改/,\r\n /变更/,\r\n /变化/,\r\n ],\r\n weight: 0.8,\r\n },\r\n {\r\n intent: 'problem',\r\n patterns: [\r\n /\\bbug(?:s|gy)?\\b/i,\r\n /\\berror(?:s)?\\b/i,\r\n /\\bfix(?:e[ds]|ing)?\\b/i,\r\n /\\bissue(?:s)?\\b/i,\r\n /\\bproblem(?:s)?\\b/i,\r\n /\\bcrash(?:e[ds]|ing)?\\b/i,\r\n /\\bfail(?:e[ds]|ure|ing)?\\b/i,\r\n /\\bbroken\\b/i,\r\n /\\bgotcha\\b/i,\r\n /\\bpitfall\\b/i,\r\n /\\bworkaround\\b/i,\r\n /\\btroubleshoot/i,\r\n /\\bdebug(?:ging)?\\b/i,\r\n /报错/,\r\n /问题/,\r\n /修复/,\r\n /故障/,\r\n /异常/,\r\n ],\r\n weight: 0.9,\r\n },\r\n];\r\n\r\n// ─── Type Boost Maps ───\r\n\r\nconst INTENT_TYPE_BOOSTS: Record<QueryIntent, Partial<Record<ObservationType, number>>> = {\r\n why: {\r\n 'decision': 3.0,\r\n 'why-it-exists': 3.0,\r\n 'trade-off': 2.5,\r\n 'how-it-works': 1.2,\r\n },\r\n when: {\r\n // Temporal queries don't strongly prefer any type — they prefer recency\r\n 'what-changed': 1.5,\r\n 'session-request': 1.3,\r\n },\r\n how: {\r\n 'how-it-works': 3.0,\r\n 'discovery': 2.0,\r\n 'decision': 1.3,\r\n },\r\n what_changed: {\r\n 'what-changed': 3.0,\r\n 'discovery': 1.5,\r\n 'session-request': 1.2,\r\n },\r\n problem: {\r\n 'problem-solution': 3.0,\r\n 'gotcha': 2.5,\r\n 'discovery': 1.3,\r\n },\r\n general: {\r\n // No special boosting\r\n },\r\n};\r\n\r\n// ─── Source Boost Maps ───\r\n// Maps intent to preferred memory sources for source-aware retrieval.\r\n// git source = ground truth (commits), agent source = reasoning/decisions.\r\n\r\nconst INTENT_SOURCE_BOOSTS: Partial<Record<QueryIntent, Partial<Record<'agent' | 'git' | 'manual', number>>>> = {\r\n what_changed: {\r\n git: 2.0, // \"what changed\" → prefer commit-derived ground truth\r\n agent: 0.8,\r\n },\r\n when: {\r\n git: 1.8, // Temporal queries → git has precise timestamps\r\n agent: 1.0,\r\n },\r\n why: {\r\n agent: 2.0, // \"why\" → prefer reasoning/decision memories\r\n git: 0.7, // commits rarely explain WHY\r\n },\r\n how: {\r\n agent: 1.5, // \"how\" → prefer explanations\r\n git: 1.0,\r\n },\r\n problem: {\r\n git: 1.5, // Bug fixes often in commit history\r\n agent: 1.5, // But also in problem-solution memories\r\n },\r\n};\r\n\r\nconst INTENT_FIELD_BOOSTS: Partial<Record<QueryIntent, Record<string, number>>> = {\r\n why: {\r\n title: 2,\r\n entityName: 1.5,\r\n narrative: 2.5, // WHY queries need narrative context\r\n facts: 1.5,\r\n concepts: 1,\r\n filesModified: 0.3,\r\n },\r\n problem: {\r\n title: 3,\r\n entityName: 2,\r\n narrative: 2,\r\n facts: 2, // Bug details often in facts\r\n concepts: 1,\r\n filesModified: 1.5, // File paths help find the right bug fix\r\n },\r\n};\r\n\r\n// ─── Detection ───\r\n\r\n/**\r\n * Detect the intent of a search query.\r\n *\r\n * Returns the best matching intent with confidence score and\r\n * type-specific boosting factors to apply during search.\r\n */\r\nexport function detectQueryIntent(query: string): IntentResult {\r\n if (!query || query.length < 2) {\r\n return {\r\n intent: 'general',\r\n confidence: 0,\r\n typeBoosts: {},\r\n preferChronological: false,\r\n };\r\n }\r\n\r\n let bestIntent: QueryIntent = 'general';\r\n let bestScore = 0;\r\n let totalMatches = 0;\r\n\r\n for (const { intent, patterns, weight } of INTENT_PATTERNS) {\r\n let matchCount = 0;\r\n for (const pattern of patterns) {\r\n if (pattern.test(query)) matchCount++;\r\n }\r\n if (matchCount > 0) {\r\n const score = matchCount * weight;\r\n totalMatches += matchCount;\r\n if (score > bestScore) {\r\n bestScore = score;\r\n bestIntent = intent;\r\n }\r\n }\r\n }\r\n\r\n // Confidence: how strongly did we match vs. random noise\r\n const confidence = totalMatches === 0\r\n ? 0\r\n : Math.min(1, bestScore / 2); // 2+ pattern matches → high confidence\r\n\r\n return {\r\n intent: bestIntent,\r\n confidence,\r\n typeBoosts: INTENT_TYPE_BOOSTS[bestIntent],\r\n fieldBoosts: INTENT_FIELD_BOOSTS[bestIntent],\r\n sourceBoosts: INTENT_SOURCE_BOOSTS[bestIntent],\r\n preferChronological: bestIntent === 'when',\r\n };\r\n}\r\n\r\n/**\r\n * Apply intent-based type boosting to a search result's score.\r\n *\r\n * @param score Original search score\r\n * @param type Observation type of the result\r\n * @param intentResult Detected intent from detectQueryIntent()\r\n * @returns Boosted score\r\n */\r\nexport function applyIntentBoost(\r\n score: number,\r\n type: string,\r\n intentResult: IntentResult,\r\n): number {\r\n if (intentResult.confidence < 0.3) return score; // Low confidence → no boost\r\n const boost = intentResult.typeBoosts[type as ObservationType] ?? 1.0;\r\n // Scale boost by confidence: full boost at confidence=1, partial at lower\r\n const effectiveBoost = 1 + (boost - 1) * intentResult.confidence;\r\n return score * effectiveBoost;\r\n}\r\n","/**\r\n * LLM Provider\r\n *\r\n * Abstraction layer for LLM-enhanced memory management.\r\n * Supports OpenAI-compatible APIs (OpenAI, Anthropic via proxy, local models).\r\n *\r\n * This is the optional \"premium\" path — Memorix works without it,\r\n * but with an LLM configured, memory quality approaches Mem0/Cipher level.\r\n */\r\n\r\nexport interface LLMConfig {\r\n provider: 'openai' | 'anthropic' | 'openrouter' | 'custom';\r\n apiKey: string;\r\n model?: string;\r\n baseUrl?: string;\r\n}\r\n\r\nconst LLM_TIMEOUT_DEFAULT_MS = 30_000;\r\nconst LLM_TIMEOUT_MIN_MS = 1_000;\r\nconst LLM_TIMEOUT_MAX_MS = 300_000;\r\nconst MAX_LLM_RESPONSE_BYTES = 2 * 1024 * 1024;\r\n\r\n/**\r\n * Parse and validate MEMORIX_LLM_TIMEOUT_MS environment variable.\r\n * - Must be a valid integer in the range 1000–300000ms.\r\n * - Non-integer or out-of-range values log a warning and fall back to the default.\r\n * Default: 30000ms (30s) — allows for proxy routing and cold starts.\r\n */\r\nexport function parseLLMTimeoutMs(raw: string | undefined): number {\r\n if (raw === undefined || raw.trim() === '') return LLM_TIMEOUT_DEFAULT_MS;\r\n const parsed = Number(raw);\r\n if (!Number.isInteger(parsed) || Number.isNaN(parsed)) {\r\n console.warn(\r\n `[memorix] MEMORIX_LLM_TIMEOUT_MS=\"${raw}\" is invalid (must be a positive integer between ${LLM_TIMEOUT_MIN_MS}–${LLM_TIMEOUT_MAX_MS}ms). Using default ${LLM_TIMEOUT_DEFAULT_MS}ms.`,\r\n );\r\n return LLM_TIMEOUT_DEFAULT_MS;\r\n }\r\n if (parsed < LLM_TIMEOUT_MIN_MS) return LLM_TIMEOUT_MIN_MS;\r\n if (parsed > LLM_TIMEOUT_MAX_MS) return LLM_TIMEOUT_MAX_MS;\r\n return parsed;\r\n}\r\n\r\nconst LLM_CALL_TIMEOUT_MS = parseLLMTimeoutMs(process.env.MEMORIX_LLM_TIMEOUT_MS);\r\n\r\nexport interface LLMResponse {\r\n content: string;\r\n usage?: { promptTokens: number; completionTokens: number };\r\n}\r\n\r\n/** A single tool call requested by the LLM */\r\nexport interface ToolCall {\r\n id: string;\r\n name: string;\r\n arguments: string; // JSON string\r\n}\r\n\r\n/** Response from callLLMWithTools — may contain text, tool calls, or both */\r\nexport interface LLMToolResponse {\r\n content: string;\r\n toolCalls: ToolCall[];\r\n stopReason: 'end_turn' | 'tool_use' | 'stop' | 'unknown';\r\n usage?: { promptTokens: number; completionTokens: number };\r\n}\r\n\r\n/** Streaming event from callLLMWithToolsStream */\r\nexport type LLMStreamEvent =\r\n | { type: 'text'; content: string }\r\n | { type: 'tool_call'; toolCall: ToolCall }\r\n | { type: 'done'; response: LLMToolResponse };\r\n\r\nasync function readResponseText(response: Response, signal?: AbortSignal, maxBytes = MAX_LLM_RESPONSE_BYTES): Promise<string> {\r\n const contentLength = response.headers.get('content-length');\r\n if (contentLength && Number(contentLength) > maxBytes) {\r\n throw new Error(`LLM response too large (${contentLength} bytes)`);\r\n }\r\n\r\n const reader = response.body?.getReader();\r\n if (!reader) {\r\n signal?.throwIfAborted();\r\n return response.text();\r\n }\r\n\r\n const decoder = new TextDecoder();\r\n const chunks: string[] = [];\r\n let bytesRead = 0;\r\n const abortReader = () => {\r\n void reader.cancel(signal?.reason).catch(() => undefined);\r\n };\r\n\r\n signal?.addEventListener('abort', abortReader, { once: true });\r\n\r\n try {\r\n while (true) {\r\n signal?.throwIfAborted();\r\n const { value, done } = await reader.read();\r\n if (done) break;\r\n signal?.throwIfAborted();\r\n if (!value) continue;\r\n bytesRead += value.byteLength;\r\n if (bytesRead > maxBytes) {\r\n await reader.cancel('response too large').catch(() => undefined);\r\n throw new Error(`LLM response exceeded ${maxBytes} bytes`);\r\n }\r\n chunks.push(decoder.decode(value, { stream: true }));\r\n }\r\n\r\n chunks.push(decoder.decode());\r\n signal?.throwIfAborted();\r\n return chunks.join('');\r\n } finally {\r\n signal?.removeEventListener('abort', abortReader);\r\n reader.releaseLock();\r\n }\r\n}\r\n\r\nasync function readResponseJson<T>(response: Response, signal?: AbortSignal, maxBytes = MAX_LLM_RESPONSE_BYTES): Promise<T> {\r\n const text = await readResponseText(response, signal, maxBytes);\r\n return JSON.parse(text) as T;\r\n}\r\n\r\n/**\r\n * Call the LLM with tools in streaming mode.\r\n * Yields text chunks as they arrive, then a final 'done' event with the complete response.\r\n * Tool calls are accumulated and yielded at the end.\r\n */\r\nexport async function* callLLMWithToolsStream(\r\n messages: ChatMessage[],\r\n tools: ToolDefinition[],\r\n): AsyncGenerator<LLMStreamEvent, void, undefined> {\r\n if (!currentConfig) {\r\n throw new Error('LLM not configured. Set MEMORIX_LLM_API_KEY or OPENAI_API_KEY.');\r\n }\r\n\r\n if (currentConfig.provider === 'anthropic') {\r\n yield* callAnthropicWithToolsStream(messages, tools);\r\n return;\r\n }\r\n\r\n yield* callOpenAIWithToolsStream(messages, tools);\r\n}\r\n\r\n/** Tool definition for LLM function calling */\r\nexport interface ToolDefinition {\r\n name: string;\r\n description: string;\r\n parameters: Record<string, unknown>; // JSON Schema object\r\n}\r\n\r\n/** Chat message for multi-turn tool-use conversations */\r\nexport interface ChatMessage {\r\n role: 'system' | 'user' | 'assistant' | 'tool';\r\n content: string;\r\n toolCallId?: string; // for role='tool': which call this result is for\r\n toolCalls?: ToolCall[]; // for role='assistant': tool calls made\r\n name?: string; // for role='tool': function name\r\n}\r\n\r\n/** Provider defaults per provider type */\r\nconst PROVIDER_DEFAULTS: Record<string, { baseUrl: string; model: string }> = {\r\n openai: { baseUrl: 'https://api.openai.com/v1', model: 'gpt-4.1-nano' },\r\n anthropic: { baseUrl: 'https://api.anthropic.com/v1', model: 'claude-3-5-haiku-latest' },\r\n openrouter: { baseUrl: 'https://openrouter.ai/api/v1', model: 'openai/gpt-4.1-nano' },\r\n custom: { baseUrl: 'http://localhost:11434/v1', model: 'llama3' },\r\n};\r\n\r\nlet currentConfig: LLMConfig | null = null;\r\n\r\n/**\r\n * Initialize the LLM provider from environment variables.\r\n * Returns null if no API key is configured — Memorix gracefully degrades.\r\n */\r\nexport function initLLM(): LLMConfig | null {\r\n // Unified config: env vars > config.json > defaults\r\n const { getLLMApiKey, getLLMProvider, getLLMModel, getLLMBaseUrl } = require('../config.js');\r\n\r\n const apiKey = getLLMApiKey();\r\n if (!apiKey) {\r\n currentConfig = null;\r\n return null;\r\n }\r\n\r\n const provider = getLLMProvider() as LLMConfig['provider'];\r\n const defaults = PROVIDER_DEFAULTS[provider] ?? PROVIDER_DEFAULTS.openai;\r\n\r\n currentConfig = {\r\n provider,\r\n apiKey,\r\n model: getLLMModel(defaults.model),\r\n baseUrl: getLLMBaseUrl(defaults.baseUrl),\r\n };\r\n\r\n return currentConfig;\r\n}\r\n\r\n/**\r\n * Check if LLM is available.\r\n */\r\nexport function isLLMEnabled(): boolean {\r\n return currentConfig !== null;\r\n}\r\n\r\n/**\r\n * Get current LLM config (for display/debug).\r\n */\r\nexport function getLLMConfig(): LLMConfig | null {\r\n return currentConfig;\r\n}\r\n\r\n/**\r\n * Set LLM config directly (for testing or programmatic use).\r\n */\r\nexport function setLLMConfig(config: LLMConfig | null): void {\r\n currentConfig = config;\r\n}\r\n\r\n/**\r\n * Call the LLM with a prompt.\r\n * Uses OpenAI-compatible chat completions API (works with OpenRouter, Ollama, etc.)\r\n *\r\n * For Anthropic, we use their Messages API directly.\r\n */\r\nexport async function callLLM(\r\n systemPrompt: string,\r\n userMessage: string,\r\n): Promise<LLMResponse> {\r\n if (!currentConfig) {\r\n throw new Error('LLM not configured. Set MEMORIX_LLM_API_KEY or OPENAI_API_KEY.');\r\n }\r\n\r\n if (currentConfig.provider === 'anthropic') {\r\n return callAnthropic(systemPrompt, userMessage);\r\n }\r\n\r\n return callOpenAICompatible(systemPrompt, userMessage);\r\n}\r\n\r\n/**\r\n * OpenAI-compatible API call (works with OpenAI, OpenRouter, Ollama, etc.)\r\n */\r\nasync function callOpenAICompatible(\r\n systemPrompt: string,\r\n userMessage: string,\r\n): Promise<LLMResponse> {\r\n const config = currentConfig!;\r\n // Auto-fix: append /v1 if baseUrl doesn't end with it (common user mistake)\r\n let base = config.baseUrl!.replace(/\\/+$/, '');\r\n if (!base.endsWith('/v1')) base += '/v1';\r\n const url = `${base}/chat/completions`;\r\n\r\n const response = await fetch(url, {\r\n signal: AbortSignal.timeout(LLM_CALL_TIMEOUT_MS),\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n 'Authorization': `Bearer ${config.apiKey}`,\r\n },\r\n body: JSON.stringify({\r\n model: config.model,\r\n messages: [\r\n { role: 'system', content: systemPrompt },\r\n { role: 'user', content: userMessage },\r\n ],\r\n temperature: 0.1,\r\n max_tokens: 1024,\r\n }),\r\n });\r\n\r\n if (!response.ok) {\r\n const error = await readResponseText(response, undefined, 64 * 1024).catch(() => 'unknown error');\r\n throw new Error(`LLM API error (${response.status}): ${error}`);\r\n }\r\n\r\n const data = await readResponseJson<{\r\n choices: Array<{ message: { content: string } }>;\r\n usage?: { prompt_tokens: number; completion_tokens: number };\r\n }>(response);\r\n\r\n return {\r\n content: data.choices[0]?.message?.content ?? '',\r\n usage: data.usage ? {\r\n promptTokens: data.usage.prompt_tokens,\r\n completionTokens: data.usage.completion_tokens,\r\n } : undefined,\r\n };\r\n}\r\n\r\n/**\r\n * Anthropic Messages API call.\r\n */\r\nasync function callAnthropic(\r\n systemPrompt: string,\r\n userMessage: string,\r\n): Promise<LLMResponse> {\r\n const config = currentConfig!;\r\n const url = `${config.baseUrl}/messages`;\r\n\r\n const response = await fetch(url, {\r\n signal: AbortSignal.timeout(LLM_CALL_TIMEOUT_MS),\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n 'x-api-key': config.apiKey,\r\n 'anthropic-version': '2023-06-01',\r\n },\r\n body: JSON.stringify({\r\n model: config.model,\r\n system: systemPrompt,\r\n messages: [\r\n { role: 'user', content: userMessage },\r\n ],\r\n temperature: 0.1,\r\n max_tokens: 1024,\r\n }),\r\n });\r\n\r\n if (!response.ok) {\r\n const error = await readResponseText(response, undefined, 64 * 1024).catch(() => 'unknown error');\r\n throw new Error(`Anthropic API error (${response.status}): ${error}`);\r\n }\r\n\r\n const data = await readResponseJson<{\r\n content: Array<{ text: string }>;\r\n usage?: { input_tokens: number; output_tokens: number };\r\n }>(response);\r\n\r\n return {\r\n content: data.content[0]?.text ?? '',\r\n usage: data.usage ? {\r\n promptTokens: data.usage.input_tokens,\r\n completionTokens: data.usage.output_tokens,\r\n } : undefined,\r\n };\r\n}\r\n\r\n/**\r\n * Call the LLM with tool definitions (agentic harness pattern).\r\n *\r\n * The LLM can decide to call tools or respond directly.\r\n * Returns structured response with tool_calls for the agentic loop.\r\n */\r\nexport async function callLLMWithTools(\r\n messages: ChatMessage[],\r\n tools: ToolDefinition[],\r\n signal?: AbortSignal,\r\n): Promise<LLMToolResponse> {\r\n if (!currentConfig) {\r\n throw new Error('LLM not configured. Set MEMORIX_LLM_API_KEY or OPENAI_API_KEY.');\r\n }\r\n\r\n if (currentConfig.provider === 'anthropic') {\r\n return callAnthropicWithTools(messages, tools, signal);\r\n }\r\n\r\n return callOpenAIWithTools(messages, tools, signal);\r\n}\r\n\r\n/**\r\n * OpenAI-compatible tool calling (works with OpenAI, OpenRouter, Ollama, etc.)\r\n */\r\nasync function callOpenAIWithTools(\r\n messages: ChatMessage[],\r\n tools: ToolDefinition[],\r\n signal?: AbortSignal,\r\n): Promise<LLMToolResponse> {\r\n const config = currentConfig!;\r\n let base = config.baseUrl!.replace(/\\/+$/, '');\r\n if (!base.endsWith('/v1')) base += '/v1';\r\n const url = `${base}/chat/completions`;\r\n\r\n // Convert ChatMessage[] to OpenAI format\r\n const openaiMessages: Array<Record<string, unknown>> = messages.map((msg) => {\r\n if (msg.role === 'tool') {\r\n return { role: 'tool', content: msg.content, tool_call_id: msg.toolCallId };\r\n }\r\n if (msg.role === 'assistant' && msg.toolCalls && msg.toolCalls.length > 0) {\r\n return {\r\n role: 'assistant',\r\n content: msg.content || null,\r\n tool_calls: msg.toolCalls.map((tc) => ({\r\n id: tc.id,\r\n type: 'function',\r\n function: { name: tc.name, arguments: tc.arguments },\r\n })),\r\n };\r\n }\r\n return { role: msg.role, content: msg.content };\r\n });\r\n\r\n const openaiTools = tools.map((t) => ({\r\n type: 'function' as const,\r\n function: { name: t.name, description: t.description, parameters: t.parameters },\r\n }));\r\n\r\n const fetchSignal = signal\r\n ? AbortSignal.any([signal, AbortSignal.timeout(LLM_CALL_TIMEOUT_MS)])\r\n : AbortSignal.timeout(LLM_CALL_TIMEOUT_MS);\r\n\r\n const response = await fetch(url, {\r\n signal: fetchSignal,\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n 'Authorization': `Bearer ${config.apiKey}`,\r\n },\r\n body: JSON.stringify({\r\n model: config.model,\r\n messages: openaiMessages,\r\n tools: openaiTools.length > 0 ? openaiTools : undefined,\r\n temperature: 0.3,\r\n max_tokens: 2048,\r\n }),\r\n });\r\n\r\n if (!response.ok) {\r\n const error = await readResponseText(response, signal, 64 * 1024).catch(() => 'unknown error');\r\n throw new Error(`LLM tool-call API error (${response.status}): ${error}`);\r\n }\r\n\r\n const data = await readResponseJson<{\r\n choices: Array<{\r\n message: {\r\n content: string | null;\r\n tool_calls?: Array<{\r\n id: string;\r\n type: string;\r\n function: { name: string; arguments: string };\r\n }>;\r\n };\r\n finish_reason: string;\r\n }>;\r\n usage?: { prompt_tokens: number; completion_tokens: number };\r\n }>(response, signal);\r\n\r\n const choice = data.choices[0];\r\n const content = choice?.message?.content ?? '';\r\n const toolCalls: ToolCall[] = (choice?.message?.tool_calls ?? []).map((tc: { id: string; function: { name: string; arguments: string } }) => ({\r\n id: tc.id,\r\n name: tc.function.name,\r\n arguments: tc.function.arguments,\r\n }));\r\n\r\n const stopReason = choice?.finish_reason === 'tool_calls' ? 'tool_use'\r\n : choice?.finish_reason === 'stop' ? 'stop'\r\n : 'unknown';\r\n\r\n return {\r\n content,\r\n toolCalls,\r\n stopReason,\r\n usage: data.usage ? {\r\n promptTokens: data.usage.prompt_tokens,\r\n completionTokens: data.usage.completion_tokens,\r\n } : undefined,\r\n };\r\n}\r\n\r\n/**\r\n * Anthropic tool calling (Messages API with tool_use).\r\n */\r\nasync function callAnthropicWithTools(\r\n messages: ChatMessage[],\r\n tools: ToolDefinition[],\r\n signal?: AbortSignal,\r\n): Promise<LLMToolResponse> {\r\n const config = currentConfig!;\r\n const url = `${config.baseUrl}/messages`;\r\n\r\n // Separate system message from the rest\r\n const systemContent = messages.find((m) => m.role === 'system')?.content ?? '';\r\n const nonSystemMessages = messages.filter((m) => m.role !== 'system');\r\n\r\n // Convert to Anthropic message format\r\n const anthropicMessages: Array<Record<string, unknown>> = [];\r\n for (const msg of nonSystemMessages) {\r\n if (msg.role === 'user') {\r\n anthropicMessages.push({ role: 'user', content: msg.content });\r\n } else if (msg.role === 'assistant') {\r\n const contentBlocks: Array<Record<string, unknown>> = [];\r\n if (msg.content) contentBlocks.push({ type: 'text', text: msg.content });\r\n if (msg.toolCalls) {\r\n for (const tc of msg.toolCalls) {\r\n contentBlocks.push({\r\n type: 'tool_use',\r\n id: tc.id,\r\n name: tc.name,\r\n input: JSON.parse(tc.arguments),\r\n });\r\n }\r\n }\r\n anthropicMessages.push({ role: 'assistant', content: contentBlocks });\r\n } else if (msg.role === 'tool') {\r\n anthropicMessages.push({\r\n role: 'user',\r\n content: [{\r\n type: 'tool_result',\r\n tool_use_id: msg.toolCallId,\r\n content: msg.content,\r\n }],\r\n });\r\n }\r\n }\r\n\r\n const anthropicTools = tools.map((t) => ({\r\n name: t.name,\r\n description: t.description,\r\n input_schema: t.parameters,\r\n }));\r\n\r\n const fetchSignal = signal\r\n ? AbortSignal.any([signal, AbortSignal.timeout(LLM_CALL_TIMEOUT_MS)])\r\n : AbortSignal.timeout(LLM_CALL_TIMEOUT_MS);\r\n\r\n const response = await fetch(url, {\r\n signal: fetchSignal,\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n 'x-api-key': config.apiKey,\r\n 'anthropic-version': '2023-06-01',\r\n },\r\n body: JSON.stringify({\r\n model: config.model,\r\n system: systemContent,\r\n messages: anthropicMessages,\r\n tools: anthropicTools.length > 0 ? anthropicTools : undefined,\r\n temperature: 0.3,\r\n max_tokens: 2048,\r\n }),\r\n });\r\n\r\n if (!response.ok) {\r\n const error = await readResponseText(response, signal, 64 * 1024).catch(() => 'unknown error');\r\n throw new Error(`Anthropic tool-call API error (${response.status}): ${error}`);\r\n }\r\n\r\n const data = await readResponseJson<{\r\n content: Array<{ type: string; text?: string; id?: string; name?: string; input?: unknown }>;\r\n stop_reason: string;\r\n usage?: { input_tokens: number; output_tokens: number };\r\n }>(response, signal);\r\n\r\n let content = '';\r\n const toolCalls: ToolCall[] = [];\r\n for (const block of data.content) {\r\n if (block.type === 'text' && block.text) {\r\n content += block.text;\r\n } else if (block.type === 'tool_use' && block.id && block.name) {\r\n toolCalls.push({\r\n id: block.id,\r\n name: block.name,\r\n arguments: JSON.stringify(block.input ?? {}),\r\n });\r\n }\r\n }\r\n\r\n const stopReason = data.stop_reason === 'tool_use' ? 'tool_use'\r\n : data.stop_reason === 'end_turn' ? 'end_turn'\r\n : 'unknown';\r\n\r\n return {\r\n content,\r\n toolCalls,\r\n stopReason,\r\n usage: data.usage ? {\r\n promptTokens: data.usage.input_tokens,\r\n completionTokens: data.usage.output_tokens,\r\n } : undefined,\r\n };\r\n}\r\n\r\n// ── Streaming implementations ────────────────────────────────────\r\n\r\n/**\r\n * OpenAI-compatible streaming with tool support.\r\n * Parses SSE chunks, yields text deltas, accumulates tool calls.\r\n */\r\nasync function* callOpenAIWithToolsStream(\r\n messages: ChatMessage[],\r\n tools: ToolDefinition[],\r\n): AsyncGenerator<LLMStreamEvent, void, undefined> {\r\n const config = currentConfig!;\r\n let base = config.baseUrl!.replace(/\\/+$/, '');\r\n if (!base.endsWith('/v1')) base += '/v1';\r\n const url = `${base}/chat/completions`;\r\n\r\n const openaiMessages: Array<Record<string, unknown>> = messages.map((msg) => {\r\n if (msg.role === 'tool') {\r\n return { role: 'tool', content: msg.content, tool_call_id: msg.toolCallId };\r\n }\r\n if (msg.role === 'assistant' && msg.toolCalls && msg.toolCalls.length > 0) {\r\n return {\r\n role: 'assistant',\r\n content: msg.content || null,\r\n tool_calls: msg.toolCalls.map((tc) => ({\r\n id: tc.id,\r\n type: 'function',\r\n function: { name: tc.name, arguments: tc.arguments },\r\n })),\r\n };\r\n }\r\n return { role: msg.role, content: msg.content };\r\n });\r\n\r\n const openaiTools = tools.map((t) => ({\r\n type: 'function' as const,\r\n function: { name: t.name, description: t.description, parameters: t.parameters },\r\n }));\r\n\r\n const response = await fetch(url, {\r\n signal: AbortSignal.timeout(LLM_CALL_TIMEOUT_MS * 2), // longer timeout for streaming\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n 'Authorization': `Bearer ${config.apiKey}`,\r\n },\r\n body: JSON.stringify({\r\n model: config.model,\r\n messages: openaiMessages,\r\n tools: openaiTools.length > 0 ? openaiTools : undefined,\r\n temperature: 0.3,\r\n max_tokens: 2048,\r\n stream: true,\r\n }),\r\n });\r\n\r\n if (!response.ok) {\r\n const error = await response.text().catch(() => 'unknown error');\r\n throw new Error(`LLM streaming API error (${response.status}): ${error}`);\r\n }\r\n\r\n // Parse SSE stream\r\n const reader = response.body?.getReader();\r\n if (!reader) throw new Error('No response body for streaming');\r\n\r\n const decoder = new TextDecoder();\r\n let fullContent = '';\r\n const toolCallMap = new Map<number, { id: string; name: string; arguments: string }>();\r\n let finishReason = 'unknown';\r\n let buffer = '';\r\n\r\n try {\r\n while (true) {\r\n const { done, value } = await reader.read();\r\n if (done) break;\r\n\r\n buffer += decoder.decode(value, { stream: true });\r\n const lines = buffer.split('\\n');\r\n buffer = lines.pop() ?? ''; // keep incomplete line in buffer\r\n\r\n for (const line of lines) {\r\n const trimmed = line.trim();\r\n if (!trimmed || trimmed === 'data: [DONE]') continue;\r\n if (!trimmed.startsWith('data: ')) continue;\r\n\r\n try {\r\n const chunk = JSON.parse(trimmed.slice(6));\r\n const delta = chunk.choices?.[0]?.delta;\r\n if (!delta) continue;\r\n\r\n // Text content\r\n if (delta.content) {\r\n fullContent += delta.content;\r\n yield { type: 'text' as const, content: delta.content };\r\n }\r\n\r\n // Tool call deltas — accumulate\r\n if (delta.tool_calls) {\r\n for (const tc of delta.tool_calls) {\r\n const idx = tc.index ?? 0;\r\n if (!toolCallMap.has(idx)) {\r\n toolCallMap.set(idx, {\r\n id: tc.id ?? '',\r\n name: tc.function?.name ?? '',\r\n arguments: tc.function?.arguments ?? '',\r\n });\r\n } else {\r\n const existing = toolCallMap.get(idx)!;\r\n if (tc.id) existing.id = tc.id;\r\n if (tc.function?.name) existing.name = tc.function.name;\r\n if (tc.function?.arguments) existing.arguments += tc.function.arguments;\r\n }\r\n }\r\n }\r\n\r\n // Finish reason\r\n if (chunk.choices?.[0]?.finish_reason) {\r\n finishReason = chunk.choices[0].finish_reason;\r\n }\r\n } catch {\r\n // Skip malformed JSON chunks\r\n }\r\n }\r\n }\r\n } finally {\r\n reader.releaseLock();\r\n }\r\n\r\n const toolCalls = [...toolCallMap.values()].map((tc) => ({\r\n id: tc.id,\r\n name: tc.name,\r\n arguments: tc.arguments,\r\n }));\r\n\r\n // Yield tool_call events\r\n for (const tc of toolCalls) {\r\n yield { type: 'tool_call' as const, toolCall: tc };\r\n }\r\n\r\n const stopReason = finishReason === 'tool_calls' ? 'tool_use'\r\n : finishReason === 'stop' ? 'stop'\r\n : 'unknown';\r\n\r\n yield {\r\n type: 'done' as const,\r\n response: {\r\n content: fullContent,\r\n toolCalls,\r\n stopReason,\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * Anthropic streaming with tool support.\r\n * Parses SSE events, yields text deltas, accumulates tool_use blocks.\r\n */\r\nasync function* callAnthropicWithToolsStream(\r\n messages: ChatMessage[],\r\n tools: ToolDefinition[],\r\n): AsyncGenerator<LLMStreamEvent, void, undefined> {\r\n const config = currentConfig!;\r\n const url = `${config.baseUrl}/messages`;\r\n\r\n const systemContent = messages.find((m) => m.role === 'system')?.content ?? '';\r\n const nonSystemMessages = messages.filter((m) => m.role !== 'system');\r\n\r\n const anthropicMessages: Array<Record<string, unknown>> = [];\r\n for (const msg of nonSystemMessages) {\r\n if (msg.role === 'user') {\r\n anthropicMessages.push({ role: 'user', content: msg.content });\r\n } else if (msg.role === 'assistant') {\r\n const contentBlocks: Array<Record<string, unknown>> = [];\r\n if (msg.content) contentBlocks.push({ type: 'text', text: msg.content });\r\n if (msg.toolCalls) {\r\n for (const tc of msg.toolCalls) {\r\n contentBlocks.push({\r\n type: 'tool_use',\r\n id: tc.id,\r\n name: tc.name,\r\n input: JSON.parse(tc.arguments),\r\n });\r\n }\r\n }\r\n anthropicMessages.push({ role: 'assistant', content: contentBlocks });\r\n } else if (msg.role === 'tool') {\r\n anthropicMessages.push({\r\n role: 'user',\r\n content: [{\r\n type: 'tool_result',\r\n tool_use_id: msg.toolCallId,\r\n content: msg.content,\r\n }],\r\n });\r\n }\r\n }\r\n\r\n const anthropicTools = tools.map((t) => ({\r\n name: t.name,\r\n description: t.description,\r\n input_schema: t.parameters,\r\n }));\r\n\r\n const response = await fetch(url, {\r\n signal: AbortSignal.timeout(LLM_CALL_TIMEOUT_MS * 2),\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n 'x-api-key': config.apiKey,\r\n 'anthropic-version': '2023-06-01',\r\n },\r\n body: JSON.stringify({\r\n model: config.model,\r\n system: systemContent,\r\n messages: anthropicMessages,\r\n tools: anthropicTools.length > 0 ? anthropicTools : undefined,\r\n temperature: 0.3,\r\n max_tokens: 2048,\r\n stream: true,\r\n }),\r\n });\r\n\r\n if (!response.ok) {\r\n const error = await response.text().catch(() => 'unknown error');\r\n throw new Error(`Anthropic streaming API error (${response.status}): ${error}`);\r\n }\r\n\r\n const reader = response.body?.getReader();\r\n if (!reader) throw new Error('No response body for streaming');\r\n\r\n const decoder = new TextDecoder();\r\n let fullContent = '';\r\n const toolCalls: ToolCall[] = [];\r\n let currentToolId = '';\r\n let currentToolName = '';\r\n let currentToolInput = '';\r\n let stopReason = 'unknown';\r\n let buffer = '';\r\n\r\n try {\r\n while (true) {\r\n const { done, value } = await reader.read();\r\n if (done) break;\r\n\r\n buffer += decoder.decode(value, { stream: true });\r\n const lines = buffer.split('\\n');\r\n buffer = lines.pop() ?? '';\r\n\r\n for (const line of lines) {\r\n const trimmed = line.trim();\r\n if (!trimmed.startsWith('data: ')) continue;\r\n\r\n try {\r\n const event = JSON.parse(trimmed.slice(6));\r\n\r\n if (event.type === 'content_block_delta') {\r\n const delta = event.delta;\r\n if (delta?.type === 'text_delta' && delta.text) {\r\n fullContent += delta.text;\r\n yield { type: 'text' as const, content: delta.text };\r\n } else if (delta?.type === 'input_json_delta' && delta.partial_json) {\r\n currentToolInput += delta.partial_json;\r\n }\r\n } else if (event.type === 'content_block_start') {\r\n const block = event.content_block;\r\n if (block?.type === 'tool_use') {\r\n currentToolId = block.id ?? '';\r\n currentToolName = block.name ?? '';\r\n currentToolInput = '';\r\n }\r\n } else if (event.type === 'content_block_stop') {\r\n // Finalize current tool call\r\n if (currentToolId && currentToolName) {\r\n const tc: ToolCall = {\r\n id: currentToolId,\r\n name: currentToolName,\r\n arguments: currentToolInput || '{}',\r\n };\r\n toolCalls.push(tc);\r\n yield { type: 'tool_call' as const, toolCall: tc };\r\n currentToolId = '';\r\n currentToolName = '';\r\n currentToolInput = '';\r\n }\r\n } else if (event.type === 'message_delta') {\r\n if (event.delta?.stop_reason) {\r\n stopReason = event.delta.stop_reason;\r\n }\r\n }\r\n } catch {\r\n // Skip malformed JSON\r\n }\r\n }\r\n }\r\n } finally {\r\n reader.releaseLock();\r\n }\r\n\r\n const mappedStopReason = stopReason === 'tool_use' ? 'tool_use'\r\n : stopReason === 'end_turn' ? 'end_turn'\r\n : 'unknown';\r\n\r\n yield {\r\n type: 'done' as const,\r\n response: {\r\n content: fullContent,\r\n toolCalls,\r\n stopReason: mappedStopReason,\r\n },\r\n };\r\n}\r\n","import { callLLM, initLLM, isLLMEnabled } from '../llm/provider.js';\r\n\r\nconst CJK_PATTERN = /[\\u4e00-\\u9fff\\u3040-\\u309f\\u30a0-\\u30ff\\uac00-\\ud7af]/g;\r\nconst COMMAND_LIKE_QUERY = /\\b(git|npm|npx|pnpm|yarn|node|bash|powershell|curl|memorix)\\b/i;\r\n\r\nconst QUERY_EXPANSION_PROMPT = `You rewrite coding-memory search queries for retrieval.\r\n\r\nRules:\r\n- Input may be Chinese, Japanese, or Korean\r\n- Output one short English search phrase only\r\n- Keep the technical meaning\r\n- Prefer wording that would match engineering notes or memory titles\r\n- No bullets, no JSON, no explanation, no quotes\r\n- 4 to 12 words is ideal`;\r\n\r\nfunction isCjkHeavy(query: string): boolean {\r\n const cjkCount = (query.match(CJK_PATTERN) || []).length;\r\n return query.length > 0 && cjkCount / query.length > 0.3;\r\n}\r\n\r\nfunction normalizeExpansion(text: string): string {\r\n return text\r\n .trim()\r\n .replace(/^[-*]\\s*/, '')\r\n .replace(/^[\"'`]+|[\"'`]+$/g, '')\r\n .split(/\\r?\\n/)[0]\r\n .trim();\r\n}\r\n\r\nexport async function maybeExpandSearchQuery(query: string): Promise<string> {\r\n if (!query || !isCjkHeavy(query) || COMMAND_LIKE_QUERY.test(query)) {\r\n return query;\r\n }\r\n\r\n if (!isLLMEnabled()) {\r\n initLLM();\r\n }\r\n\r\n if (!isLLMEnabled()) {\r\n return query;\r\n }\r\n\r\n try {\r\n const response = await callLLM(QUERY_EXPANSION_PROMPT, query);\r\n const expanded = normalizeExpansion(response.content);\r\n if (!expanded) return query;\r\n if (expanded.toLowerCase() === query.toLowerCase()) return query;\r\n return `${query} ${expanded}`.slice(0, 500);\r\n } catch {\r\n return query;\r\n }\r\n}\r\n","/**\r\n * Project Alias Registry\r\n *\r\n * Solves the \"project identity split\" problem: the same project gets different\r\n * projectIds depending on which IDE detects it (git remote vs local path vs placeholder).\r\n *\r\n * Maintains a registry file (~/.memorix/data/.project-aliases.json) that groups\r\n * all known IDs for the same physical project under one canonical ID.\r\n *\r\n * Canonical ID priority: git remote > local > placeholder\r\n *\r\n * Matching heuristics (any match → same project):\r\n * 1. Same normalized rootPath\r\n * 2. Same git remote URL\r\n */\r\n\r\nimport { promises as fs } from 'node:fs';\r\nimport path from 'node:path';\r\nimport os from 'node:os';\r\nimport type { ProjectInfo } from '../types.js';\r\n\r\nconst DEFAULT_DATA_DIR = process.env.MEMORIX_DATA_DIR || path.join(os.homedir(), '.memorix', 'data');\r\nconst ALIAS_FILE = '.project-aliases.json';\r\n\r\n/** A group of project IDs that all refer to the same physical project */\r\nexport interface AliasGroup {\r\n /** The best-known ID for this project (git remote > local > placeholder) */\r\n canonical: string;\r\n /** All known IDs including canonical */\r\n aliases: string[];\r\n /** All known root paths (normalized) for this project */\r\n rootPaths: string[];\r\n /** Git remote URL if known */\r\n gitRemote?: string;\r\n}\r\n\r\ninterface AliasRegistry {\r\n version: 1;\r\n groups: AliasGroup[];\r\n}\r\n\r\n/** In-memory cache of the registry */\r\nlet registryCache: AliasRegistry | null = null;\r\nlet registryDir: string | null = null;\r\n\r\n/**\r\n * Normalize a root path for comparison.\r\n * - Forward slashes\r\n * - Lowercase on Windows\r\n * - No trailing slash\r\n */\r\nfunction normalizePath(p: string): string {\r\n let normalized = p.replace(/\\\\/g, '/').replace(/\\/+$/, '');\r\n if (process.platform === 'win32') {\r\n normalized = normalized.toLowerCase();\r\n }\r\n return normalized;\r\n}\r\n\r\n/**\r\n * Determine the priority of a project ID prefix.\r\n * Higher = better canonical candidate.\r\n */\r\nfunction idPriority(id: string): number {\r\n if (id.startsWith('untracked/')) return 0;\r\n if (id.startsWith('local/')) return 1;\r\n // Git remote-based IDs (e.g., \"user/repo\") have no prefix → highest priority\r\n return 2;\r\n}\r\n\r\n/**\r\n * Get the alias registry file path.\r\n */\r\nfunction getRegistryPath(baseDir?: string): string {\r\n return path.join(baseDir ?? registryDir ?? DEFAULT_DATA_DIR, ALIAS_FILE);\r\n}\r\n\r\n/**\r\n * Load the alias registry from disk.\r\n */\r\nasync function loadRegistry(baseDir?: string): Promise<AliasRegistry> {\r\n if (registryCache) return registryCache;\r\n try {\r\n const data = await fs.readFile(getRegistryPath(baseDir), 'utf-8');\r\n const parsed = JSON.parse(data);\r\n if (parsed.version === 1 && Array.isArray(parsed.groups)) {\r\n registryCache = parsed;\r\n return registryCache!;\r\n }\r\n } catch { /* file doesn't exist yet */ }\r\n registryCache = { version: 1, groups: [] };\r\n return registryCache;\r\n}\r\n\r\n/**\r\n * Save the alias registry to disk.\r\n */\r\nasync function saveRegistry(baseDir?: string): Promise<void> {\r\n if (!registryCache) return;\r\n const filePath = getRegistryPath(baseDir);\r\n await fs.mkdir(path.dirname(filePath), { recursive: true });\r\n await fs.writeFile(filePath, JSON.stringify(registryCache, null, 2), 'utf-8');\r\n}\r\n\r\n/**\r\n * Find an existing alias group that matches the given project info.\r\n *\r\n * Match criteria (any one is sufficient):\r\n * 1. Group already contains this exact ID\r\n * 2. Group has a matching normalized rootPath\r\n * 3. Group has a matching gitRemote\r\n */\r\nfunction findMatchingGroup(\r\n registry: AliasRegistry,\r\n projectInfo: ProjectInfo,\r\n): AliasGroup | null {\r\n const normalizedRoot = normalizePath(projectInfo.rootPath);\r\n\r\n for (const group of registry.groups) {\r\n // Match by ID\r\n if (group.aliases.includes(projectInfo.id)) return group;\r\n\r\n // Match by rootPath\r\n if (group.rootPaths.some((rp) => rp === normalizedRoot)) return group;\r\n\r\n // Match by git remote\r\n if (projectInfo.gitRemote && group.gitRemote && group.gitRemote === projectInfo.gitRemote) {\r\n return group;\r\n }\r\n }\r\n\r\n return null;\r\n}\r\n\r\n/**\r\n * Select the best canonical ID from a list of aliases.\r\n * Priority: git remote-based > local > placeholder\r\n */\r\nfunction selectCanonical(aliases: string[]): string {\r\n return [...aliases].sort((a, b) => idPriority(b) - idPriority(a))[0];\r\n}\r\n\r\n/**\r\n * Register a detected project in the alias registry.\r\n *\r\n * If the project matches an existing group, merges the new ID/rootPath into it.\r\n * If not, creates a new group.\r\n *\r\n * Returns the **canonical** project ID that should be used for storage and search.\r\n *\r\n * @param projectInfo - The detected project info from detectProject()\r\n * @param baseDir - Override data directory (for testing)\r\n * @returns The canonical project ID\r\n */\r\nexport async function registerAlias(projectInfo: ProjectInfo, baseDir?: string): Promise<string> {\r\n const registry = await loadRegistry(baseDir);\r\n const normalizedRoot = normalizePath(projectInfo.rootPath);\r\n\r\n const existingGroup = findMatchingGroup(registry, projectInfo);\r\n\r\n if (existingGroup) {\r\n // Merge into existing group\r\n let changed = false;\r\n\r\n if (!existingGroup.aliases.includes(projectInfo.id)) {\r\n existingGroup.aliases.push(projectInfo.id);\r\n changed = true;\r\n }\r\n\r\n if (!existingGroup.rootPaths.includes(normalizedRoot)) {\r\n existingGroup.rootPaths.push(normalizedRoot);\r\n changed = true;\r\n }\r\n\r\n if (projectInfo.gitRemote && !existingGroup.gitRemote) {\r\n existingGroup.gitRemote = projectInfo.gitRemote;\r\n changed = true;\r\n }\r\n\r\n // Re-evaluate canonical (maybe we just learned a git remote ID)\r\n const newCanonical = selectCanonical(existingGroup.aliases);\r\n if (newCanonical !== existingGroup.canonical) {\r\n existingGroup.canonical = newCanonical;\r\n changed = true;\r\n }\r\n\r\n if (changed) {\r\n await saveRegistry(baseDir);\r\n }\r\n\r\n return existingGroup.canonical;\r\n }\r\n\r\n // Create new group\r\n const newGroup: AliasGroup = {\r\n canonical: projectInfo.id,\r\n aliases: [projectInfo.id],\r\n rootPaths: [normalizedRoot],\r\n ...(projectInfo.gitRemote ? { gitRemote: projectInfo.gitRemote } : {}),\r\n };\r\n registry.groups.push(newGroup);\r\n await saveRegistry(baseDir);\r\n\r\n return newGroup.canonical;\r\n}\r\n\r\n/**\r\n * Resolve all known aliases for a project ID.\r\n *\r\n * Used in search to expand the projectId filter so that observations stored\r\n * under any alias are found regardless of which IDE stored them.\r\n *\r\n * @returns Array of all known IDs for the same project, or [projectId] if no aliases found.\r\n */\r\nexport async function resolveAliases(projectId: string, baseDir?: string): Promise<string[]> {\r\n const registry = await loadRegistry(baseDir);\r\n\r\n for (const group of registry.groups) {\r\n if (group.aliases.includes(projectId) || group.canonical === projectId) {\r\n return [...group.aliases];\r\n }\r\n }\r\n\r\n return [projectId];\r\n}\r\n\r\n/**\r\n * Get the canonical ID for a project ID.\r\n *\r\n * @returns The canonical ID, or the input ID if no alias group found.\r\n */\r\nexport async function getCanonicalId(projectId: string, baseDir?: string): Promise<string> {\r\n const registry = await loadRegistry(baseDir);\r\n\r\n for (const group of registry.groups) {\r\n if (group.aliases.includes(projectId) || group.canonical === projectId) {\r\n return group.canonical;\r\n }\r\n }\r\n\r\n return projectId;\r\n}\r\n\r\n/**\r\n * Get all alias groups (for dashboard/debug).\r\n */\r\nexport async function getAllAliasGroups(baseDir?: string): Promise<AliasGroup[]> {\r\n const registry = await loadRegistry(baseDir);\r\n return registry.groups;\r\n}\r\n\r\n/**\r\n * Auto-merge obvious alias groups by scanning existing observation projectIds.\r\n *\r\n * Detects project IDs that share the same base name but have different prefixes:\r\n * - placeholder/foo + local/foo → merge under the higher-priority one\r\n * - AVIDS2/test-repo + local/test-repo → merge under AVIDS2/test-repo\r\n *\r\n * Called once during server startup after observations are loaded.\r\n *\r\n * @param observedIds - All unique projectIds found in observations data\r\n * @returns Number of new merges performed\r\n */\r\nexport async function autoMergeByBaseName(\r\n observedIds: string[],\r\n baseDir?: string,\r\n): Promise<number> {\r\n if (observedIds.length <= 1) return 0;\r\n\r\n const registry = await loadRegistry(baseDir);\r\n\r\n // Group observed IDs by their base name (the part after the last /)\r\n const byBaseName = new Map<string, string[]>();\r\n for (const id of observedIds) {\r\n const baseName = id.split('/').pop() ?? id;\r\n if (!byBaseName.has(baseName)) byBaseName.set(baseName, []);\r\n byBaseName.get(baseName)!.push(id);\r\n }\r\n\r\n let mergeCount = 0;\r\n\r\n for (const [_baseName, ids] of byBaseName) {\r\n if (ids.length <= 1) continue;\r\n\r\n // Check if these IDs are already in the same alias group\r\n const existingGroups = new Set<number>();\r\n const ungroupedIds: string[] = [];\r\n\r\n for (const id of ids) {\r\n const groupIdx = registry.groups.findIndex(\r\n g => g.aliases.includes(id) || g.canonical === id,\r\n );\r\n if (groupIdx >= 0) {\r\n existingGroups.add(groupIdx);\r\n } else {\r\n ungroupedIds.push(id);\r\n }\r\n }\r\n\r\n // If all IDs are already in the same group, skip\r\n if (existingGroups.size <= 1 && ungroupedIds.length === 0) continue;\r\n\r\n // Merge: pick the best canonical from all IDs\r\n const allIdsInGroup = [...ids];\r\n const canonical = selectCanonical(allIdsInGroup);\r\n\r\n if (existingGroups.size > 0) {\r\n // Merge into the first existing group\r\n const primaryIdx = [...existingGroups][0];\r\n const primaryGroup = registry.groups[primaryIdx];\r\n\r\n // Add all IDs to primary group\r\n for (const id of allIdsInGroup) {\r\n if (!primaryGroup.aliases.includes(id)) {\r\n primaryGroup.aliases.push(id);\r\n }\r\n }\r\n\r\n // Absorb other existing groups into primary\r\n const otherIdxs = [...existingGroups].slice(1).sort((a, b) => b - a);\r\n for (const idx of otherIdxs) {\r\n const other = registry.groups[idx];\r\n for (const alias of other.aliases) {\r\n if (!primaryGroup.aliases.includes(alias)) {\r\n primaryGroup.aliases.push(alias);\r\n }\r\n }\r\n for (const rp of other.rootPaths) {\r\n if (!primaryGroup.rootPaths.includes(rp)) {\r\n primaryGroup.rootPaths.push(rp);\r\n }\r\n }\r\n if (other.gitRemote && !primaryGroup.gitRemote) {\r\n primaryGroup.gitRemote = other.gitRemote;\r\n }\r\n registry.groups.splice(idx, 1);\r\n }\r\n\r\n // Re-evaluate canonical\r\n primaryGroup.canonical = selectCanonical(primaryGroup.aliases);\r\n mergeCount++;\r\n } else {\r\n // All ungrouped — create new group\r\n registry.groups.push({\r\n canonical,\r\n aliases: allIdsInGroup,\r\n rootPaths: [],\r\n });\r\n mergeCount++;\r\n }\r\n }\r\n\r\n if (mergeCount > 0) {\r\n await saveRegistry(baseDir);\r\n }\r\n\r\n return mergeCount;\r\n}\r\n\r\n/**\r\n * Initialize the alias registry with a data directory.\r\n * Should be called once during server startup.\r\n */\r\nexport function initAliasRegistry(dataDir: string): void {\r\n registryDir = dataDir;\r\n registryCache = null; // Force reload from new location\r\n}\r\n\r\n/**\r\n * Reset the in-memory cache (for testing).\r\n */\r\nexport function resetAliasCache(): void {\r\n registryCache = null;\r\n}\r\n","/**\r\n * LLM Quality Enhancements\r\n *\r\n * Premium memory quality features powered by LLM:\r\n * 1. Narrative Compression — compress verbose narratives into concise core knowledge\r\n * 2. Search Reranking — rerank search results by relevance to current task context\r\n *\r\n * Both features gracefully degrade: when LLM is not configured, they return\r\n * the original data unchanged.\r\n *\r\n * Performance targets:\r\n * - Compression: ~60% token reduction per stored memory\r\n * - Reranking: ~40% improvement in Top-5 precision\r\n */\r\n\r\nimport { callLLM, isLLMEnabled } from './provider.js';\r\n\r\n// ── Narrative Compression ────────────────────────────────────────\r\n\r\nconst COMPRESS_PROMPT = `You are a memory compression engine for a coding assistant.\r\n\r\nCompress the given narrative while preserving ALL technical facts and reasoning.\r\n\r\nRules:\r\n- Remove: filler words, debugging journey, repeated info already in facts\r\n- Keep: specific values, file paths, error messages, version numbers, config keys, causal relationships, design reasoning\r\n- Merge related points into dense sentences\r\n- If facts are provided separately, do NOT repeat them in the compressed narrative\r\n- Output the compressed text ONLY, no explanation or wrapper\r\n\r\nExamples:\r\nInput: \"我在调试过程中发现JWT token的refresh机制存在问题,具体来说是因为服务端没有实现自动续签,导致用户在24小时后会遇到静默的认证失败,之前我一直以为是网络问题但后来排查发现是token过期了\"\r\nOutput: \"JWT refresh无自动续签→24h后静默认证失败(非网络问题)\"\r\n\r\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.\"\r\nOutput: \"shadcn-blog部署: GH Actions构建→SCP到VPS→systemd管理, 弃Docker(复杂度过高), push到上线~2min\"`;\r\n\r\n/** Gentler prompt for high-value types where reasoning context matters */\r\nconst COMPRESS_PROMPT_GENTLE = `You are a memory compression engine for a coding assistant.\r\n\r\nLightly compress the given narrative — preserve reasoning, trade-offs, and \"why\" context.\r\n\r\nRules:\r\n- Only remove: obvious filler, debugging detours, info already in the separate facts list\r\n- PRESERVE: design reasoning, rejected alternatives, trade-off analysis, causal chains\r\n- Aim for ~70-80% of original length, NOT aggressive compression\r\n- If facts are provided separately, do NOT repeat them in the compressed narrative\r\n- Output the compressed text ONLY, no explanation or wrapper`;\r\n\r\n/**\r\n * Compress a narrative to its essential core using LLM.\r\n *\r\n * Returns the original narrative if:\r\n * - LLM is not enabled\r\n * - Narrative is already short (≤80 chars)\r\n * - Narrative is already concise (commands, file paths, git operations)\r\n * - LLM call fails\r\n */\r\nexport async function compressNarrative(\r\n narrative: string,\r\n facts?: string[],\r\n type?: string,\r\n): Promise<{ compressed: string; saved: number; usedLLM: boolean }> {\r\n const originalTokens = estimateTokens(narrative);\r\n\r\n // Skip compression for short narratives (≤150 chars is already concise)\r\n if (!isLLMEnabled() || narrative.length <= 150) {\r\n return { compressed: narrative, saved: 0, usedLLM: false };\r\n }\r\n\r\n // Skip compression for already-concise content that LLM can't meaningfully compress\r\n if (shouldSkipCompression(narrative, type)) {\r\n return { compressed: narrative, saved: 0, usedLLM: false };\r\n }\r\n\r\n try {\r\n const factsContext = facts && facts.length > 0\r\n ? `\\n\\nSeparate facts (already stored, don't repeat): ${facts.join('; ')}`\r\n : '';\r\n\r\n // Use gentler compression for high-value types where reasoning matters\r\n const HIGH_VALUE_TYPES = new Set(['decision', 'trade-off', 'why-it-exists', 'how-it-works']);\r\n const prompt = (type && HIGH_VALUE_TYPES.has(type)) ? COMPRESS_PROMPT_GENTLE : COMPRESS_PROMPT;\r\n const response = await callLLM(prompt, narrative + factsContext);\r\n const compressed = response.content.trim();\r\n\r\n // Sanity check: compressed should be shorter and non-empty\r\n if (!compressed || compressed.length >= narrative.length) {\r\n return { compressed: narrative, saved: 0, usedLLM: true };\r\n }\r\n\r\n const compressedTokens = estimateTokens(compressed);\r\n return {\r\n compressed,\r\n saved: originalTokens - compressedTokens,\r\n usedLLM: true,\r\n };\r\n } catch {\r\n return { compressed: narrative, saved: 0, usedLLM: false };\r\n }\r\n}\r\n\r\n// ── Search Reranking ─────────────────────────────────────────────\r\n\r\n/** Minimal search result for reranking */\r\nexport interface RerankCandidate {\r\n id: string;\r\n title: string;\r\n type: string;\r\n score: number;\r\n narrative?: string;\r\n}\r\n\r\nconst RERANK_PROMPT = `You are a memory relevance ranker for a coding assistant.\r\n\r\nGiven a QUERY (what the user/agent is looking for) and a list of CANDIDATE memories,\r\nrerank them by relevance to the query.\r\n\r\nRules:\r\n- Consider semantic relevance, not just keyword overlap\r\n- Gotchas and decisions related to the query topic should rank higher\r\n- Recent problem-solutions for the same component should rank higher\r\n- Command or audit-log memories (titles starting with \"Ran:\" or \"Command:\") should rank lower for natural-language questions unless the query is explicitly about commands, scripts, or audit history\r\n- Generic or loosely related memories should rank lower\r\n- Output ONLY a JSON array of IDs in order of relevance (most relevant first)\r\n- Include ALL candidate IDs, just reorder them\r\n\r\nExample output: [\"r1\", \"r3\", \"r2\"]`;\r\n\r\n/**\r\n * Rerank search results using LLM contextual understanding.\r\n *\r\n * Takes Orama's initial ranking and improves it by considering\r\n * semantic relevance to the current query/task context.\r\n *\r\n * Returns original order if LLM is not enabled or call fails.\r\n */\r\nexport async function rerankResults(\r\n query: string,\r\n candidates: RerankCandidate[],\r\n): Promise<{ reranked: RerankCandidate[]; usedLLM: boolean }> {\r\n // Skip if too few results or LLM not available\r\n if (!isLLMEnabled() || candidates.length <= 2) {\r\n return { reranked: candidates, usedLLM: false };\r\n }\r\n\r\n // Only rerank top-N to save LLM tokens (reranking 20+ is wasteful)\r\n const MAX_RERANK = 10;\r\n const toRerank = candidates.slice(0, MAX_RERANK);\r\n const rest = candidates.slice(MAX_RERANK);\r\n\r\n try {\r\n const candidateList = toRerank.map(c =>\r\n `[ID: ${c.id}] (${c.type}) ${c.title}${c.narrative ? ` — ${c.narrative.substring(0, 100)}` : ''}`,\r\n ).join('\\n');\r\n\r\n const response = await callLLM(RERANK_PROMPT, `QUERY: ${query}\\n\\nCANDIDATES:\\n${candidateList}`);\r\n\r\n // Parse response — handle markdown code blocks\r\n let content = response.content.trim();\r\n if (content.startsWith('```')) {\r\n content = content.replace(/^```(?:json)?\\s*/, '').replace(/\\s*```$/, '');\r\n }\r\n\r\n const rankedIds = JSON.parse(content) as string[];\r\n\r\n // Validate: must be an array of IDs matching our candidates\r\n if (!Array.isArray(rankedIds) || rankedIds.length === 0) {\r\n return { reranked: candidates, usedLLM: true };\r\n }\r\n\r\n // Build reranked list preserving original scores for display\r\n const idMap = new Map(toRerank.map(c => [c.id, c]));\r\n const reranked: RerankCandidate[] = [];\r\n const seen = new Set<string>();\r\n\r\n // Add IDs in LLM-reranked order\r\n for (const id of rankedIds) {\r\n const candidate = idMap.get(id);\r\n if (candidate && !seen.has(id)) {\r\n reranked.push(candidate);\r\n seen.add(id);\r\n }\r\n }\r\n\r\n // Add any candidates the LLM missed (safety: never lose results)\r\n for (const c of toRerank) {\r\n if (!seen.has(c.id)) {\r\n reranked.push(c);\r\n }\r\n }\r\n\r\n // Append non-reranked tail\r\n reranked.push(...rest);\r\n\r\n return { reranked, usedLLM: true };\r\n } catch {\r\n return { reranked: candidates, usedLLM: false };\r\n }\r\n}\r\n\r\n// ── Smart Compression Filtering ──────────────────────────────────\r\n\r\n/** Patterns that indicate already-concise content not worth compressing */\r\nconst SKIP_PATTERNS = [\r\n /^(?:Command|Run|Execute):\\s/i, // Shell commands\r\n /^(?:File|Edit|Changed):\\s/i, // File change descriptions\r\n /^git\\s+(?:add|commit|push|pull|log)/i, // Git operations\r\n /^(?:npm|npx|pnpm|yarn|bun)\\s/i, // Package manager commands\r\n /^(?:Remove-Item|New-Item|Set-Content)/i, // PowerShell commands\r\n /^[A-Za-z]:\\\\[\\w\\\\]/, // Windows file paths\r\n /^\\/(?:usr|home|var|etc|opt)\\//, // Unix file paths\r\n];\r\n\r\n/** Low-value observation types that hooks auto-capture (usually already terse) */\r\nconst LOW_COMPRESSION_TYPES = new Set(['what-changed', 'discovery', 'session-request']);\r\n\r\n/**\r\n * Determine if a narrative should skip LLM compression.\r\n *\r\n * Skip when:\r\n * - Content starts with command/path patterns (already structured, not prose)\r\n * - Type is hooks-auto-captured AND narrative is relatively short\r\n * - Narrative is mostly code/paths (high ratio of special chars)\r\n */\r\nfunction shouldSkipCompression(narrative: string, type?: string): boolean {\r\n // Skip command/path-like content\r\n const firstLine = narrative.split('\\n')[0];\r\n if (SKIP_PATTERNS.some(p => p.test(firstLine))) return true;\r\n\r\n // Skip short auto-captured observations (hooks produce terse what-changed)\r\n if (type && LOW_COMPRESSION_TYPES.has(type) && narrative.length < 200) return true;\r\n\r\n // Skip if narrative is mostly code/structured data (high special char ratio)\r\n const specialChars = (narrative.match(/[{}()\\[\\]<>:;=|\\\\\\/\\-_\\.@#$%^&*+~`\"']/g) || []).length;\r\n if (specialChars / narrative.length > 0.35) return true;\r\n\r\n return false;\r\n}\r\n\r\n// ── Utility ──────────────────────────────────────────────────────\r\n\r\n/** Rough token estimate: ~4 chars per token for English, ~2 for CJK */\r\nfunction estimateTokens(text: string): number {\r\n const cjkChars = (text.match(/[\\u4e00-\\u9fff\\u3040-\\u309f\\u30a0-\\u30ff\\uac00-\\ud7af]/g) || []).length;\r\n const otherChars = text.length - cjkChars;\r\n return Math.ceil(cjkChars / 1.5 + otherChars / 4);\r\n}\r\n","/**\r\n * Unified Freshness Gate (Phase 3a)\r\n *\r\n * Replaces withFreshObservations() as the public API for all retrieval\r\n * surfaces. Checks both observation and mini-skill generation counters\r\n * to ensure the Orama index is fully up-to-date before any read.\r\n *\r\n * withFreshObservations() remains in observations.ts as @internal —\r\n * only called by this module and legacy test code.\r\n */\r\n\r\nimport { ensureFreshObservations } from './observations.js';\r\nimport { getMiniSkillStore, isMiniSkillStoreInitialized } from '../store/mini-skill-store.js';\r\nimport { miniSkillToDocument } from '../skills/mini-skills.js';\r\nimport { insert, remove } from '@orama/orama';\r\n\r\n// ── Mini-skill index state ──────────────────────────────────────\r\n\r\nlet lastMiniSkillGeneration = -1;\r\n\r\n/**\r\n * Check if mini-skills have changed since our last index sync.\r\n * If stale, reindex all mini-skills in Orama.\r\n *\r\n * Returns true if the index was refreshed.\r\n */\r\nexport async function ensureFreshMiniSkills(): Promise<boolean> {\r\n // Skip silently when the store has not been initialized yet —\r\n // observation-only paths never call initMiniSkillStore().\r\n if (!isMiniSkillStoreInitialized()) return false;\r\n\r\n try {\r\n const store = getMiniSkillStore();\r\n const wasStale = await store.ensureFresh();\r\n const currentGen = store.getGeneration();\r\n\r\n if (wasStale || currentGen !== lastMiniSkillGeneration) {\r\n await reindexMiniSkills();\r\n lastMiniSkillGeneration = currentGen;\r\n return true;\r\n }\r\n } catch (err) {\r\n // Best-effort — don't crash the read path, but log for diagnostics\r\n console.warn(`[memorix] ensureFreshMiniSkills failed: ${err instanceof Error ? err.message : err}`);\r\n }\r\n return false;\r\n}\r\n\r\n// Deterministic tracking of indexed mini-skill doc IDs — avoids empty-term search\r\nconst indexedSkillDocIds = new Set<string>();\r\n\r\n/**\r\n * Reindex all mini-skills into the Orama database.\r\n * Uses deterministic doc ID tracking instead of empty-term search to ensure\r\n * all stale documents are removed reliably.\r\n */\r\nexport async function reindexMiniSkills(): Promise<number> {\r\n // Lazy import to avoid circular dependency\r\n const { getDb } = await import('../store/orama-store.js');\r\n const database = await getDb();\r\n\r\n // Remove previously tracked mini-skill documents by their known IDs\r\n for (const docId of indexedSkillDocIds) {\r\n try { await remove(database, docId); } catch { /* already removed or never existed */ }\r\n }\r\n indexedSkillDocIds.clear();\r\n\r\n // Load and index all current mini-skills\r\n const store = getMiniSkillStore();\r\n const skills = await store.loadAll();\r\n let indexed = 0;\r\n\r\n for (const skill of skills) {\r\n try {\r\n const doc = miniSkillToDocument(skill);\r\n await insert(database, doc);\r\n indexedSkillDocIds.add(doc.id);\r\n indexed++;\r\n } catch (err) {\r\n console.error(`[memorix] Failed to index mini-skill ${skill.id}: ${err instanceof Error ? err.message : err}`);\r\n }\r\n }\r\n\r\n return indexed;\r\n}\r\n\r\n// ── Unified gate ────────────────────────────────────────────────\r\n\r\n/**\r\n * Ensure both observations and mini-skills are fresh in the Orama index.\r\n * Returns true if any data source was refreshed.\r\n */\r\nexport async function ensureFreshIndex(): Promise<boolean> {\r\n let anyStale = false;\r\n const obsStale = await ensureFreshObservations();\r\n if (obsStale) anyStale = true;\r\n const skillsStale = await ensureFreshMiniSkills();\r\n if (skillsStale) anyStale = true;\r\n return anyStale;\r\n}\r\n\r\n/**\r\n * Centralized freshness gate — wraps a read-facing function with\r\n * ensureFreshIndex() so callers cannot forget the freshness check.\r\n *\r\n * Usage:\r\n * return withFreshIndex(async () => { ... read from Orama ... });\r\n *\r\n * Phase 3a: replaces withFreshObservations() at all retrieval call sites.\r\n */\r\nexport async function withFreshIndex<T>(fn: () => T | Promise<T>): Promise<T> {\r\n await ensureFreshIndex();\r\n return fn();\r\n}\r\n\r\n/**\r\n * Reset mini-skill freshness tracking. Used in tests.\r\n */\r\nexport function resetMiniSkillFreshness(): void {\r\n lastMiniSkillGeneration = -1;\r\n indexedSkillDocIds.clear();\r\n}\r\n","/**\r\n * Orama Store\r\n *\r\n * Full-text + vector + hybrid search engine backed by Orama.\r\n * Source: @orama/orama (10.1K stars, <2KB, pure JS, zero deps)\r\n *\r\n * Schema designed to store Observations with all searchable fields.\r\n * Vector search (embeddings) will be added in P1 phase.\r\n */\r\n\r\nimport { create, insert, search, remove, update, count, type AnyOrama } from '@orama/orama';\r\nimport type { MemorixDocument, SearchOptions, IndexEntry, KnowledgeLayer } from '../types.js';\r\nimport { OBSERVATION_ICONS, type ObservationType } from '../types.js';\r\nimport { resolveKnowledgeLayer } from '../skills/mini-skills.js';\r\nimport { getEmbeddingProvider, type EmbeddingProvider } from '../embedding/provider.js';\r\nimport { calculateProjectAffinity, extractProjectKeywords, type AffinityContext, type MemoryContent } from './project-affinity.js';\r\nimport { detectQueryIntent, applyIntentBoost } from '../search/intent-detector.js';\r\nimport { maybeExpandSearchQuery } from '../search/query-expansion.js';\r\n\r\nlet db: AnyOrama | null = null;\r\nlet embeddingEnabled = false;\r\nlet embeddingDimensions: number | null = null;\r\nconst NON_CJK_HYBRID_SIMILARITY = 0.45;\r\nconst lastSearchModeByProject = new Map<string, string>();\r\nconst SEARCH_MODE_DEFAULT_KEY = '__global__';\r\nexport function getLastSearchMode(projectId?: string): string {\r\n return lastSearchModeByProject.get(projectId ?? SEARCH_MODE_DEFAULT_KEY) ?? 'fulltext';\r\n}\r\n// Hard filter: titles starting with these are command execution logs, not knowledge.\r\n// They are excluded from results entirely (not just demoted) unless the query is command-like.\r\nconst COMMAND_LOG_TITLE = /^(Ran:|Command:|Executed:)\\s/i;\r\n// Soft demotion: titles containing shell-specific patterns get a score penalty.\r\nconst COMMAND_STYLE_TITLE = /(\\bfindstr\\b|\\bSelect-String\\b|\\bGet-Content\\b|\\bnpx\\s+vitest\\b|\\bnpx\\s+tsc\\b|\\b2>&1\\b)/i;\r\nconst COMMAND_LIKE_QUERY = /\\b(git|npm|npx|pnpm|yarn|node|bash|powershell|curl|memorix)\\b/i;\r\n// Stricter pattern: query IS a command (tool word at start, e.g. \"git status\", \"npm install\").\r\n// Does NOT match natural language like \"why is memorix search slow\".\r\nconst COMMAND_INTENT_QUERY = /^\\s*(git|npm|npx|pnpm|yarn|node|bash|powershell|curl|memorix)\\s/i;\r\n// Natural language markers — if ANY of these appear in the query, it is NOT a pure command.\r\n// Covers: question words, problem descriptors, reasoning words.\r\nconst NATURAL_LANGUAGE_MARKERS = /\\b(why|how|what|where|when|does|did|is|are|was|will|can|should|would|slow|fast|fail|error|bug|broken|issue|problem|wrong|crash|fix|work|performance|cause|reason|explain|understand)\\b/i;\r\n\r\n/**\r\n * Build a globally unique Orama document ID for an observation.\r\n * observationId is only unique within a project, so projectId must be included.\r\n */\r\nexport function makeOramaObservationId(projectId: string, observationId: number): string {\r\n return `obs-${encodeURIComponent(projectId)}-${observationId}`;\r\n}\r\n\r\nfunction makeEntryKey(projectId: string | undefined, observationId: number): string {\r\n return `${projectId ?? ''}::${observationId}`;\r\n}\r\n\r\nfunction isCommandLikeQuery(query: string): boolean {\r\n return COMMAND_LIKE_QUERY.test(query);\r\n}\r\n\r\n/**\r\n * Resolve the effective source label for intent-boost purposes.\r\n * Phase 1 introduced sourceDetail='git-ingest' as a more precise signal than\r\n * source='git'. Treat them as equivalent so intent-based source boosts\r\n * (e.g. what_changed → git: 2.0) apply to both representations.\r\n * Used in the source-aware retrieval path only — not stored or exported.\r\n */\r\nfunction effectiveSource(\r\n source: 'agent' | 'git' | 'manual',\r\n sourceDetail?: 'explicit' | 'hook' | 'git-ingest',\r\n): 'agent' | 'git' | 'manual' {\r\n return sourceDetail === 'git-ingest' ? 'git' : source;\r\n}\r\n\r\n/** True when the query IS a command (tool word leads), not just mentioning a tool. */\r\nfunction isCommandIntentQuery(query: string): boolean {\r\n if (!COMMAND_INTENT_QUERY.test(query)) return false;\r\n // If the query contains natural language markers (question words, problem\r\n // descriptors), it is a human question about a tool, not a CLI invocation.\r\n if (NATURAL_LANGUAGE_MARKERS.test(query)) return false;\r\n return true;\r\n}\r\n\r\n/** @internal Exported for testing only. */\r\nexport { classifyQueryTier as _classifyQueryTier };\r\n\r\n/**\r\n * Query tier classification for performance-aware search.\r\n * - 'fast': short/exact/command queries → fulltext only, no embedding, no rerank\r\n * - 'standard': normal queries → fulltext + embedding, no rerank\r\n * - 'heavy': CJK or long ambiguous queries → expansion + embedding + rerank\r\n */\r\ntype QueryTier = 'fast' | 'standard' | 'heavy';\r\n\r\nfunction classifyQueryTier(query: string): QueryTier {\r\n if (!query || query.trim().length === 0) return 'fast';\r\n // CJK-heavy queries must be checked FIRST — CJK text has no word-separating\r\n // spaces, so word-count heuristics would misclassify them as \"fast\".\r\n const cjkCount = (query.match(/[\\u4e00-\\u9fff\\u3040-\\u309f\\u30a0-\\u30ff\\uac00-\\ud7af]/g) || []).length;\r\n if (cjkCount / query.length > 0.3) return 'heavy';\r\n // Single-word or very short queries: fast path\r\n const words = query.trim().split(/\\s+/);\r\n if (words.length <= 1 && query.length <= 20) return 'fast';\r\n // Command-intent queries: fast path (\"git status\", \"npm install\")\r\n // NOT triggered by natural language mentioning a tool (\"why is memorix search slow\")\r\n if (isCommandIntentQuery(query)) return 'fast';\r\n // Long multi-word queries: heavy path\r\n if (words.length >= 5) return 'heavy';\r\n // Everything else: standard\r\n return 'standard';\r\n}\r\n\r\nfunction isCommandLogEntry(title: string): boolean {\r\n return COMMAND_LOG_TITLE.test(title);\r\n}\r\n\r\nfunction isCommandStyleEntry(title: string): boolean {\r\n return COMMAND_STYLE_TITLE.test(title);\r\n}\r\n\r\nfunction isVectorDimensionMismatchError(error: unknown): boolean {\r\n if (!(error instanceof Error)) return false;\r\n return (\r\n /declared as a \\d+-dimensional vector, but got a \\d+-dimensional vector/i.test(error.message) ||\r\n /dimension mismatch/i.test(error.message)\r\n );\r\n}\r\n\r\nfunction stripVectorSearchParams(params: Record<string, unknown>): Record<string, unknown> {\r\n const { mode, vector, similarity, hybridWeights, ...rest } = params;\r\n return rest;\r\n}\r\n\r\n/**\r\n * Initialize or return the Orama database instance.\r\n * Schema conditionally includes vector field based on embedding provider.\r\n * Graceful degradation: no provider → fulltext only, provider → hybrid.\r\n */\r\nexport async function getDb(): Promise<AnyOrama> {\r\n if (db) return db;\r\n\r\n // Check if embedding provider is available\r\n const provider = await getEmbeddingProvider();\r\n embeddingEnabled = provider !== null;\r\n embeddingDimensions = provider?.dimensions ?? null;\r\n\r\n const baseSchema = {\r\n id: 'string' as const,\r\n observationId: 'number' as const,\r\n entityName: 'string' as const,\r\n type: 'string' as const,\r\n title: 'string' as const,\r\n narrative: 'string' as const,\r\n facts: 'string' as const,\r\n filesModified: 'string' as const,\r\n concepts: 'string' as const,\r\n tokens: 'number' as const,\r\n createdAt: 'string' as const,\r\n projectId: 'string' as const,\r\n accessCount: 'number' as const,\r\n lastAccessedAt: 'string' as const,\r\n status: 'string' as const,\r\n source: 'string' as const,\r\n sourceDetail: 'string' as const,\r\n valueCategory: 'string' as const,\r\n documentType: 'string' as const,\r\n knowledgeLayer: 'string' as const,\r\n };\r\n\r\n // Dynamic vector dimensions based on provider (384 for local, 1024+ for API)\r\n const dims = embeddingDimensions ?? 384;\r\n const schema = embeddingEnabled\r\n ? { ...baseSchema, embedding: `vector[${dims}]` as const }\r\n : baseSchema;\r\n\r\n db = await create({ schema });\r\n\r\n return db;\r\n}\r\n\r\n/**\r\n * Reset the database instance (useful for testing).\r\n */\r\nexport async function resetDb(): Promise<void> {\r\n db = null;\r\n embeddingEnabled = false;\r\n embeddingDimensions = null;\r\n lastSearchModeByProject.clear();\r\n}\r\n\r\n/**\r\n * Check if embedding/vector search is active.\r\n */\r\nexport function isEmbeddingEnabled(): boolean {\r\n return embeddingEnabled;\r\n}\r\n\r\n/**\r\n * Current vector dimensions for the active Orama index.\r\n * Returns null when vector search is disabled for this process.\r\n */\r\nexport function getVectorDimensions(): number | null {\r\n return embeddingEnabled ? embeddingDimensions : null;\r\n}\r\n\r\n/**\r\n * Generate embedding for text content using the available provider.\r\n * Returns null if no provider is available.\r\n */\r\nexport async function generateEmbedding(text: string): Promise<number[] | null> {\r\n const provider = await getEmbeddingProvider();\r\n if (!provider) return null;\r\n return provider.embed(text);\r\n}\r\n\r\n/**\r\n * Batch-generate embeddings for multiple texts.\r\n * Much faster than individual calls — ONNX processes batches of 64 in parallel.\r\n * Returns null entries for texts that fail.\r\n */\r\nexport async function batchGenerateEmbeddings(texts: string[]): Promise<(number[] | null)[]> {\r\n const provider = await getEmbeddingProvider();\r\n if (!provider || texts.length === 0) return texts.map(() => null);\r\n try {\r\n const results = await provider.embedBatch(texts);\r\n return results;\r\n } catch (error) {\r\n console.error(\r\n `[memorix] Batch embedding failed, falling back to null vectors: ${error instanceof Error ? error.message : error}`,\r\n );\r\n return texts.map(() => null);\r\n }\r\n}\r\n\r\n/**\r\n * Hydrate the Orama index from persisted observations.\r\n * Must be called before searching if the index was freshly created (TUI / CLI startup).\r\n * Skips observations already in the index (idempotent).\r\n */\r\nexport async function hydrateIndex(observations: any[]): Promise<number> {\r\n const database = await getDb();\r\n const currentCount = await count(database);\r\n if (currentCount > 0) return 0; // already hydrated\r\n\r\n let inserted = 0;\r\n for (const obs of observations) {\r\n if (!obs || !obs.id || !obs.projectId) continue;\r\n try {\r\n const doc: MemorixDocument = {\r\n id: makeOramaObservationId(obs.projectId, obs.id),\r\n observationId: obs.id,\r\n entityName: obs.entityName || '',\r\n type: obs.type || 'discovery',\r\n title: obs.title || '',\r\n narrative: obs.narrative || '',\r\n facts: Array.isArray(obs.facts) ? obs.facts.join(' ') : '',\r\n filesModified: Array.isArray(obs.filesModified) ? obs.filesModified.join(' ') : '',\r\n concepts: Array.isArray(obs.concepts) ? obs.concepts.join(' ') : '',\r\n tokens: obs.tokens ?? 0,\r\n createdAt: obs.createdAt || '',\r\n projectId: obs.projectId,\r\n accessCount: obs.accessCount ?? 0,\r\n lastAccessedAt: obs.lastAccessedAt || '',\r\n status: obs.status ?? 'active',\r\n source: obs.source || 'agent',\r\n documentType: 'observation',\r\n knowledgeLayer: resolveKnowledgeLayer('observation', obs.sourceDetail, obs.source),\r\n };\r\n await insert(database, doc);\r\n inserted++;\r\n } catch { /* skip malformed entries */ }\r\n }\r\n return inserted;\r\n}\r\n\r\n/**\r\n * Insert an observation document into the store.\r\n */\r\nexport async function insertObservation(doc: MemorixDocument): Promise<void> {\r\n const database = await getDb();\r\n await insert(database, doc);\r\n}\r\n\r\n/**\r\n * Remove an observation document by its Orama internal ID.\r\n */\r\nexport async function removeObservation(oramaId: string): Promise<void> {\r\n const database = await getDb();\r\n await remove(database, oramaId);\r\n}\r\n\r\n/**\r\n * Search observations using Orama full-text search.\r\n * Returns L1 IndexEntry array (compact, ~50-100 tokens per result).\r\n *\r\n * Progressive Disclosure Layer 1 — adopted from claude-mem.\r\n */\r\nexport async function searchObservations(options: SearchOptions): Promise<IndexEntry[]> {\r\n const perf = !!process.env.MEMORIX_PERF;\r\n const t0 = perf ? performance.now() : 0;\r\n const mark = (label: string) => { if (perf) { const now = performance.now(); process.stderr.write(` [search-perf] ${label}: ${(now - t0).toFixed(0)}ms\\n`); } };\r\n const modeKey = options.projectId ?? SEARCH_MODE_DEFAULT_KEY;\r\n lastSearchModeByProject.set(modeKey, embeddingEnabled ? 'hybrid' : 'fulltext');\r\n const database = await getDb();\r\n\r\n // Resolve project aliases — safety net for observations not yet migrated to canonical ID.\r\n // After migration, this is typically a single-element array matching options.projectId.\r\n let projectIds: string[] | null = null;\r\n if (options.projectId) {\r\n try {\r\n const { resolveAliases } = await import('../project/aliases.js');\r\n projectIds = await resolveAliases(options.projectId);\r\n } catch {\r\n projectIds = [options.projectId];\r\n }\r\n }\r\n\r\n const filters: Record<string, unknown> = {};\r\n if (projectIds && projectIds.length === 1) {\r\n filters['projectId'] = projectIds[0];\r\n }\r\n // If multiple aliases exist, we skip the Orama projectId filter and post-filter instead\r\n if (options.type) {\r\n filters['type'] = options.type;\r\n }\r\n if (options.source) {\r\n filters['source'] = options.source;\r\n }\r\n\r\n // Determine search mode: hybrid (with vector) or fulltext (default)\r\n const hasQuery = options.query && options.query.trim().length > 0;\r\n const originalQuery = options.query;\r\n const tier = hasQuery ? classifyQueryTier(originalQuery!) : 'fast' as QueryTier;\r\n mark(`tier=${tier}`);\r\n\r\n // Query expansion: only for heavy-tier (CJK) queries\r\n const expandedEmbeddingQuery = tier === 'heavy' ? await maybeExpandSearchQuery(options.query!) : options.query;\r\n mark('queryExpansion');\r\n\r\n // ── Intent-Aware Recall ──────────────────────────────────────\r\n // Detect query intent (why/when/how/what/problem) and adjust\r\n // field weights and type boosting accordingly.\r\n const intentResult = hasQuery ? detectQueryIntent(originalQuery!) : null;\r\n\r\n // Orama's vector/hybrid search can leak cross-project hits even when `where`\r\n // is present, so always keep enough headroom for a deterministic post-filter.\r\n const requestLimit = projectIds\r\n ? (options.limit ?? 20) * 3\r\n : (options.limit ?? 20);\r\n\r\n // Default field boosts — overridden by intent-specific boosts when detected\r\n const defaultBoost: Record<string, number> = {\r\n title: 3,\r\n entityName: 2,\r\n concepts: 1.5,\r\n narrative: 1,\r\n facts: 1,\r\n filesModified: 0.5,\r\n };\r\n const fieldBoost = (intentResult?.confidence ?? 0) > 0.3 && intentResult?.fieldBoosts\r\n ? intentResult.fieldBoosts\r\n : defaultBoost;\r\n\r\n let searchParams: Record<string, unknown> = {\r\n term: originalQuery,\r\n limit: requestLimit,\r\n ...(Object.keys(filters).length > 0 ? { where: filters } : {}),\r\n // Search specific fields (not tokens, accessCount, etc.)\r\n properties: ['title', 'entityName', 'narrative', 'facts', 'concepts', 'filesModified'],\r\n // Field boosting: intent-aware or default\r\n boost: fieldBoost,\r\n // Fuzzy tolerance: allow 1-char typos for short queries, 2 for longer\r\n ...(hasQuery ? { tolerance: originalQuery!.length > 6 ? 2 : 1 } : {}),\r\n };\r\n\r\n // If embedding provider is available and query tier warrants it, use hybrid search\r\n // Fast-tier queries skip embedding entirely (fulltext is sufficient)\r\n let queryVector: number[] | null = null;\r\n if (embeddingEnabled && hasQuery && tier !== 'fast') {\r\n try {\r\n const provider = await getEmbeddingProvider();\r\n if (provider) {\r\n const activeVectorDimensions = getVectorDimensions();\r\n if (activeVectorDimensions !== null && provider.dimensions !== activeVectorDimensions) {\r\n lastSearchModeByProject.set(\r\n modeKey,\r\n `fulltext (embedding dimension mismatch: provider ${provider.dimensions}d vs index ${activeVectorDimensions}d)`,\r\n );\r\n console.error(\r\n `[memorix] Embedding provider dimension mismatch (${provider.dimensions}d provider vs ${activeVectorDimensions}d index); using fulltext search`,\r\n );\r\n } else {\r\n // Embedding timeout: 15 seconds\r\n const EMBEDDING_TIMEOUT_MS = 15000;\r\n const embedPromise = provider.embed(expandedEmbeddingQuery!);\r\n const timeoutPromise = new Promise<never>((_, reject) =>\r\n setTimeout(() => reject(new Error(`Embedding timeout after ${EMBEDDING_TIMEOUT_MS}ms`)), EMBEDDING_TIMEOUT_MS)\r\n );\r\n queryVector = await Promise.race([embedPromise, timeoutPromise]);\r\n mark('embedding');\r\n // Detect CJK-heavy queries: BM25 can't tokenize Chinese/Japanese/Korean well\r\n const cjkRatio = (originalQuery!.match(/[\\u4e00-\\u9fff\\u3040-\\u309f\\u30a0-\\u30ff\\uac00-\\ud7af]/g) || []).length / originalQuery!.length;\r\n const isCJKHeavy = cjkRatio > 0.3;\r\n lastSearchModeByProject.set(modeKey, 'hybrid');\r\n searchParams = {\r\n ...searchParams,\r\n mode: 'hybrid',\r\n vector: {\r\n value: queryVector,\r\n property: 'embedding',\r\n },\r\n // English paraphrase queries were getting clipped just below 0.5\r\n // even when vector-only search could already find the right memory.\r\n similarity: isCJKHeavy ? 0.3 : NON_CJK_HYBRID_SIMILARITY,\r\n hybridWeights: isCJKHeavy\r\n ? { text: 0.2, vector: 0.8 } // CJK: trust vector over BM25\r\n : { text: 0.6, vector: 0.4 },\r\n };\r\n }\r\n }\r\n } catch (error) {\r\n // Fallback to fulltext if embedding fails or times out\r\n lastSearchModeByProject.set(modeKey, 'fulltext (embedding unavailable)');\r\n console.error('[memorix] Embedding failed or timed out, falling back to fulltext search');\r\n }\r\n }\r\n\r\n mark('preSearch');\r\n let results;\r\n try {\r\n results = await search(database, searchParams);\r\n } catch (error) {\r\n if (queryVector && isVectorDimensionMismatchError(error)) {\r\n lastSearchModeByProject.set(modeKey, 'fulltext (embedding dimension mismatch)');\r\n console.error('[memorix] Vector search dimension mismatch detected, retrying without embeddings');\r\n results = await search(database, stripVectorSearchParams(searchParams));\r\n } else {\r\n throw error;\r\n }\r\n }\r\n mark('oramaSearch');\r\n\r\n // Fallback: if hybrid returned nothing but we have a vector, retry with vector-only\r\n if (results.count === 0 && queryVector && embeddingEnabled) {\r\n try {\r\n const vectorOnlyParams: Record<string, unknown> = {\r\n term: '',\r\n limit: requestLimit,\r\n ...(Object.keys(filters).length > 0 ? { where: filters } : {}),\r\n mode: 'vector',\r\n vector: {\r\n value: queryVector,\r\n property: 'embedding',\r\n },\r\n similarity: 0.25,\r\n };\r\n lastSearchModeByProject.set(modeKey, 'vector-only (hybrid empty fallback)');\r\n results = await search(database, vectorOnlyParams);\r\n } catch {\r\n // Keep original empty results\r\n }\r\n }\r\n\r\n // Status filter: default to 'active' only\r\n const statusFilter = options.status ?? 'active';\r\n\r\n // Build intermediate results with rawTime for temporal filtering\r\n let intermediate = results.hits\r\n // Always post-filter by projectIds. Vector/hybrid search can leak hits even when\r\n // the `where` clause is present, so this keeps project isolation deterministic.\r\n .filter((hit) => {\r\n if (!projectIds) return true;\r\n const doc = hit.document as unknown as MemorixDocument;\r\n return projectIds.includes(doc.projectId);\r\n })\r\n // Post-filter by status (active/resolved/archived)\r\n .filter((hit) => {\r\n if (statusFilter === 'all') return true;\r\n const doc = hit.document as unknown as MemorixDocument;\r\n return (doc.status || 'active') === statusFilter;\r\n })\r\n .map((hit) => {\r\n const doc = hit.document as unknown as MemorixDocument;\r\n const obsType = doc.type as ObservationType;\r\n // Time decay: newer memories get higher boost\r\n const ageMs = Date.now() - new Date(doc.createdAt).getTime();\r\n const DAY = 86_400_000;\r\n let recencyBoost: number;\r\n if (ageMs < 1 * DAY) recencyBoost = 1.0;\r\n else if (ageMs < 7 * DAY) recencyBoost = 0.85;\r\n else if (ageMs < 30 * DAY) recencyBoost = 0.6;\r\n else recencyBoost = 0.35;\r\n\r\n return {\r\n id: doc.observationId,\r\n time: formatTime(doc.createdAt),\r\n rawTime: doc.createdAt,\r\n type: obsType,\r\n icon: OBSERVATION_ICONS[obsType] ?? '[UNKNOWN]',\r\n title: doc.title,\r\n tokens: doc.tokens,\r\n score: (hit.score ?? 1) * recencyBoost,\r\n projectId: doc.projectId,\r\n source: (doc.source || 'agent') as 'agent' | 'git' | 'manual',\r\n sourceDetail: (doc.sourceDetail || undefined) as 'explicit' | 'hook' | 'git-ingest' | undefined,\r\n valueCategory: (doc.valueCategory || undefined) as 'core' | 'contextual' | 'ephemeral' | undefined,\r\n entityName: doc.entityName || undefined,\r\n documentType: (doc.documentType || 'observation') as 'observation' | 'mini-skill',\r\n knowledgeLayer: (doc.knowledgeLayer || 'project-truth') as KnowledgeLayer,\r\n _isCommandLog: isCommandLogEntry(doc.title),\r\n };\r\n });\r\n\r\n // ── Knowledge-Layer Boost (Phase 3a, step 3) ─────────────────\r\n // Explicit layer-aware ranking: promoted knowledge gets a mild boost\r\n // for general queries, evidence gets a boost for evidence-seeking queries.\r\n // This is the dedicated layer signal — NOT borrowed from valueCategory.\r\n {\r\n const isEvidenceSeeking = intentResult?.intent === 'what_changed' ||\r\n (hasQuery && /\\b(evidence|verify|proof|git|commit)\\b/i.test(originalQuery!));\r\n const layerBoosts: Record<string, number> = isEvidenceSeeking\r\n ? { promoted: 1.10, 'project-truth': 1.00, evidence: 1.15 }\r\n : { promoted: 1.20, 'project-truth': 1.00, evidence: 0.90 };\r\n intermediate = intermediate.map(entry => ({\r\n ...entry,\r\n score: entry.score * (layerBoosts[(entry as any).knowledgeLayer] ?? 1.0),\r\n }));\r\n }\r\n\r\n // ── Intent-Aware Type Boosting ───────────────────────────────\r\n // Boost scores for observation types that match the query intent\r\n if (intentResult && intentResult.confidence > 0.3) {\r\n intermediate = intermediate.map(entry => ({\r\n ...entry,\r\n score: applyIntentBoost(entry.score, entry.type, intentResult),\r\n }));\r\n }\r\n\r\n // ── Source-Aware Retrieval ─────────────────────────────────────\r\n // Boost scores based on memory source matching query intent.\r\n // e.g., \"what changed\" queries boost git-derived memories,\r\n // \"why\" queries boost agent-authored reasoning memories.\r\n if (intentResult && intentResult.confidence > 0.3 && intentResult.sourceBoosts) {\r\n const srcBoosts = intentResult.sourceBoosts;\r\n intermediate = intermediate.map(entry => {\r\n const boost = srcBoosts[effectiveSource(entry.source, entry.sourceDetail)] ?? 1.0;\r\n const effectiveBoost = 1 + (boost - 1) * intentResult.confidence;\r\n return { ...entry, score: entry.score * effectiveBoost };\r\n });\r\n }\r\n\r\n // ── Command-log noise suppression (two-pass) ────────────────\r\n // 73% of observations are Ran:/Command:/Executed: hook logs. When the query\r\n // is NOT command-like, we first try excluding them entirely. If that would\r\n // leave 0 real results (the query only matched command logs), we fall back to\r\n // keeping them with a very aggressive 0.05x demotion so SOMETHING is returned\r\n // but noise never dominates when real results exist.\r\n if (hasQuery && !isCommandLikeQuery(originalQuery!)) {\r\n const nonCommandEntries = intermediate.filter(e => !(e as any)._isCommandLog);\r\n if (nonCommandEntries.length > 0) {\r\n // Enough real results — drop command logs entirely\r\n intermediate = nonCommandEntries;\r\n } else {\r\n // Only command logs matched — keep them but demote heavily\r\n intermediate = intermediate.map(entry => ({\r\n ...entry,\r\n score: (entry as any)._isCommandLog ? entry.score * 0.05 : entry.score,\r\n }));\r\n }\r\n // Also soft-demote shell-specific patterns in remaining results\r\n intermediate = intermediate.map(entry => ({\r\n ...entry,\r\n score: isCommandStyleEntry(entry.title) ? entry.score * 0.3 : entry.score,\r\n }));\r\n }\r\n\r\n // Re-sort: chronological for WHEN queries, relevance for others\r\n if (intentResult?.preferChronological) {\r\n intermediate.sort((a, b) => new Date(b.rawTime).getTime() - new Date(a.rawTime).getTime());\r\n } else {\r\n intermediate.sort((a, b) => b.score - a.score);\r\n }\r\n\r\n // ─── Project Affinity Scoring (mcp-memory-service style) ───\r\n // Penalize memories that don't reference the current project to prevent\r\n // cross-project pollution (e.g., discussing Memorix in a test project workspace)\r\n if (options.projectId && intermediate.length > 0) {\r\n const projectName = options.projectId.split('/').pop() ?? options.projectId;\r\n const affinityContext: AffinityContext = {\r\n projectName,\r\n projectId: options.projectId,\r\n projectKeywords: extractProjectKeywords(projectName, options.projectId),\r\n };\r\n\r\n // Build a map of memory content for affinity calculation\r\n const memoryContentMap = new Map<number, MemoryContent>();\r\n for (const hit of results.hits) {\r\n const doc = hit.document as unknown as MemorixDocument;\r\n memoryContentMap.set(doc.observationId, {\r\n title: doc.title,\r\n narrative: doc.narrative,\r\n facts: doc.facts?.split?.('\\n') ?? (Array.isArray(doc.facts) ? doc.facts : []),\r\n concepts: doc.concepts?.split?.('\\n') ?? (Array.isArray(doc.concepts) ? doc.concepts : []),\r\n entityName: doc.entityName,\r\n filesModified: doc.filesModified?.split?.('\\n') ?? (Array.isArray(doc.filesModified) ? doc.filesModified : []),\r\n });\r\n }\r\n\r\n // Apply affinity scoring to each result\r\n intermediate = intermediate.map(entry => {\r\n const memory = memoryContentMap.get(entry.id);\r\n if (!memory) return entry;\r\n\r\n const { score: affinityScore } = calculateProjectAffinity(memory, affinityContext);\r\n return {\r\n ...entry,\r\n score: entry.score * affinityScore, // Apply affinity as multiplier\r\n };\r\n });\r\n\r\n // Re-sort after affinity adjustment\r\n intermediate.sort((a, b) => b.score - a.score);\r\n }\r\n\r\n // Temporal filtering: since/until date range\r\n if (options.since) {\r\n const sinceDate = new Date(options.since).getTime();\r\n intermediate = intermediate.filter(e => new Date(e.rawTime).getTime() >= sinceDate);\r\n }\r\n if (options.until) {\r\n const untilDate = new Date(options.until).getTime();\r\n intermediate = intermediate.filter(e => new Date(e.rawTime).getTime() <= untilDate);\r\n }\r\n\r\n // Apply original limit after post-filtering (we intentionally over-requested when project filtering is active)\r\n if (projectIds) {\r\n intermediate = intermediate.slice(0, options.limit ?? 20);\r\n }\r\n\r\n // ── Provenance Tiebreaker (standard tier only) ──────────────────\r\n // When Orama scores converge — a common outcome in standard-tier queries\r\n // where both fulltext and embedding are used — this pass gives a tiny\r\n // preference to repository-backed and core memories within the top-K\r\n // results whose scores fall within a 20% window of the highest score.\r\n // Amplitudes are intentionally small: the tiebreaker must never reverse\r\n // a meaningful score gap, only resolve genuine ambiguity.\r\n // git-ingest / source=git → ×1.06 (repository evidence)\r\n // valueCategory=core → ×1.03 (explicitly classified durable memory)\r\n // Constraints:\r\n // - Standard tier only (fast has no ambiguity; heavy has LLM rerank)\r\n // - Top-8 results only (doesn't affect long tail)\r\n // - 20% score window from top score (score ≥ topScore × 0.80)\r\n if (tier === 'standard' && intermediate.length > 1) {\r\n const TIEBREAK_TOP_K = 8;\r\n const TIEBREAK_WINDOW = 0.20;\r\n const topScore = intermediate[0]?.score ?? 0;\r\n const threshold = topScore * (1 - TIEBREAK_WINDOW);\r\n let changed = false;\r\n for (let i = 0; i < Math.min(TIEBREAK_TOP_K, intermediate.length); i++) {\r\n const entry = intermediate[i];\r\n if (entry.score < threshold) break; // outside tiebreak window, stop\r\n const isGitEvidence = effectiveSource(entry.source, entry.sourceDetail) === 'git';\r\n const isCore = entry.valueCategory === 'core';\r\n if (isGitEvidence) {\r\n intermediate[i] = { ...entry, score: entry.score * 1.06 };\r\n changed = true;\r\n } else if (isCore) {\r\n intermediate[i] = { ...entry, score: entry.score * 1.03 };\r\n changed = true;\r\n }\r\n }\r\n if (changed) intermediate.sort((a, b) => b.score - a.score);\r\n }\r\n\r\n // ── Entity-affinity hint (standard + heavy tier only) ──────────────\r\n // When query tokens (4+ chars) match some entity names in results but not\r\n // others, mildly boost the matching entities (×1.08). This helps queries\r\n // like \"blog VPS deployment\" surface blog-vps observations over api-relay\r\n // observations stored in the same project bucket.\r\n // Gates:\r\n // - standard or heavy tier only (fast tier is single-word, too noisy)\r\n // - only fires when some but not all entity names match the query\r\n // - top-8 and within the 20% window of the top score\r\n // - cannot reverse a meaningful score gap (amplitude ×1.08)\r\n if ((tier === 'standard' || tier === 'heavy') && intermediate.length > 1 && hasQuery) {\r\n const affTokens = originalQuery!\r\n .toLowerCase()\r\n .split(/\\s+/)\r\n .map(t => t.replace(/[_-]/g, ''))\r\n .filter(t => t.length >= 4);\r\n\r\n if (affTokens.length > 0) {\r\n const entityNames = [...new Set(intermediate.map(e => e.entityName).filter((n): n is string => !!n))];\r\n const matchedEntities = new Set(\r\n entityNames.filter(name => {\r\n const norm = name.toLowerCase().replace(/[_-]/g, '');\r\n return affTokens.some(t => norm.includes(t));\r\n }),\r\n );\r\n\r\n if (matchedEntities.size > 0 && matchedEntities.size < entityNames.length) {\r\n const AFF_TOP_K = 8;\r\n const AFF_WINDOW = 0.20;\r\n const AFF_BOOST = 1.08;\r\n const topScore = intermediate[0]?.score ?? 0;\r\n const threshold = topScore * (1 - AFF_WINDOW);\r\n let affChanged = false;\r\n for (let i = 0; i < Math.min(AFF_TOP_K, intermediate.length); i++) {\r\n const entry = intermediate[i];\r\n if (entry.score < threshold) break;\r\n if (matchedEntities.has(entry.entityName ?? '')) {\r\n intermediate[i] = { ...entry, score: entry.score * AFF_BOOST };\r\n affChanged = true;\r\n }\r\n }\r\n if (affChanged) intermediate.sort((a, b) => b.score - a.score);\r\n }\r\n }\r\n }\r\n\r\n // ── LLM Reranking (heavy-tier only) ────────────────────────────\r\n // Only triggered for heavy-tier queries with ambiguous top results.\r\n // Fast and standard tiers skip entirely.\r\n // Ambiguity check: top-2 scores within 30% → results are uncertain.\r\n const shouldRerank = tier === 'heavy'\r\n && hasQuery\r\n && intermediate.length > 2\r\n && (() => {\r\n const top = intermediate[0]?.score ?? 0;\r\n const second = intermediate[1]?.score ?? 0;\r\n return top > 0 && second / top > 0.7; // top-2 within 30% = ambiguous\r\n })();\r\n\r\n if (shouldRerank) {\r\n try {\r\n const { rerankResults } = await import('../llm/quality.js');\r\n const narrativeMap = new Map<string, string>();\r\n for (const hit of results.hits) {\r\n const doc = hit.document as unknown as MemorixDocument;\r\n narrativeMap.set(makeEntryKey(doc.projectId, doc.observationId), doc.narrative);\r\n }\r\n // Rerank only top-5 (was 10) to save LLM tokens and latency\r\n const RERANK_TOP_K = 5;\r\n const toRerank = intermediate.slice(0, RERANK_TOP_K);\r\n const candidates = toRerank.map((e, index) => ({\r\n id: `r${index + 1}`,\r\n title: e.title,\r\n type: e.type,\r\n score: e.score,\r\n narrative: narrativeMap.get(makeEntryKey(e.projectId, e.id)),\r\n }));\r\n \r\n // LLM rerank timeout: configurable via MEMORIX_RERANK_TIMEOUT_MS, default 5s\r\n const _parsedRerank = parseInt(process.env.MEMORIX_RERANK_TIMEOUT_MS || '', 10);\r\n const RERANK_TIMEOUT_MS = Number.isFinite(_parsedRerank) && _parsedRerank > 0 ? _parsedRerank : 5000;\r\n const rerankPromise = rerankResults(originalQuery!, candidates);\r\n const timeoutPromise = new Promise<never>((_, reject) =>\r\n setTimeout(() => reject(new Error(`LLM rerank timeout after ${RERANK_TIMEOUT_MS}ms`)), RERANK_TIMEOUT_MS)\r\n );\r\n const { reranked, usedLLM } = await Promise.race([rerankPromise, timeoutPromise]);\r\n mark(`rerank(usedLLM=${usedLLM})`);\r\n \r\n if (usedLLM) {\r\n lastSearchModeByProject.set(modeKey, (lastSearchModeByProject.get(modeKey) ?? 'fulltext') + ' + LLM rerank');\r\n const candidateMap = new Map(candidates.map((candidate, index) => [candidate.id, toRerank[index]]));\r\n const rerankedTop = reranked\r\n .map(r => candidateMap.get(r.id))\r\n .filter((e): e is NonNullable<typeof e> => e != null);\r\n if (rerankedTop.length > 0) {\r\n intermediate = [...rerankedTop, ...intermediate.slice(RERANK_TOP_K)];\r\n }\r\n }\r\n } catch (error) {\r\n // Reranking is best-effort: fall back to original order on timeout or error\r\n console.error('[memorix] LLM rerank failed or timed out, using original order');\r\n }\r\n } else {\r\n mark(`rerank(skipped,tier=${tier})`);\r\n }\r\n\r\n // Build IndexEntry with optional match explanation\r\n let entries: IndexEntry[] = intermediate.map(({ rawTime: _, _isCommandLog: _c, ...rest }: any) => rest);\r\n\r\n // Explainable recall: annotate entries with match reasons (O(1) lookup via Map)\r\n if (hasQuery && originalQuery) {\r\n const queryLower = originalQuery.toLowerCase();\r\n const queryTokens = queryLower.split(/\\s+/).filter(t => t.length > 1);\r\n const entryMap = new Map(entries.map(e => [makeEntryKey(e.projectId, e.id), e]));\r\n for (const hit of results.hits) {\r\n const doc = hit.document as unknown as MemorixDocument;\r\n const entry = entryMap.get(makeEntryKey(doc.projectId, doc.observationId));\r\n if (!entry) continue;\r\n\r\n const reasons: string[] = [];\r\n const fields: [string, string][] = [\r\n ['title', doc.title], ['entity', doc.entityName], ['concept', doc.concepts],\r\n ['narrative', doc.narrative], ['fact', doc.facts], ['file', doc.filesModified],\r\n ];\r\n for (const [name, value] of fields) {\r\n const valueLower = value.toLowerCase();\r\n if (queryTokens.some(t => valueLower.includes(t))) reasons.push(name);\r\n }\r\n if (reasons.length === 0) reasons.push('fuzzy');\r\n\r\n // Prepend a single evidence-type tag (max 1) ahead of field-match labels.\r\n // Priority: git evidence > synthesized > core core\r\n // This surfaces WHY this result is notable beyond the query match.\r\n const isGitEvidence = doc.sourceDetail === 'git-ingest' || doc.source === 'git';\r\n const isSynthesized = doc.sourceDetail === 'explicit' &&\r\n // Note: relatedCommits not in MemorixDocument; flag is best-effort from sourceDetail alone.\r\n // Full synthesized detection is handled in the detail/timeline path where we have the full obs.\r\n false; // reserved — set explicitly if MemorixDocument gains relatedCommits in future\r\n const isCore = doc.valueCategory === 'core';\r\n\r\n if (isGitEvidence) {\r\n entry.matchedFields = ['git evidence', ...reasons];\r\n } else if (isSynthesized) {\r\n entry.matchedFields = ['synthesized', ...reasons];\r\n } else if (isCore) {\r\n entry.matchedFields = ['core core', ...reasons];\r\n } else {\r\n entry.matchedFields = reasons;\r\n }\r\n }\r\n }\r\n\r\n // Apply token budget if specified (inspired by MemCP)\r\n if (options.maxTokens && options.maxTokens > 0) {\r\n entries = applyTokenBudget(entries, options.maxTokens);\r\n }\r\n\r\n // Record access for returned results (fire-and-forget, non-blocking)\r\n const hitDocs = results.hits.map((h) => ({ id: h.id, doc: h.document as unknown as MemorixDocument }));\r\n recordAccessBatch(hitDocs).catch(() => {});\r\n\r\n return entries;\r\n}\r\n\r\n/**\r\n * Get full observation documents by their observation IDs.\r\n *\r\n * Progressive Disclosure Layer 3 — adopted from claude-mem.\r\n */\r\nexport async function getObservationsByIds(\r\n ids: number[],\r\n projectId?: string,\r\n): Promise<MemorixDocument[]> {\r\n const database = await getDb();\r\n\r\n // Search for each ID individually and collect results\r\n const results: MemorixDocument[] = [];\r\n\r\n for (const id of ids) {\r\n const searchResult = await search(database, {\r\n term: '',\r\n where: {\r\n observationId: { eq: id },\r\n ...(projectId ? { projectId } : {}),\r\n },\r\n limit: 1,\r\n });\r\n\r\n if (searchResult.hits.length > 0) {\r\n results.push(searchResult.hits[0].document as unknown as MemorixDocument);\r\n }\r\n }\r\n\r\n return results;\r\n}\r\n\r\n/**\r\n * Get observations around an anchor for timeline context.\r\n *\r\n * Progressive Disclosure Layer 2 — adopted from claude-mem.\r\n */\r\nexport async function getTimeline(\r\n anchorId: number,\r\n projectId?: string,\r\n depthBefore = 3,\r\n depthAfter = 3,\r\n): Promise<{ before: IndexEntry[]; anchor: IndexEntry | null; after: IndexEntry[] }> {\r\n // Use in-memory observations for reliable lookup\r\n // (Orama search with empty term is unreliable — same fix as compactDetail)\r\n const { withFreshIndex } = await import('../memory/freshness.js');\r\n const { getAllObservations } = await import('../memory/observations.js');\r\n const rawObs = await withFreshIndex(() => getAllObservations());\r\n\r\n // Filter by project if specified — prevents cross-project context leaking\r\n const allObs = projectId\r\n ? rawObs.filter((o) => o.projectId === projectId)\r\n : rawObs;\r\n\r\n // Sort by creation time\r\n const sorted = allObs.sort((a, b) => a.createdAt.localeCompare(b.createdAt));\r\n\r\n const anchorIndex = sorted.findIndex((o) => o.id === anchorId);\r\n if (anchorIndex === -1) {\r\n return { before: [], anchor: null, after: [] };\r\n }\r\n\r\n const toIndexEntry = (obs: {\r\n id: number; type: string; title: string; tokens: number; createdAt: string;\r\n source?: string; sourceDetail?: string; valueCategory?: string;\r\n }): IndexEntry => {\r\n const obsType = obs.type as ObservationType;\r\n return {\r\n id: obs.id,\r\n time: formatTime(obs.createdAt),\r\n type: obsType,\r\n icon: OBSERVATION_ICONS[obsType] ?? '[UNKNOWN]',\r\n title: obs.title,\r\n tokens: obs.tokens,\r\n source: (obs.source as IndexEntry['source']) || undefined,\r\n sourceDetail: (obs.sourceDetail as IndexEntry['sourceDetail']) || undefined,\r\n valueCategory: (obs.valueCategory as IndexEntry['valueCategory']) || undefined,\r\n };\r\n };\r\n\r\n const before = sorted\r\n .slice(Math.max(0, anchorIndex - depthBefore), anchorIndex)\r\n .map(toIndexEntry);\r\n\r\n const after = sorted\r\n .slice(anchorIndex + 1, anchorIndex + 1 + depthAfter)\r\n .map(toIndexEntry);\r\n\r\n return {\r\n before,\r\n anchor: toIndexEntry(sorted[anchorIndex]),\r\n after,\r\n };\r\n}\r\n\r\n/**\r\n * Record access for observations returned in search results.\r\n * Increments accessCount and updates lastAccessedAt.\r\n * Inspired by mcp-memory-service's record_access() pattern.\r\n */\r\nasync function recordAccessBatch(hitDocs: { id: string; doc: MemorixDocument }[]): Promise<void> {\r\n const database = await getDb();\r\n const now = new Date().toISOString();\r\n\r\n for (const { id, doc } of hitDocs) {\r\n try {\r\n // Use update() directly — no need to re-search since we already have the doc\r\n await update(database, id, {\r\n ...doc,\r\n accessCount: (doc.accessCount ?? 0) + 1,\r\n lastAccessedAt: now,\r\n });\r\n } catch {\r\n // Best-effort — don't break search if access tracking fails\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Trim search results to fit within a token budget.\r\n * Inspired by MemCP's _apply_token_budget() pattern.\r\n */\r\nfunction applyTokenBudget(entries: IndexEntry[], maxTokens: number): IndexEntry[] {\r\n const budgeted: IndexEntry[] = [];\r\n let tokensUsed = 0;\r\n\r\n for (const entry of entries) {\r\n if (tokensUsed + entry.tokens > maxTokens && budgeted.length > 0) {\r\n break;\r\n }\r\n budgeted.push(entry);\r\n tokensUsed += entry.tokens;\r\n }\r\n\r\n return budgeted;\r\n}\r\n\r\n/**\r\n * Get total observation count, optionally filtered by project.\r\n */\r\nexport async function getObservationCount(projectId?: string): Promise<number> {\r\n const database = await getDb();\r\n if (!projectId) {\r\n return await count(database);\r\n }\r\n const results = await search(database, {\r\n term: '',\r\n where: { projectId },\r\n limit: 0,\r\n });\r\n return results.count;\r\n}\r\n\r\n/**\r\n * Format ISO date string to compact time display.\r\n */\r\nfunction formatTime(isoDate: string): string {\r\n try {\r\n const date = new Date(isoDate);\r\n return date.toLocaleTimeString('en-US', {\r\n hour: 'numeric',\r\n minute: '2-digit',\r\n hour12: true,\r\n });\r\n } catch {\r\n return isoDate;\r\n }\r\n}\r\n","/**\r\n * SqliteBackend — ObservationStore implementation backed by better-sqlite3.\r\n *\r\n * Features:\r\n * - WAL mode for concurrent read performance\r\n * - storage_generation counter for cross-process freshness detection\r\n * - next_id counter in meta table (replaces counter.json)\r\n * - One-time migration from observations.json on first init\r\n * - Dynamic require of better-sqlite3 (optionalDependencies)\r\n *\r\n * Array fields (facts, filesModified, concepts, relatedCommits, relatedEntities)\r\n * are stored as JSON strings in SQLite columns.\r\n *\r\n * Uses the shared database handle from sqlite-db.ts so that observations,\r\n * mini-skills, and sessions all share one connection and one DB file.\r\n */\r\n\r\nimport type { Observation } from '../types.js';\r\nimport type { ObservationStore, StoreTransaction } from './obs-store.js';\r\nimport { getDatabase, closeDatabase } from './sqlite-db.js';\r\nimport path from 'node:path';\r\nimport fs from 'node:fs';\r\n\r\n// ── Row ↔ Observation serialization ────────────────────────────────\r\n\r\nfunction obsToRow(obs: Observation): Record<string, unknown> {\r\n return {\r\n id: obs.id,\r\n entityName: obs.entityName,\r\n type: obs.type,\r\n title: obs.title,\r\n narrative: obs.narrative,\r\n facts: JSON.stringify(obs.facts ?? []),\r\n filesModified: JSON.stringify(obs.filesModified ?? []),\r\n concepts: JSON.stringify(obs.concepts ?? []),\r\n tokens: obs.tokens ?? 0,\r\n createdAt: obs.createdAt,\r\n updatedAt: obs.updatedAt ?? null,\r\n projectId: obs.projectId,\r\n hasCausalLanguage: obs.hasCausalLanguage ? 1 : 0,\r\n topicKey: obs.topicKey ?? null,\r\n revisionCount: obs.revisionCount ?? 1,\r\n sessionId: obs.sessionId ?? null,\r\n status: obs.status ?? 'active',\r\n progress: obs.progress ? JSON.stringify(obs.progress) : null,\r\n source: obs.source ?? 'agent',\r\n commitHash: obs.commitHash ?? null,\r\n relatedCommits: obs.relatedCommits ? JSON.stringify(obs.relatedCommits) : null,\r\n relatedEntities: obs.relatedEntities ? JSON.stringify(obs.relatedEntities) : null,\r\n sourceDetail: obs.sourceDetail ?? null,\r\n valueCategory: obs.valueCategory ?? null,\r\n createdByAgentId: obs.createdByAgentId ?? null,\r\n writeGeneration: obs.writeGeneration ?? 0,\r\n };\r\n}\r\n\r\nfunction rowToObs(row: any): Observation {\r\n return {\r\n id: row.id,\r\n entityName: row.entityName,\r\n type: row.type,\r\n title: row.title,\r\n narrative: row.narrative,\r\n facts: safeJsonParse(row.facts, []),\r\n filesModified: safeJsonParse(row.filesModified, []),\r\n concepts: safeJsonParse(row.concepts, []),\r\n tokens: row.tokens,\r\n createdAt: row.createdAt,\r\n ...(row.updatedAt ? { updatedAt: row.updatedAt } : {}),\r\n projectId: row.projectId,\r\n hasCausalLanguage: !!row.hasCausalLanguage,\r\n ...(row.topicKey ? { topicKey: row.topicKey } : {}),\r\n revisionCount: row.revisionCount ?? 1,\r\n ...(row.sessionId ? { sessionId: row.sessionId } : {}),\r\n status: row.status ?? 'active',\r\n ...(row.progress ? { progress: safeJsonParse(row.progress, undefined) } : {}),\r\n ...(row.source ? { source: row.source } : {}),\r\n ...(row.commitHash ? { commitHash: row.commitHash } : {}),\r\n ...(row.relatedCommits ? { relatedCommits: safeJsonParse(row.relatedCommits, []) } : {}),\r\n ...(row.relatedEntities ? { relatedEntities: safeJsonParse(row.relatedEntities, []) } : {}),\r\n ...(row.sourceDetail ? { sourceDetail: row.sourceDetail } : {}),\r\n ...(row.valueCategory ? { valueCategory: row.valueCategory } : {}),\r\n ...(row.createdByAgentId ? { createdByAgentId: row.createdByAgentId } : {}),\r\n ...(row.writeGeneration ? { writeGeneration: row.writeGeneration } : {}),\r\n } as Observation;\r\n}\r\n\r\nfunction safeJsonParse(val: string | null | undefined, fallback: any): any {\r\n if (val == null || val === '') return fallback;\r\n try { return JSON.parse(val); } catch { return fallback; }\r\n}\r\n\r\n// ── SqliteBackend ──────────────────────────────────────────────────\r\n\r\nexport class SqliteBackend implements ObservationStore {\r\n private db: any = null;\r\n private dataDir: string = '';\r\n private knownGeneration: number = 0;\r\n\r\n // Async mutex for serializing atomic() calls on the single connection\r\n private _atomicQueue: Promise<unknown> = Promise.resolve();\r\n\r\n // Prepared statements (lazy-initialized after db open)\r\n private stmtInsert: any = null;\r\n private stmtUpdate: any = null;\r\n private stmtDelete: any = null;\r\n private stmtSelectAll: any = null;\r\n private stmtSelectGeneration: any = null;\r\n private stmtBumpGeneration: any = null;\r\n private stmtGetMeta: any = null;\r\n private stmtSetMeta: any = null;\r\n\r\n async init(dataDir: string): Promise<void> {\r\n this.dataDir = dataDir;\r\n\r\n // Use shared database handle (opens DB, creates all tables, sets pragmas)\r\n this.db = getDatabase(dataDir);\r\n\r\n // Prepare statements\r\n this.stmtInsert = this.db.prepare(`\r\n INSERT OR REPLACE INTO observations\r\n (id, entityName, type, title, narrative, facts, filesModified, concepts, tokens,\r\n createdAt, updatedAt, projectId, hasCausalLanguage, topicKey, revisionCount,\r\n sessionId, status, progress, source, commitHash, relatedCommits, relatedEntities,\r\n sourceDetail, valueCategory, createdByAgentId, writeGeneration)\r\n VALUES\r\n (@id, @entityName, @type, @title, @narrative, @facts, @filesModified, @concepts, @tokens,\r\n @createdAt, @updatedAt, @projectId, @hasCausalLanguage, @topicKey, @revisionCount,\r\n @sessionId, @status, @progress, @source, @commitHash, @relatedCommits, @relatedEntities,\r\n @sourceDetail, @valueCategory, @createdByAgentId, @writeGeneration)\r\n `);\r\n this.stmtUpdate = this.stmtInsert; // INSERT OR REPLACE works for both\r\n this.stmtDelete = this.db.prepare(`DELETE FROM observations WHERE id = ?`);\r\n this.stmtSelectAll = this.db.prepare(`SELECT * FROM observations`);\r\n this.stmtSelectGeneration = this.db.prepare(`SELECT value FROM meta WHERE key = 'storage_generation'`);\r\n this.stmtBumpGeneration = this.db.prepare(`UPDATE meta SET value = CAST(CAST(value AS INTEGER) + 1 AS TEXT) WHERE key = 'storage_generation'`);\r\n this.stmtGetMeta = this.db.prepare(`SELECT value FROM meta WHERE key = ?`);\r\n this.stmtSetMeta = this.db.prepare(`INSERT OR REPLACE INTO meta (key, value) VALUES (?, ?)`);\r\n\r\n // Read initial generation\r\n this.knownGeneration = this.readGeneration();\r\n\r\n // Migration: if observations table is empty but observations.json exists, import\r\n await this.migrateFromJsonIfNeeded();\r\n }\r\n\r\n // ── Internal helpers ─────────────────────────────────────────────\r\n\r\n private readGeneration(): number {\r\n const row = this.stmtSelectGeneration.get();\r\n return row ? parseInt(row.value, 10) : 0;\r\n }\r\n\r\n private bumpGeneration(): void {\r\n this.stmtBumpGeneration.run();\r\n this.knownGeneration = this.readGeneration();\r\n }\r\n\r\n private rawLoadAll(): Observation[] {\r\n const rows = this.stmtSelectAll.all();\r\n return rows.map(rowToObs);\r\n }\r\n\r\n private rawLoadIdCounter(): number {\r\n const row = this.stmtGetMeta.get('next_id');\r\n return row ? parseInt(row.value, 10) : 1;\r\n }\r\n\r\n private rawSaveIdCounter(nextId: number): void {\r\n this.stmtSetMeta.run('next_id', String(nextId));\r\n }\r\n\r\n // ── Migration ────────────────────────────────────────────────────\r\n\r\n private async migrateFromJsonIfNeeded(): Promise<void> {\r\n // Only migrate if table is empty\r\n const count = this.db.prepare(`SELECT COUNT(*) AS cnt FROM observations`).get();\r\n if (count.cnt > 0) return;\r\n\r\n const jsonPath = path.join(this.dataDir, 'observations.json');\r\n if (!fs.existsSync(jsonPath)) return;\r\n\r\n try {\r\n const raw = fs.readFileSync(jsonPath, 'utf-8');\r\n const observations: Observation[] = JSON.parse(raw);\r\n\r\n if (observations.length === 0) return;\r\n\r\n console.error(`[memorix] Migrating ${observations.length} observations from JSON to SQLite...`);\r\n\r\n const insertMany = this.db.transaction((obsList: Observation[]) => {\r\n for (const obs of obsList) {\r\n this.stmtInsert.run(obsToRow(obs));\r\n }\r\n });\r\n insertMany(observations);\r\n\r\n // Migrate counter\r\n const counterPath = path.join(this.dataDir, 'counter.json');\r\n if (fs.existsSync(counterPath)) {\r\n try {\r\n const counterData = JSON.parse(fs.readFileSync(counterPath, 'utf-8'));\r\n const nextId = counterData.nextId ?? counterData.next_id ?? (Math.max(...observations.map(o => o.id)) + 1);\r\n this.rawSaveIdCounter(nextId);\r\n } catch {\r\n // Fallback: derive from max observation ID\r\n this.rawSaveIdCounter(Math.max(...observations.map(o => o.id)) + 1);\r\n }\r\n } else {\r\n this.rawSaveIdCounter(Math.max(...observations.map(o => o.id)) + 1);\r\n }\r\n\r\n this.bumpGeneration();\r\n\r\n console.error(`[memorix] Migration complete. ${observations.length} observations now in SQLite.`);\r\n } catch (err) {\r\n console.error(`[memorix] JSON→SQLite migration failed (non-fatal, data preserved in JSON): ${err}`);\r\n }\r\n }\r\n\r\n // ── Public read ──────────────────────────────────────────────────\r\n\r\n async loadAll(): Promise<Observation[]> {\r\n return this.rawLoadAll();\r\n }\r\n\r\n async loadIdCounter(): Promise<number> {\r\n return this.rawLoadIdCounter();\r\n }\r\n\r\n // ── Public write (each bumps generation) ─────────────────────────\r\n\r\n async insert(obs: Observation): Promise<void> {\r\n this.stmtInsert.run(obsToRow(obs));\r\n this.bumpGeneration();\r\n }\r\n\r\n async update(obs: Observation): Promise<void> {\r\n this.stmtUpdate.run(obsToRow(obs));\r\n this.bumpGeneration();\r\n }\r\n\r\n async remove(id: number): Promise<void> {\r\n this.stmtDelete.run(id);\r\n this.bumpGeneration();\r\n }\r\n\r\n async bulkReplace(obs: Observation[]): Promise<void> {\r\n const run = this.db.transaction((obsList: Observation[]) => {\r\n this.db.prepare(`DELETE FROM observations`).run();\r\n for (const o of obsList) {\r\n this.stmtInsert.run(obsToRow(o));\r\n }\r\n });\r\n run(obs);\r\n this.bumpGeneration();\r\n }\r\n\r\n async bulkRemoveByIds(ids: number[]): Promise<void> {\r\n if (ids.length === 0) return;\r\n const run = this.db.transaction((idList: number[]) => {\r\n const stmt = this.db.prepare(`DELETE FROM observations WHERE id = ?`);\r\n for (const id of idList) {\r\n stmt.run(id);\r\n }\r\n });\r\n run(ids);\r\n this.bumpGeneration();\r\n }\r\n\r\n async saveIdCounter(nextId: number): Promise<void> {\r\n this.rawSaveIdCounter(nextId);\r\n }\r\n\r\n // ── Compound atomic operation ────────────────────────────────────\r\n\r\n async atomic<T>(fn: (tx: StoreTransaction) => Promise<T>): Promise<T> {\r\n // Serialize concurrent atomic() calls via an async queue.\r\n // better-sqlite3 is single-connection; nested BEGIN is illegal.\r\n const run = this._atomicQueue\r\n .catch(() => undefined)\r\n .then(async () => {\r\n this.db.prepare('BEGIN IMMEDIATE').run();\r\n try {\r\n const tx: StoreTransaction = {\r\n loadAll: async () => this.rawLoadAll(),\r\n loadIdCounter: async () => this.rawLoadIdCounter(),\r\n saveAll: async (obs) => {\r\n this.db.prepare(`DELETE FROM observations`).run();\r\n for (const o of obs) {\r\n this.stmtInsert.run(obsToRow(o));\r\n }\r\n },\r\n saveIdCounter: async (nextId) => this.rawSaveIdCounter(nextId),\r\n };\r\n const result = await fn(tx);\r\n this.bumpGeneration();\r\n this.db.prepare('COMMIT').run();\r\n return result;\r\n } catch (err) {\r\n try { this.db.prepare('ROLLBACK').run(); } catch { /* already rolled back */ }\r\n throw err;\r\n }\r\n });\r\n\r\n // Keep the queue alive after failures so one bad transaction does not poison\r\n // all future atomic() calls.\r\n this._atomicQueue = run.catch(() => undefined);\r\n return run;\r\n }\r\n\r\n // ── Freshness ────────────────────────────────────────────────────\r\n\r\n async ensureFresh(): Promise<boolean> {\r\n const remoteGen = this.readGeneration();\r\n if (remoteGen > this.knownGeneration) {\r\n this.knownGeneration = remoteGen;\r\n return true; // caller should reload observations[] + rebuild Orama\r\n }\r\n return false;\r\n }\r\n\r\n getGeneration(): number {\r\n return this.knownGeneration;\r\n }\r\n\r\n // ── Diagnostics ──────────────────────────────────────────────────\r\n\r\n close(): void {\r\n // Detach from the shared handle without closing it — other stores\r\n // (MiniSkillSqliteStore, SessionSqliteStore) may still be using it.\r\n // Use closeDatabase(dataDir) or closeAllDatabases() for full shutdown.\r\n this.db = null;\r\n }\r\n\r\n getBackendName(): 'sqlite' | 'degraded' {\r\n return 'sqlite';\r\n }\r\n}\r\n","/**\r\n * ObservationStore — unified persistence abstraction for observations.\r\n *\r\n * Backends:\r\n * - SqliteBackend (sqlite-store.ts) — WAL-mode SQLite with generation tracking\r\n * - DegradedBackend — read-only empty store when SQLite is unavailable\r\n *\r\n * JSON is no longer a runtime writable backend.\r\n * observations.json is only used as a one-time migration source into SQLite.\r\n *\r\n * All observation persistence flows through this interface.\r\n */\r\n\r\nimport type { Observation } from '../types.js';\r\n\r\n/**\r\n * Raw transaction handle for compound atomic operations.\r\n *\r\n * Inside an `atomic()` block the caller gets a StoreTransaction whose methods\r\n * operate directly on the underlying storage WITHOUT acquiring their own lock.\r\n * The outer `atomic()` already holds the lock / transaction.\r\n */\r\nexport interface StoreTransaction {\r\n /** Load all observations (raw, no lock). */\r\n loadAll(): Promise<Observation[]>;\r\n /** Load the ID counter (raw, no lock). */\r\n loadIdCounter(): Promise<number>;\r\n /** Save all observations (raw, no lock). */\r\n saveAll(obs: Observation[]): Promise<void>;\r\n /** Save the ID counter (raw, no lock). */\r\n saveIdCounter(nextId: number): Promise<void>;\r\n}\r\n\r\nexport interface ObservationStore {\r\n // ── Lifecycle ──────────────────────────────────────────────────────\r\n\r\n /** One-time init: open DB/files, run migration if needed */\r\n init(dataDir: string): Promise<void>;\r\n\r\n // ── Read ───────────────────────────────────────────────────────────\r\n\r\n /** Load all observations into memory. Called at startup after init(). */\r\n loadAll(): Promise<Observation[]>;\r\n\r\n /** Load the current next-ID counter value. */\r\n loadIdCounter(): Promise<number>;\r\n\r\n // ── Write — single mutations ───────────────────────────────────────\r\n\r\n /** Insert a new observation. Bumps generation (if applicable). */\r\n insert(obs: Observation): Promise<void>;\r\n\r\n /** Update an existing observation in-place (matched by obs.id). */\r\n update(obs: Observation): Promise<void>;\r\n\r\n /** Remove a single observation by ID. */\r\n remove(id: number): Promise<void>;\r\n\r\n // ── Write — batch ──────────────────────────────────────────────────\r\n\r\n /**\r\n * Replace the entire observation set atomically.\r\n * Used by consolidation, cleanup, and project-ID migration.\r\n */\r\n bulkReplace(obs: Observation[]): Promise<void>;\r\n\r\n /** Remove multiple observations by ID in one operation. */\r\n bulkRemoveByIds(ids: number[]): Promise<void>;\r\n\r\n /** Persist the next-ID counter. */\r\n saveIdCounter(nextId: number): Promise<void>;\r\n\r\n // ── Compound atomic operations ─────────────────────────────────────\r\n\r\n /**\r\n * Execute fn while holding an exclusive lock (file lock for JSON,\r\n * transaction for SQLite). The StoreTransaction provides raw load/save\r\n * methods that operate within the lock scope.\r\n *\r\n * Used by storeObservation for compound topicKey-TOCTOU + ID-assignment.\r\n */\r\n atomic<T>(fn: (tx: StoreTransaction) => Promise<T>): Promise<T>;\r\n\r\n // ── Freshness (cross-process coherence) ────────────────────────────\r\n\r\n /**\r\n * Check if another process has mutated the store since our last read.\r\n * If yes, the caller should reload observations[] and rebuild the Orama index.\r\n *\r\n * - SqliteBackend: compares storage_generation in meta table vs local knownGeneration\r\n * - DegradedBackend: no-op, returns false (no data to refresh)\r\n *\r\n * @returns true if the local cache is stale and was refreshed\r\n */\r\n ensureFresh(): Promise<boolean>;\r\n\r\n /** Current known generation counter (local). */\r\n getGeneration(): number;\r\n\r\n // ── Lifecycle ─────────────────────────────────────────────────────\r\n\r\n /** Close the backend (release DB handles, file locks, etc.). */\r\n close(): void;\r\n\r\n // ── Diagnostics ────────────────────────────────────────────────────\r\n\r\n /** Which backend is active: 'sqlite' or 'degraded' (read-only). */\r\n getBackendName(): 'sqlite' | 'degraded';\r\n}\r\n\r\n// ── Singleton store access ─────────────────────────────────────────\r\n\r\nlet _store: ObservationStore | null = null;\r\nlet _storeDataDir: string | null = null;\r\n\r\n/** Get the active ObservationStore singleton. Throws if not yet initialized. */\r\nexport function getObservationStore(): ObservationStore {\r\n if (!_store) {\r\n throw new Error('[memorix] ObservationStore not initialized — call initObservationStore() first');\r\n }\r\n return _store;\r\n}\r\n\r\n/** Set the active ObservationStore singleton (called once during startup). */\r\nexport function setObservationStore(store: ObservationStore): void {\r\n _store = store;\r\n}\r\n\r\n/** Reset the singleton (for tests only). Detaches from the backend.\r\n * Call closeAllDatabases() separately if you need to release the shared DB handle. */\r\nexport function resetObservationStore(): void {\r\n if (_store) {\r\n try { _store.close(); } catch { /* best-effort */ }\r\n }\r\n _store = null;\r\n _storeDataDir = null;\r\n}\r\n\r\n/**\r\n * Create a fresh ObservationStore instance for a specific data directory\r\n * without touching the process-wide singleton. This is useful for long-lived\r\n * multi-project hosts (for example serve-http embedded dashboard APIs) where\r\n * requests may need to read different project data dirs concurrently.\r\n */\r\nexport async function createObservationStore(dataDir: string): Promise<ObservationStore> {\r\n // Try SQLite first (optionalDependencies — may not be installed)\r\n try {\r\n const { SqliteBackend } = await import('./sqlite-store.js');\r\n const store = new SqliteBackend();\r\n await store.init(dataDir);\r\n return store;\r\n } catch (err) {\r\n console.error(`[memorix] SQLite backend unavailable — degraded mode (read-only): ${err instanceof Error ? err.message : err}`);\r\n }\r\n\r\n // No writable JSON fallback — degraded read-only mode instead\r\n // observations.json is only used as migration source, not runtime backend\r\n const store = new DegradedBackend();\r\n await store.init(dataDir);\r\n return store;\r\n}\r\n\r\n/**\r\n * Initialize the ObservationStore singleton for the given data directory.\r\n *\r\n * Tries SQLite first. If unavailable, falls back to DegradedBackend (read-only).\r\n *\r\n * Idempotent: if already initialized for the same dataDir, returns the existing store.\r\n */\r\nexport async function initObservationStore(dataDir: string): Promise<ObservationStore> {\r\n if (_store && _storeDataDir === dataDir) {\r\n return _store;\r\n }\r\n\r\n // Close previous store if switching directories\r\n if (_store) {\r\n try { _store.close(); } catch { /* best-effort */ }\r\n _store = null;\r\n _storeDataDir = null;\r\n }\r\n\r\n const store = await createObservationStore(dataDir);\r\n _store = store;\r\n _storeDataDir = dataDir;\r\n return store;\r\n}\r\n\r\n// ── DegradedBackend (read-only when SQLite unavailable) ──────────\r\n\r\n/**\r\n * DegradedBackend — ObservationStore that is read-only and empty.\r\n *\r\n * Used when better-sqlite3 is unavailable. All write operations throw.\r\n * This ensures the system does not silently fall back to writing observations.json\r\n * as a runtime canonical store.\r\n */\r\nexport class DegradedBackend implements ObservationStore {\r\n private dataDir: string = '';\r\n\r\n async init(dataDir: string): Promise<void> {\r\n this.dataDir = dataDir;\r\n }\r\n\r\n async loadAll(): Promise<Observation[]> {\r\n return [];\r\n }\r\n\r\n async loadIdCounter(): Promise<number> {\r\n return 1;\r\n }\r\n\r\n async insert(_obs: Observation): Promise<void> {\r\n throw new Error('[memorix] Cannot write observations: SQLite backend unavailable (degraded mode)');\r\n }\r\n\r\n async update(_obs: Observation): Promise<void> {\r\n throw new Error('[memorix] Cannot write observations: SQLite backend unavailable (degraded mode)');\r\n }\r\n\r\n async remove(_id: number): Promise<void> {\r\n throw new Error('[memorix] Cannot write observations: SQLite backend unavailable (degraded mode)');\r\n }\r\n\r\n async bulkReplace(_obs: Observation[]): Promise<void> {\r\n throw new Error('[memorix] Cannot write observations: SQLite backend unavailable (degraded mode)');\r\n }\r\n\r\n async bulkRemoveByIds(_ids: number[]): Promise<void> {\r\n throw new Error('[memorix] Cannot write observations: SQLite backend unavailable (degraded mode)');\r\n }\r\n\r\n async saveIdCounter(_nextId: number): Promise<void> {\r\n throw new Error('[memorix] Cannot write observations: SQLite backend unavailable (degraded mode)');\r\n }\r\n\r\n async atomic<T>(_fn: (tx: StoreTransaction) => Promise<T>): Promise<T> {\r\n throw new Error('[memorix] Cannot write observations: SQLite backend unavailable (degraded mode)');\r\n }\r\n\r\n async ensureFresh(): Promise<boolean> {\r\n return false;\r\n }\r\n\r\n getGeneration(): number {\r\n return 0;\r\n }\r\n\r\n close(): void {\r\n // No resources to release\r\n }\r\n\r\n getBackendName(): 'sqlite' | 'degraded' {\r\n return 'degraded';\r\n }\r\n}\r\n","/**\r\n * Entity Extractor\r\n *\r\n * Regex-based entity extraction from observation content.\r\n * Inspired by MemCP's RegexEntityExtractor (MAGMA paper).\r\n *\r\n * Extracts: file paths, module paths, URLs, @mentions, CamelCase identifiers.\r\n * Also detects causal patterns for automatic edge typing.\r\n */\r\n\r\nconst ENTITY_PATTERNS: Array<{ kind: string; pattern: RegExp }> = [\r\n // File paths (e.g. src/auth/jwt.ts, ./config.json)\r\n { kind: 'file', pattern: /(?:^|[\\s\"'(])([.\\w/-]+\\.\\w{1,10})(?:[\\s\"'),]|$)/g },\r\n // Module/package paths (e.g. @orama/orama, memcp.core.graph)\r\n { kind: 'module', pattern: /(?:^|[\\s\"'(,])(@[\\w-]+\\/[\\w.-]+)|\\b([a-zA-Z_]\\w*(?:\\.[a-zA-Z_]\\w*){2,})\\b/g },\r\n // URLs\r\n { kind: 'url', pattern: /https?:\\/\\/[^\\s\"'<>)]+/g },\r\n // @mentions\r\n { kind: 'mention', pattern: /@([a-zA-Z_]\\w+)/g },\r\n // CamelCase identifiers (likely class/type names)\r\n { kind: 'identifier', pattern: /\\b([A-Z][a-z]+(?:[A-Z][a-z]+)+)\\b/g },\r\n // Chinese identifiers: quoted Chinese terms or backtick-wrapped Chinese (e.g. 「认证模块」, `数据库连接`)\r\n { kind: 'identifier', pattern: /[「『【]([一-鿿㐀-䶿]{2,}(?:[一-鿿㐀-䶿a-zA-Z0-9_-]*[一-鿿㐀-䶿])?)[」』】]/g },\r\n { kind: 'identifier', pattern: /`([一-鿿㐀-䶿]{2,}[一-鿿㐀-䶿a-zA-Z0-9_-]*)`/g },\r\n];\r\n\r\n/**\r\n * Patterns that indicate causal relationships.\r\n * Used to auto-detect causal edge types in Knowledge Graph.\r\n */\r\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;\r\n\r\nexport interface ExtractedEntities {\r\n files: string[];\r\n modules: string[];\r\n urls: string[];\r\n mentions: string[];\r\n identifiers: string[];\r\n hasCausalLanguage: boolean;\r\n}\r\n\r\n/**\r\n * Extract entities from text content.\r\n * Returns deduplicated lists of each entity type.\r\n */\r\nexport function extractEntities(content: string): ExtractedEntities {\r\n const result: ExtractedEntities = {\r\n files: [],\r\n modules: [],\r\n urls: [],\r\n mentions: [],\r\n identifiers: [],\r\n hasCausalLanguage: false,\r\n };\r\n\r\n const seen = new Set<string>();\r\n\r\n for (const { kind, pattern } of ENTITY_PATTERNS) {\r\n // Reset lastIndex for global regexes\r\n pattern.lastIndex = 0;\r\n let match: RegExpExecArray | null;\r\n while ((match = pattern.exec(content)) !== null) {\r\n const entity = (match[1] ?? match[2] ?? match[0]).trim().replace(/^[\"'(]+|[\"'),]+$/g, '');\r\n if (entity.length < 3 || (kind === 'file' && entity.length < 5)) continue;\r\n\r\n const key = `${kind}:${entity.toLowerCase()}`;\r\n if (seen.has(key)) continue;\r\n seen.add(key);\r\n\r\n switch (kind) {\r\n case 'file':\r\n // Filter out property chains (e.g. config.llm.apiKey, process.env.FOO)\r\n // Real files have path separators or known extensions\r\n // Inline logic to prevent tree-shaking\r\n const isLikelyFilePath = (() => {\r\n // Has path separator → likely a file path\r\n if (entity.includes('/') || entity.includes('\\\\')) return true;\r\n // Starts with ./ or ../ → relative path\r\n if (entity.startsWith('./') || entity.startsWith('../')) return true;\r\n // Blocked property chains\r\n if (/^(?:process\\.env|config\\.|options\\.|params\\.|props\\.|this\\.|self\\.|module\\.|exports\\.|require\\.|import\\.)/i.test(entity)) return false;\r\n // Multiple dots without path separator → likely property chain\r\n const dotCount = (entity.match(/\\./g) || []).length;\r\n if (dotCount >= 2) return false;\r\n // Single dot: check if extension is a known file extension\r\n const ext = entity.split('.').pop()?.toLowerCase() ?? '';\r\n const FILE_EXTENSIONS = new Set(['ts', 'js', 'tsx', 'jsx', 'mts', 'mjs', 'cjs', 'json', 'yaml', 'yml', 'toml', 'xml', 'csv', 'py', 'rb', 'go', 'rs', 'java', 'kt', 'swift', 'c', 'cpp', 'h', 'html', 'css', 'scss', 'less', 'vue', 'svelte', 'sh', 'bash', 'zsh', 'ps1', 'cmd', 'bat', 'md', 'txt', 'rst', 'log', 'sql', 'graphql', 'prisma', 'env', 'gitignore', 'dockerignore', 'dockerfile', 'lock', 'config']);\r\n return FILE_EXTENSIONS.has(ext);\r\n })();\r\n if (isLikelyFilePath) {\r\n result.files.push(entity);\r\n }\r\n break;\r\n case 'module':\r\n result.modules.push(entity);\r\n break;\r\n case 'url':\r\n result.urls.push(entity);\r\n break;\r\n case 'mention':\r\n result.mentions.push(entity);\r\n break;\r\n case 'identifier':\r\n result.identifiers.push(entity);\r\n break;\r\n }\r\n }\r\n }\r\n\r\n result.hasCausalLanguage = CAUSAL_PATTERN.test(content);\r\n\r\n return result;\r\n}\r\n\r\n/** Known file extensions that indicate a real file path */\r\nconst FILE_EXTENSIONS = new Set([\r\n 'ts', 'js', 'tsx', 'jsx', 'mts', 'mjs', 'cjs',\r\n 'json', 'yaml', 'yml', 'toml', 'xml', 'csv',\r\n 'py', 'rb', 'go', 'rs', 'java', 'kt', 'swift', 'c', 'cpp', 'h',\r\n 'html', 'css', 'scss', 'less', 'vue', 'svelte',\r\n 'sh', 'bash', 'zsh', 'ps1', 'cmd', 'bat',\r\n 'md', 'txt', 'rst', 'log',\r\n 'sql', 'graphql', 'prisma',\r\n 'env', 'gitignore', 'dockerignore', 'dockerfile',\r\n 'lock', 'config',\r\n]);\r\n\r\n/** Property-chain patterns that are NOT file paths */\r\nconst PROPERTY_CHAIN_BLOCKLIST = /^(?:process\\.env|config\\.|options\\.|params\\.|props\\.|this\\.|self\\.|module\\.|exports\\.|require\\.|import\\.)/i;\r\n\r\n/**\r\n * Determine if a matched string is likely a real file path vs a property chain.\r\n * \r\n * Examples:\r\n * \"src/config.ts\" → true (has path separator + known extension)\r\n * \"config.llm.apiKey\" → false (property chain, no path separator)\r\n * \"./package.json\" → true (relative path)\r\n * \"process.env.FOO\" → false (property chain)\r\n */\r\nfunction isLikelyFilePath(candidate: string): boolean {\r\n // Has path separator → likely a file path\r\n if (candidate.includes('/') || candidate.includes('\\\\')) return true;\r\n\r\n // Starts with ./ or ../ → relative path\r\n if (candidate.startsWith('./') || candidate.startsWith('../')) return true;\r\n\r\n // Blocked property chains\r\n if (PROPERTY_CHAIN_BLOCKLIST.test(candidate)) return false;\r\n\r\n // Multiple dots without path separator → likely property chain (e.g. config.llm.apiKey)\r\n const dotCount = (candidate.match(/\\./g) || []).length;\r\n if (dotCount >= 2) return false;\r\n\r\n // Single dot: check if extension is a known file extension\r\n const ext = candidate.split('.').pop()?.toLowerCase() ?? '';\r\n return FILE_EXTENSIONS.has(ext);\r\n}\r\n\r\n/**\r\n * Auto-generate concepts from extracted entities.\r\n * Merges with any user-provided concepts.\r\n */\r\nexport function enrichConcepts(\r\n userConcepts: string[],\r\n extracted: ExtractedEntities,\r\n): string[] {\r\n const all = new Set(userConcepts.map((c) => c.toLowerCase()));\r\n const enriched = [...userConcepts];\r\n\r\n // Add file names (without path) as concepts\r\n for (const f of extracted.files) {\r\n const name = f.split('/').pop()?.replace(/\\.\\w+$/, '') ?? '';\r\n if (name.length >= 3 && !all.has(name.toLowerCase())) {\r\n all.add(name.toLowerCase());\r\n enriched.push(name);\r\n }\r\n }\r\n\r\n // Add module names as concepts\r\n for (const m of extracted.modules) {\r\n const short = m.split(/[./]/).pop() ?? '';\r\n if (short.length >= 3 && !all.has(short.toLowerCase())) {\r\n all.add(short.toLowerCase());\r\n enriched.push(short);\r\n }\r\n }\r\n\r\n // Add CamelCase identifiers as concepts\r\n for (const id of extracted.identifiers) {\r\n if (!all.has(id.toLowerCase())) {\r\n all.add(id.toLowerCase());\r\n enriched.push(id);\r\n }\r\n }\r\n\r\n return enriched;\r\n}\r\n","/**\r\n * Secret Filter\r\n *\r\n * Conservative credential detection and redaction for Memorix memory content.\r\n * Designed for low false-positive risk: only matches explicit credential\r\n * assignments (key=value / key: value), not generic discussion of auth concepts.\r\n *\r\n * sanitizeCredentials() — store-time: called inside storeObservation() before write\r\n * redactCredentials() — retrieval-time: called in format/output paths for legacy safety\r\n * containsCredential() — predicate used for testing and optional logging\r\n *\r\n * Both sanitize and redact share the same pattern logic. They are kept as\r\n * separate named exports so call-site semantics remain clear.\r\n */\r\n\r\n/**\r\n * Replaces the VALUE portion of matched credential patterns with [REDACTED].\r\n * The credential key name is preserved so context is not lost.\r\n *\r\n * Pattern categories:\r\n * 1. key=value / key: value forms — password, token, api_key, secret, etc.\r\n * Requires a real value (6+ non-whitespace chars) to avoid matching\r\n * discussion text like \"password must be 8 chars\".\r\n * 2. Bearer authorization header tokens (20+ chars)\r\n * 3. Structured token prefixes: GitHub (ghp_/ghs_/gho_), OpenAI (sk-), JWT (eyJ)\r\n */\r\nfunction applyRedaction(text: string): string {\r\n if (!text) return text;\r\n let out = text;\r\n\r\n // key=value / key: \"value\" / key='value' — preserve key, redact value\r\n out = out.replace(\r\n /((?:password|passwd|pwd|secret|token|api[_-]?key|auth[_-]?key|access[_-]?key|private[_-]?key|client[_-]?secret)\\s*[:=]\\s*[\"']?)([^\\s\"',;\\n]{6,})/gi,\r\n '$1[REDACTED]',\r\n );\r\n\r\n // Bearer <token> — preserve \"Bearer \", redact token\r\n out = out.replace(\r\n /(Bearer\\s+)([A-Za-z0-9._\\-/+]{20,})/g,\r\n '$1[REDACTED]',\r\n );\r\n\r\n // GitHub tokens (ghp_, ghs_, gho_, github_pat_)\r\n out = out.replace(/\\b(?:ghp|ghs|gho|github_pat)_[A-Za-z0-9]{36,}\\b/g, '[REDACTED]');\r\n\r\n // OpenAI / similar keys (sk-...)\r\n out = out.replace(/\\bsk-[A-Za-z0-9T-]{20,}\\b/g, '[REDACTED]');\r\n\r\n // JWT tokens (base64url header eyJ...)\r\n out = out.replace(/\\beyJ[A-Za-z0-9._-]{40,}\\b/g, '[REDACTED]');\r\n\r\n return out;\r\n}\r\n\r\n/**\r\n * Store-time sanitization: strips credential values before any durable write.\r\n * Called inside storeObservation() / upsertObservation() so that every write\r\n * path (hooks, git-ingest, CLI, reasoning, compact-on-write) is covered.\r\n */\r\nexport function sanitizeCredentials(text: string): string {\r\n return applyRedaction(text);\r\n}\r\n\r\n/**\r\n * Retrieval-time redaction: masks credential values in display output.\r\n * Applied in all output formatters (detail, index table, timeline, session context)\r\n * as a safety net for legacy observations stored before sanitization was in place.\r\n */\r\nexport function redactCredentials(text: string): string {\r\n return applyRedaction(text);\r\n}\r\n\r\n/**\r\n * Returns true if the text contains an obvious credential pattern.\r\n * Used for testing and optional diagnostic logging.\r\n */\r\nexport function containsCredential(text: string): boolean {\r\n return applyRedaction(text) !== text;\r\n}\r\n","/**\r\n * Observations Manager\r\n *\r\n * Manages rich observation records with auto-classification and token counting.\r\n * Source: claude-mem's observation data model with structured fields.\r\n *\r\n * Each observation is stored both in the knowledge graph (as entity observation)\r\n * and in the Orama search index (for full-text + vector search).\r\n */\r\n\r\nimport type { Observation, ObservationType, ObservationStatus, MemorixDocument, ProgressInfo } from '../types.js';\r\nimport { TOPIC_KEY_FAMILIES } from '../types.js';\r\nimport {\r\n insertObservation,\r\n removeObservation,\r\n resetDb,\r\n generateEmbedding,\r\n batchGenerateEmbeddings,\r\n getVectorDimensions,\r\n hydrateIndex,\r\n isEmbeddingEnabled,\r\n makeOramaObservationId,\r\n} from '../store/orama-store.js';\r\nimport { getObservationStore, initObservationStore } from '../store/obs-store.js';\r\nimport { countTextTokens } from '../compact/token-budget.js';\r\nimport { extractEntities, enrichConcepts } from './entity-extractor.js';\r\nimport { getEmbeddingProvider, isEmbeddingExplicitlyDisabled } from '../embedding/provider.js';\r\nimport { sanitizeCredentials } from './secret-filter.js';\r\n\r\n/** In-memory observation list (loaded from persistence on init) */\r\nlet observations: Observation[] = [];\r\nlet nextId = 1;\r\nlet projectDir: string | null = null;\r\n\r\n// ── Vector-missing tracking ──────────────────────────────────────\r\n// Tracks observation IDs whose async embedding write failed or was skipped.\r\n// Enables observability (\"how many memories lack vectors?\") and backfill.\r\nconst vectorMissingIds = new Set<number>();\r\nlet vectorBackfillRunning = false;\r\n\r\nfunction isVectorCompatibleWithCurrentIndex(embedding: number[] | null): boolean {\r\n if (!embedding) return false;\r\n const vectorDimensions = getVectorDimensions();\r\n return vectorDimensions === null || embedding.length === vectorDimensions;\r\n}\r\n\r\n/**\r\n * Initialize the observations manager with a project directory.\r\n * Auto-initializes the ObservationStore if not already set.\r\n */\r\nexport async function initObservations(dir: string): Promise<void> {\r\n projectDir = dir;\r\n await initObservationStore(dir);\r\n const store = getObservationStore();\r\n observations = await store.loadAll();\r\n nextId = await store.loadIdCounter();\r\n}\r\n\r\n/**\r\n * Check cross-process freshness and reload if another process has written.\r\n *\r\n * Call this at every read boundary (MCP tool handler, dashboard API, etc.)\r\n * BEFORE reading observations[] via getObservation / getAllObservations /\r\n * getProjectObservations / getObservationCount.\r\n *\r\n * When the SQLite storage_generation has advanced beyond our local snapshot:\r\n * 1. Reloads observations[] from the store\r\n * 2. Updates nextId from the store\r\n * 3. Rebuilds the Orama search index (so vector + BM25 search stay in sync)\r\n *\r\n * For DegradedBackend this is a no-op (always returns false).\r\n */\r\nexport async function ensureFreshObservations(): Promise<boolean> {\r\n if (!projectDir) return false;\r\n try {\r\n const store = getObservationStore();\r\n const wasStale = await store.ensureFresh();\r\n if (wasStale) {\r\n observations = await store.loadAll();\r\n nextId = await store.loadIdCounter();\r\n await reindexObservations();\r\n return true;\r\n }\r\n } catch {\r\n // Best-effort — don't crash the read path on freshness failure\r\n }\r\n return false;\r\n}\r\n\r\n/**\r\n * @internal Observation-only freshness gate.\r\n *\r\n * Public callers should use `withFreshIndex()` from freshness.ts instead,\r\n * which also covers mini-skills. This function remains for internal use\r\n * by the freshness module and legacy test code only.\r\n */\r\nexport async function withFreshObservations<T>(fn: () => T | Promise<T>): Promise<T> {\r\n await ensureFreshObservations();\r\n return fn();\r\n}\r\n\r\n/**\r\n * Store a new observation.\r\n *\r\n * This is the primary write API — called by the `memorix_store` MCP tool.\r\n * Automatically:\r\n * 1. Assigns an incremental ID\r\n * 2. Counts tokens for the observation content\r\n * 3. Inserts into Orama for full-text search\r\n * 4. Persists to disk\r\n */\r\nexport async function storeObservation(input: {\r\n entityName: string;\r\n type: ObservationType;\r\n title: string;\r\n narrative: string;\r\n facts?: string[];\r\n filesModified?: string[];\r\n concepts?: string[];\r\n projectId: string;\r\n topicKey?: string;\r\n sessionId?: string;\r\n progress?: ProgressInfo;\r\n source?: 'agent' | 'git' | 'manual';\r\n commitHash?: string;\r\n relatedCommits?: string[];\r\n relatedEntities?: string[];\r\n sourceDetail?: 'explicit' | 'hook' | 'git-ingest';\r\n valueCategory?: 'core' | 'contextual' | 'ephemeral';\r\n createdByAgentId?: string;\r\n}): Promise<{ observation: Observation; upserted: boolean }> {\r\n const now = new Date().toISOString();\r\n\r\n // ── Central secret sanitization — strip credential values before any persistence ──\r\n // Covers all write paths: hooks, git-ingest, CLI, reasoning, compact-on-write, etc.\r\n input = { ...input, title: sanitizeCredentials(input.title), narrative: sanitizeCredentials(input.narrative), facts: input.facts?.map(sanitizeCredentials) };\r\n\r\n // Topic key upsert: fast-path check in-memory (optimistic, may be stale).\r\n // A second authoritative check happens inside the file lock to prevent TOCTOU races\r\n // where two concurrent calls with the same topicKey both miss this check.\r\n if (input.topicKey) {\r\n const existing = observations.find(\r\n o => o.topicKey === input.topicKey && o.projectId === input.projectId,\r\n );\r\n if (existing) {\r\n return { observation: await upsertObservation(existing, input, now), upserted: true };\r\n }\r\n }\r\n\r\n // ── Pre-compute enrichments (pure, no side-effects) ──\r\n const contentForExtraction = [input.title, input.narrative, ...(input.facts ?? [])].join(' ');\r\n const extracted = extractEntities(contentForExtraction);\r\n const enrichedConcepts = enrichConcepts(input.concepts ?? [], extracted);\r\n const userFiles = new Set((input.filesModified ?? []).map((f) => f.toLowerCase()));\r\n const enrichedFiles = [...(input.filesModified ?? [])];\r\n for (const f of extracted.files) {\r\n if (!userFiles.has(f.toLowerCase())) {\r\n enrichedFiles.push(f);\r\n }\r\n }\r\n const fullText = [\r\n input.title, input.narrative,\r\n ...(input.facts ?? []), ...enrichedFiles, ...enrichedConcepts,\r\n ].join(' ');\r\n const tokens = countTextTokens(fullText);\r\n\r\n // ── Atomic write: ID allocation + persist + in-memory push inside lock ──\r\n // This prevents concurrent calls from getting duplicate IDs or silently\r\n // losing observations due to stale in-memory state.\r\n let observation!: Observation;\r\n let doc!: MemorixDocument;\r\n\r\n let upsertedInsideLock = false;\r\n const assignAndPersist = async () => {\r\n if (projectDir) {\r\n const store = getObservationStore();\r\n await store.atomic(async (tx) => {\r\n // Re-read from store to get the authoritative nextId and observation list\r\n const diskObs = await tx.loadAll();\r\n const diskNextId = await tx.loadIdCounter();\r\n\r\n // ── Atomic topicKey re-check inside lock (prevents TOCTOU race) ──\r\n // Two concurrent calls with the same topicKey may both pass the fast-path\r\n // check above, but here we re-check against the authoritative disk state.\r\n if (input.topicKey) {\r\n const diskExisting = diskObs.find(\r\n o => o.topicKey === input.topicKey && o.projectId === input.projectId,\r\n );\r\n if (diskExisting) {\r\n // Switch to upsert path — update the existing observation in-place\r\n observations = diskObs;\r\n upsertedInsideLock = true;\r\n observation = diskExisting as Observation;\r\n return; // Exit atomic — upsert will be handled after assignAndPersist\r\n }\r\n }\r\n\r\n // Use the higher of in-memory vs disk counter (handles multi-process)\r\n const id = Math.max(nextId, diskNextId);\r\n\r\n observation = {\r\n id,\r\n entityName: input.entityName,\r\n type: input.type,\r\n title: input.title,\r\n narrative: input.narrative,\r\n facts: input.facts ?? [],\r\n filesModified: enrichedFiles,\r\n concepts: enrichedConcepts,\r\n tokens,\r\n createdAt: now,\r\n projectId: input.projectId,\r\n hasCausalLanguage: extracted.hasCausalLanguage,\r\n topicKey: input.topicKey,\r\n revisionCount: 1,\r\n sessionId: input.sessionId,\r\n status: 'active',\r\n progress: input.progress,\r\n source: input.source,\r\n commitHash: input.commitHash,\r\n relatedCommits: input.relatedCommits,\r\n relatedEntities: input.relatedEntities,\r\n sourceDetail: input.sourceDetail,\r\n valueCategory: input.valueCategory,\r\n createdByAgentId: input.createdByAgentId,\r\n // Phase 4a: predict writeGeneration before saveAll so it gets persisted to SQLite.\r\n // bumpGeneration() runs after fn(tx) returns, incrementing by 1.\r\n writeGeneration: store.getGeneration() + 1,\r\n };\r\n\r\n diskObs.push(observation);\r\n nextId = id + 1;\r\n observations = diskObs;\r\n\r\n await tx.saveAll(observations);\r\n await tx.saveIdCounter(nextId);\r\n });\r\n\r\n // Phase 4a: confirm writeGeneration matches actual post-bump value\r\n observation.writeGeneration = store.getGeneration();\r\n\r\n // If the atomic block detected a topicKey duplicate, skip Orama insert — upsert handles it\r\n if (upsertedInsideLock) return;\r\n } else {\r\n // No projectDir (e.g., tests) — just use in-memory counter\r\n const id = nextId++;\r\n observation = {\r\n id,\r\n entityName: input.entityName,\r\n type: input.type,\r\n title: input.title,\r\n narrative: input.narrative,\r\n facts: input.facts ?? [],\r\n filesModified: enrichedFiles,\r\n concepts: enrichedConcepts,\r\n tokens,\r\n createdAt: now,\r\n projectId: input.projectId,\r\n hasCausalLanguage: extracted.hasCausalLanguage,\r\n topicKey: input.topicKey,\r\n revisionCount: 1,\r\n sessionId: input.sessionId,\r\n status: 'active',\r\n progress: input.progress,\r\n source: input.source,\r\n commitHash: input.commitHash,\r\n relatedCommits: input.relatedCommits,\r\n relatedEntities: input.relatedEntities,\r\n sourceDetail: input.sourceDetail,\r\n valueCategory: input.valueCategory,\r\n createdByAgentId: input.createdByAgentId,\r\n writeGeneration: 0,\r\n };\r\n observations.push(observation);\r\n }\r\n\r\n // Build Orama doc AFTER id is assigned\r\n doc = {\r\n id: makeOramaObservationId(input.projectId, observation.id),\r\n observationId: observation.id,\r\n entityName: input.entityName,\r\n type: input.type,\r\n title: input.title,\r\n narrative: input.narrative,\r\n facts: (input.facts ?? []).join('\\n'),\r\n filesModified: enrichedFiles.join('\\n'),\r\n concepts: enrichedConcepts.map(c => c.replace(/-/g, ' ')).join(', '),\r\n tokens,\r\n createdAt: now,\r\n projectId: input.projectId,\r\n accessCount: 0,\r\n lastAccessedAt: '',\r\n status: 'active',\r\n source: input.source ?? 'agent',\r\n sourceDetail: input.sourceDetail ?? '',\r\n valueCategory: input.valueCategory ?? '',\r\n };\r\n\r\n await insertObservation(doc);\r\n };\r\n\r\n await assignAndPersist();\r\n\r\n // If the lock discovered a topicKey duplicate on disk, delegate to upsert\r\n if (upsertedInsideLock) {\r\n return { observation: await upsertObservation(observation, input, now), upserted: true };\r\n }\r\n\r\n // Generate embedding async (fire-and-forget) — never blocks MCP response\r\n // Track in vectorMissingIds until embedding is successfully written.\r\n const obsId = observation.id;\r\n vectorMissingIds.add(obsId);\r\n const searchableText = [input.title, input.narrative, ...(input.facts ?? [])].join(' ');\r\n generateEmbedding(searchableText).then(async (embedding) => {\r\n if (embedding) {\r\n if (!isVectorCompatibleWithCurrentIndex(embedding)) {\r\n const vectorDimensions = getVectorDimensions();\r\n console.error(\r\n `[memorix] Embedding dimension mismatch for obs-${obsId}: provider returned ${embedding.length}d, index expects ${vectorDimensions ?? 'unknown'}d (kept in backfill queue)`,\r\n );\r\n return;\r\n }\r\n try {\r\n const { removeObservation: removeObs } = await import('../store/orama-store.js');\r\n await removeObs(makeOramaObservationId(input.projectId, obsId));\r\n await insertObservation(Object.assign({}, doc, { embedding }));\r\n vectorMissingIds.delete(obsId);\r\n } catch {\r\n console.error(`[memorix] Embedding index update failed for obs-${obsId} (kept in backfill queue)`);\r\n }\r\n } else if (isEmbeddingExplicitlyDisabled()) {\r\n vectorMissingIds.delete(obsId);\r\n } else {\r\n console.error(`[memorix] Embedding provider unavailable for obs-${obsId} (kept in backfill queue for retry)`);\r\n }\r\n }).catch((err) => {\r\n console.error(`[memorix] Async embedding failed for obs-${obsId}: ${err instanceof Error ? err.message : err}`);\r\n });\r\n\r\n return { observation, upserted: false };\r\n}\r\n\r\n/**\r\n * Update an existing observation via topic key upsert.\r\n * Replaces content but preserves the original ID and createdAt.\r\n */\r\nasync function upsertObservation(\r\n existing: Observation,\r\n input: {\r\n entityName: string;\r\n type: ObservationType;\r\n title: string;\r\n narrative: string;\r\n facts?: string[];\r\n filesModified?: string[];\r\n concepts?: string[];\r\n projectId: string;\r\n topicKey?: string;\r\n sessionId?: string;\r\n progress?: ProgressInfo;\r\n sourceDetail?: 'explicit' | 'hook' | 'git-ingest';\r\n valueCategory?: 'core' | 'contextual' | 'ephemeral';\r\n },\r\n now: string,\r\n): Promise<Observation> {\r\n // ── Central secret sanitization ──\r\n input = { ...input, title: sanitizeCredentials(input.title), narrative: sanitizeCredentials(input.narrative), facts: input.facts?.map(sanitizeCredentials) };\r\n\r\n // Auto-extract and enrich (same as storeObservation)\r\n const contentForExtraction = [input.title, input.narrative, ...(input.facts ?? [])].join(' ');\r\n const extracted = extractEntities(contentForExtraction);\r\n const enrichedConcepts = enrichConcepts(input.concepts ?? [], extracted);\r\n const userFiles = new Set((input.filesModified ?? []).map((f) => f.toLowerCase()));\r\n const enrichedFiles = [...(input.filesModified ?? [])];\r\n for (const f of extracted.files) {\r\n if (!userFiles.has(f.toLowerCase())) enrichedFiles.push(f);\r\n }\r\n const fullText = [input.title, input.narrative, ...(input.facts ?? []), ...enrichedFiles, ...enrichedConcepts].join(' ');\r\n const tokens = countTextTokens(fullText);\r\n\r\n // Mark old observation as resolved (superseded by new version)\r\n // Note: topicKey upsert replaces in-place, so we just bump revision\r\n\r\n // Update in-place\r\n existing.entityName = input.entityName;\r\n existing.type = input.type;\r\n existing.title = input.title;\r\n existing.narrative = input.narrative;\r\n existing.facts = input.facts ?? [];\r\n existing.filesModified = enrichedFiles;\r\n existing.concepts = enrichedConcepts;\r\n existing.tokens = tokens;\r\n existing.updatedAt = now;\r\n existing.hasCausalLanguage = extracted.hasCausalLanguage;\r\n existing.revisionCount = (existing.revisionCount ?? 1) + 1;\r\n existing.status = 'active';\r\n if (input.sessionId) existing.sessionId = input.sessionId;\r\n if (input.progress) existing.progress = input.progress;\r\n if (input.sourceDetail !== undefined) existing.sourceDetail = input.sourceDetail;\r\n if (input.valueCategory !== undefined) existing.valueCategory = input.valueCategory;\r\n\r\n // Re-index in Orama WITHOUT embedding first (non-blocking)\r\n const doc: MemorixDocument = {\r\n id: makeOramaObservationId(existing.projectId, existing.id),\r\n observationId: existing.id,\r\n entityName: existing.entityName,\r\n type: existing.type,\r\n title: existing.title,\r\n narrative: existing.narrative,\r\n facts: existing.facts.join('\\n'),\r\n filesModified: enrichedFiles.join('\\n'),\r\n concepts: enrichedConcepts.map(c => c.replace(/-/g, ' ')).join(', '),\r\n tokens,\r\n createdAt: existing.createdAt,\r\n projectId: existing.projectId,\r\n accessCount: 0,\r\n lastAccessedAt: '',\r\n status: 'active',\r\n source: existing.source ?? 'agent',\r\n sourceDetail: existing.sourceDetail ?? '',\r\n valueCategory: existing.valueCategory ?? '',\r\n };\r\n\r\n // Remove old doc and insert updated one (with retry for concurrent upsert race)\r\n const oramaId = makeOramaObservationId(existing.projectId, existing.id);\r\n try {\r\n const { removeObservation } = await import('../store/orama-store.js');\r\n await removeObservation(oramaId);\r\n } catch { /* may not exist in index */ }\r\n try {\r\n await insertObservation(doc);\r\n } catch {\r\n // Concurrent upsert may have already re-inserted — retry remove+insert once\r\n try {\r\n const { removeObservation: removeObs } = await import('../store/orama-store.js');\r\n await removeObs(oramaId);\r\n await insertObservation(doc);\r\n } catch { /* best effort — file persistence is the source of truth */ }\r\n }\r\n\r\n // Persist via ObservationStore\r\n if (projectDir) {\r\n const store = getObservationStore();\r\n await store.update(existing);\r\n }\r\n\r\n // Generate embedding async (fire-and-forget) — never blocks MCP response\r\n const searchableText = [input.title, input.narrative, ...(input.facts ?? [])].join(' ');\r\n const obsId = existing.id;\r\n generateEmbedding(searchableText).then(async (embedding) => {\r\n if (embedding) {\r\n try {\r\n const { removeObservation: removeObs } = await import('../store/orama-store.js');\r\n await removeObs(makeOramaObservationId(existing.projectId, obsId));\r\n await insertObservation(Object.assign({}, doc, { embedding }));\r\n } catch {\r\n // Embedding index update failed — observation still persisted without vector\r\n }\r\n }\r\n }).catch((err) => {\r\n console.error(`[memorix] Async embedding failed for obs-${obsId}: ${err instanceof Error ? err.message : err}`);\r\n });\r\n\r\n return existing;\r\n}\r\n\r\n/**\r\n * Get an observation by ID.\r\n */\r\nexport function getObservation(id: number, projectId?: string): Observation | undefined {\r\n return observations.find((o) => o.id === id && (projectId ? o.projectId === projectId : true));\r\n}\r\n\r\n/**\r\n * Resolve observations — mark them as resolved (completed/no longer active).\r\n * This prevents resolved memories from appearing in default search results.\r\n */\r\nexport async function resolveObservations(\r\n ids: number[],\r\n status: ObservationStatus = 'resolved',\r\n): Promise<{ resolved: number[]; notFound: number[] }> {\r\n const resolved: number[] = [];\r\n const notFound: number[] = [];\r\n const now = new Date().toISOString();\r\n\r\n for (const id of ids) {\r\n const obs = observations.find(o => o.id === id);\r\n if (!obs) {\r\n notFound.push(id);\r\n continue;\r\n }\r\n obs.status = status;\r\n obs.updatedAt = now;\r\n if (obs.progress) {\r\n obs.progress.status = status === 'resolved' ? 'completed' : obs.progress.status;\r\n }\r\n resolved.push(id);\r\n\r\n // Update Orama index (without blocking on embedding)\r\n try {\r\n const { removeObservation: removeObs } = await import('../store/orama-store.js');\r\n await removeObs(makeOramaObservationId(obs.projectId, id));\r\n const doc: MemorixDocument = {\r\n id: makeOramaObservationId(obs.projectId, obs.id),\r\n observationId: obs.id,\r\n entityName: obs.entityName,\r\n type: obs.type,\r\n title: obs.title,\r\n narrative: obs.narrative,\r\n facts: obs.facts.join('\\n'),\r\n filesModified: obs.filesModified.join('\\n'),\r\n concepts: obs.concepts.map(c => c.replace(/-/g, ' ')).join(', '),\r\n tokens: obs.tokens,\r\n createdAt: obs.createdAt,\r\n projectId: obs.projectId,\r\n accessCount: 0,\r\n lastAccessedAt: '',\r\n status,\r\n source: obs.source ?? 'agent',\r\n sourceDetail: obs.sourceDetail ?? '',\r\n valueCategory: obs.valueCategory ?? '',\r\n };\r\n await insertObservation(doc);\r\n // Async embedding update (fire-and-forget)\r\n const obsId = obs.id;\r\n generateEmbedding([obs.title, obs.narrative, ...obs.facts].join(' ')).then(async (embedding) => {\r\n if (embedding) {\r\n try {\r\n await removeObs(`obs-${obsId}`);\r\n await insertObservation(Object.assign({}, doc, { embedding }));\r\n } catch { /* best effort */ }\r\n }\r\n }).catch(() => {});\r\n } catch { /* best effort */ }\r\n }\r\n\r\n // Persist via ObservationStore\r\n if (projectDir && resolved.length > 0) {\r\n const store = getObservationStore();\r\n await store.bulkReplace(observations);\r\n }\r\n\r\n return { resolved, notFound };\r\n}\r\n\r\n/**\r\n * Get all observations for a project.\r\n * Supports alias expansion: if projectIds is an array, matches any of them.\r\n */\r\nexport function getProjectObservations(projectId: string | string[]): Observation[] {\r\n if (Array.isArray(projectId)) {\r\n const idSet = new Set(projectId);\r\n return observations.filter((o) => idSet.has(o.projectId));\r\n }\r\n return observations.filter((o) => o.projectId === projectId);\r\n}\r\n\r\n/**\r\n * Migrate observations from non-canonical project IDs to the canonical ID.\r\n *\r\n * Called once during server startup after alias registration.\r\n * Rewrites in-memory observations and persists changes to disk.\r\n *\r\n * @param aliasIds - All known alias IDs for this project (including canonical)\r\n * @param canonicalId - The canonical project ID to normalize to\r\n * @returns Number of observations migrated\r\n */\r\nexport async function migrateProjectIds(\r\n aliasIds: string[],\r\n canonicalId: string,\r\n): Promise<number> {\r\n const nonCanonical = new Set(aliasIds.filter(id => id !== canonicalId));\r\n if (nonCanonical.size === 0) return 0;\r\n\r\n let migrated = 0;\r\n for (const obs of observations) {\r\n if (nonCanonical.has(obs.projectId)) {\r\n obs.projectId = canonicalId;\r\n migrated++;\r\n }\r\n }\r\n\r\n if (migrated > 0 && projectDir) {\r\n const store = getObservationStore();\r\n await store.bulkReplace(observations);\r\n }\r\n\r\n return migrated;\r\n}\r\n\r\n/**\r\n * Get all observations (in-memory copy).\r\n * Used by timeline and retention to avoid unreliable Orama empty-term queries.\r\n */\r\nexport function getAllObservations(): Observation[] {\r\n return [...observations];\r\n}\r\n\r\n/**\r\n * Get the total number of stored observations.\r\n */\r\nexport function getObservationCount(): number {\r\n return observations.length;\r\n}\r\n\r\n/**\r\n * Suggest a stable topic key from type + title.\r\n * Uses family heuristics (architecture/*, bug/*, decision/*, etc.)\r\n * Inspired by Engram's mem_suggest_topic_key.\r\n */\r\nexport function suggestTopicKey(type: string, title: string): string {\r\n // Determine family from type\r\n let family = 'general';\r\n const typeLower = type.toLowerCase();\r\n for (const [fam, keywords] of Object.entries(TOPIC_KEY_FAMILIES)) {\r\n if (keywords.some(k => typeLower.includes(k))) {\r\n family = fam;\r\n break;\r\n }\r\n }\r\n\r\n // Normalize title to slug\r\n const slug = title\r\n .toLowerCase()\r\n .replace(/[^a-z0-9\\u4e00-\\u9fff\\s-]/g, '') // keep letters, digits, CJK, spaces, hyphens\r\n .trim()\r\n .replace(/\\s+/g, '-')\r\n .slice(0, 60);\r\n\r\n if (!slug) return '';\r\n return `${family}/${slug}`;\r\n}\r\n\r\n/**\r\n * Reload observations into the Orama index with full corpus embeddings.\r\n * Intended for explicit heavy rebuilds, not normal MCP startup.\r\n *\r\n * Optimization: uses batch embedding (ONNX processes 64 texts at a time)\r\n * instead of individual embed calls. This reduces startup CPU from minutes\r\n * to seconds for large observation sets (500+).\r\n */\r\nexport async function reindexObservations(): Promise<number> {\r\n if (observations.length === 0) return 0;\r\n\r\n // Reset the Orama index to ensure clean reindex (idempotent)\r\n await resetDb();\r\n vectorMissingIds.clear();\r\n\r\n // Batch-generate all embeddings at once (much faster than individual calls)\r\n let embeddings: (number[] | null)[] = observations.map(() => null);\r\n const provider = await getEmbeddingProvider();\r\n const canBatchEmbedAtStartup = provider !== null && !provider.name.startsWith('api-');\r\n\r\n if (provider && !canBatchEmbedAtStartup) {\r\n console.error('[memorix] Startup reindex: skipping synchronous API embeddings; background backfill will hydrate vectors');\r\n }\r\n\r\n if (canBatchEmbedAtStartup) {\r\n try {\r\n const texts = observations.map(obs =>\r\n [obs.title, obs.narrative, ...obs.facts].join(' '),\r\n );\r\n embeddings = await batchGenerateEmbeddings(texts);\r\n // Batch embedding failed — fall back to no embeddings\r\n } catch {\r\n // Batch embedding failed; fall back to no embeddings.\r\n }\r\n }\r\n\r\n let count = 0;\r\n for (let i = 0; i < observations.length; i++) {\r\n const obs = observations[i];\r\n try {\r\n const embedding = embeddings[i] ?? null;\r\n const compatibleEmbedding = isVectorCompatibleWithCurrentIndex(embedding) ? embedding : null;\r\n if (embedding && !compatibleEmbedding) {\r\n const vectorDimensions = getVectorDimensions();\r\n console.error(\r\n `[memorix] Startup reindex embedding mismatch for obs-${obs.id}: provider returned ${embedding.length}d, index expects ${vectorDimensions ?? 'unknown'}d (queued for backfill)`,\r\n );\r\n }\r\n const docId = makeOramaObservationId(obs.projectId, obs.id);\r\n const doc: MemorixDocument = {\r\n id: docId,\r\n observationId: obs.id,\r\n entityName: obs.entityName,\r\n type: obs.type,\r\n title: obs.title,\r\n narrative: obs.narrative,\r\n facts: obs.facts.join('\\n'),\r\n filesModified: obs.filesModified.join('\\n'),\r\n concepts: obs.concepts.map((c: string) => c.replace(/-/g, ' ')).join(', '),\r\n tokens: obs.tokens,\r\n createdAt: obs.createdAt,\r\n projectId: obs.projectId,\r\n accessCount: 0,\r\n lastAccessedAt: '',\r\n status: obs.status ?? 'active',\r\n source: obs.source ?? 'agent',\r\n sourceDetail: obs.sourceDetail ?? '',\r\n valueCategory: obs.valueCategory ?? '',\r\n ...(compatibleEmbedding ? { embedding: compatibleEmbedding } : {}),\r\n };\r\n await insertObservation(doc);\r\n if (!compatibleEmbedding && !isEmbeddingExplicitlyDisabled()) {\r\n vectorMissingIds.add(obs.id);\r\n }\r\n count++;\r\n } catch (err) {\r\n console.error(`[memorix] Failed to reindex observation #${obs.id}: ${err}`);\r\n }\r\n }\r\n return count;\r\n}\r\n\r\n/**\r\n * Prepare the search index for startup and hot-reload without blocking on\r\n * corpus-wide embedding generation.\r\n *\r\n * This hydrates the lexical/BM25 index immediately so MCP availability is not\r\n * coupled to embedding provider throughput. Missing vectors are queued for the\r\n * existing background backfill cycle.\r\n */\r\nexport async function prepareSearchIndex(): Promise<number> {\r\n await resetDb();\r\n const count = await hydrateIndex(observations as unknown as any[]);\r\n\r\n vectorMissingIds.clear();\r\n if (isEmbeddingEnabled()) {\r\n for (const obs of observations) {\r\n // Queue ALL statuses for vector backfill — status filtering happens at query time,\r\n // not at index time. Omitting non-active observations here would permanently\r\n // exclude resolved/archived memories from hybrid search after restart.\r\n vectorMissingIds.add(obs.id);\r\n }\r\n }\r\n\r\n return count;\r\n}\r\n\r\n// ── Vector-missing observability & backfill ─────────────────────────\r\n\r\n/**\r\n * Get the current set of observation IDs that are missing vector embeddings.\r\n * Useful for dashboards, health checks, and monitoring search quality degradation.\r\n */\r\nexport function getVectorMissingIds(): number[] {\r\n return [...vectorMissingIds];\r\n}\r\n\r\n/**\r\n * Get a summary of vector embedding status.\r\n * Returns total observations, how many have vectors, and how many are missing.\r\n */\r\nexport function getVectorStatus(): {\r\n total: number;\r\n missing: number;\r\n missingIds: number[];\r\n backfillRunning: boolean;\r\n} {\r\n return {\r\n total: observations.length,\r\n missing: vectorMissingIds.size,\r\n missingIds: [...vectorMissingIds],\r\n backfillRunning: vectorBackfillRunning,\r\n };\r\n}\r\n\r\n/**\r\n * Attempt to backfill missing vector embeddings.\r\n * Re-generates embeddings for observations in vectorMissingIds.\r\n * Returns the number successfully backfilled.\r\n *\r\n * Safe to call concurrently — only one backfill runs at a time.\r\n */\r\nexport async function backfillVectorEmbeddings(): Promise<{\r\n attempted: number;\r\n succeeded: number;\r\n failed: number;\r\n}> {\r\n if (vectorBackfillRunning) {\r\n return { attempted: 0, succeeded: 0, failed: 0 };\r\n }\r\n vectorBackfillRunning = true;\r\n\r\n const ids = [...vectorMissingIds];\r\n let succeeded = 0;\r\n let failed = 0;\r\n\r\n try {\r\n for (const id of ids) {\r\n const obs = observations.find(o => o.id === id);\r\n if (!obs) {\r\n vectorMissingIds.delete(id);\r\n continue;\r\n }\r\n\r\n const text = [obs.title, obs.narrative, ...obs.facts].join(' ');\r\n try {\r\n const embedding = await generateEmbedding(text);\r\n if (embedding) {\r\n if (!isVectorCompatibleWithCurrentIndex(embedding)) {\r\n const vectorDimensions = getVectorDimensions();\r\n console.error(\r\n `[memorix] Backfill embedding mismatch for obs-${id}: provider returned ${embedding.length}d, index expects ${vectorDimensions ?? 'unknown'}d (kept in queue)`,\r\n );\r\n failed++;\r\n continue;\r\n }\r\n const oramaId = makeOramaObservationId(obs.projectId, obs.id);\r\n try {\r\n const { removeObservation: removeObs } = await import('../store/orama-store.js');\r\n await removeObs(oramaId);\r\n } catch { /* may not exist */ }\r\n const doc: MemorixDocument = {\r\n id: oramaId,\r\n observationId: obs.id,\r\n entityName: obs.entityName,\r\n type: obs.type,\r\n title: obs.title,\r\n narrative: obs.narrative,\r\n facts: obs.facts.join('\\n'),\r\n filesModified: obs.filesModified.join('\\n'),\r\n concepts: obs.concepts.map(c => c.replace(/-/g, ' ')).join(', '),\r\n tokens: obs.tokens,\r\n createdAt: obs.createdAt,\r\n projectId: obs.projectId,\r\n accessCount: 0,\r\n lastAccessedAt: '',\r\n status: obs.status ?? 'active',\r\n source: obs.source ?? 'agent',\r\n sourceDetail: obs.sourceDetail ?? '',\r\n valueCategory: obs.valueCategory ?? '',\r\n embedding,\r\n };\r\n await insertObservation(doc);\r\n vectorMissingIds.delete(id);\r\n succeeded++;\r\n } else if (isEmbeddingExplicitlyDisabled()) {\r\n // Embedding explicitly off — nothing to backfill from\r\n vectorMissingIds.delete(id);\r\n } else {\r\n // Provider temporarily unavailable — keep in queue for next backfill cycle\r\n failed++;\r\n }\r\n } catch {\r\n failed++;\r\n }\r\n }\r\n } finally {\r\n vectorBackfillRunning = false;\r\n }\r\n\r\n return { attempted: ids.length, succeeded, failed };\r\n}\r\n","/**\r\n * SessionStore — persistence abstraction for coding sessions.\r\n *\r\n * Backends:\r\n * - SessionSqliteStore — canonical store, uses shared DB handle from sqlite-db.ts\r\n * - SessionGracefulDegrade — no-op fallback when SQLite is unavailable\r\n *\r\n * Phase 2 debt-zero: SQLite is the only canonical store for sessions.\r\n * JSON files are migration source only. No writable JSON fallback exists.\r\n */\r\n\r\nimport type { Session } from '../types.js';\r\nimport { getDatabase } from './sqlite-db.js';\r\nimport { loadSessionsJson } from './persistence.js';\r\nimport path from 'node:path';\r\nimport fs from 'node:fs';\r\n\r\n// ── Interface ───────────────────────────────────────────────────────\r\n\r\nexport interface SessionStoreInterface {\r\n init(dataDir: string): Promise<void>;\r\n loadAll(): Promise<Session[]>;\r\n loadByProject(projectId: string): Promise<Session[]>;\r\n loadActive(projectId: string): Promise<Session[]>;\r\n insert(session: Session): Promise<void>;\r\n update(session: Session): Promise<void>;\r\n bulkUpdate(sessions: Session[]): Promise<void>;\r\n /**\r\n * Atomic rollover: complete all active sessions for the given project IDs\r\n * and insert a new active session in a single transaction.\r\n * Guarantees at most one active session per project.\r\n */\r\n atomicRolloverInsert(newSession: Session, projectIds: string[], now: string): Promise<number>;\r\n getBackendName(): 'sqlite' | 'degraded';\r\n}\r\n\r\n// ── Row <-> Session serialization ───────────────────────────────────\r\n\r\nfunction sessionToRow(session: Session): Record<string, unknown> {\r\n return {\r\n id: session.id,\r\n projectId: session.projectId,\r\n startedAt: session.startedAt,\r\n endedAt: session.endedAt ?? null,\r\n status: session.status,\r\n summary: session.summary ?? null,\r\n agent: session.agent ?? null,\r\n };\r\n}\r\n\r\nfunction rowToSession(row: any): Session {\r\n return {\r\n id: row.id,\r\n projectId: row.projectId,\r\n startedAt: row.startedAt,\r\n ...(row.endedAt ? { endedAt: row.endedAt } : {}),\r\n status: row.status ?? 'active',\r\n ...(row.summary ? { summary: row.summary } : {}),\r\n ...(row.agent ? { agent: row.agent } : {}),\r\n };\r\n}\r\n\r\n// ── SQLite Backend ──────────────────────────────────────────────────\r\n\r\nexport class SessionSqliteStore implements SessionStoreInterface {\r\n private db: any = null;\r\n private dataDir: string = '';\r\n\r\n private stmtInsert: any = null;\r\n private stmtSelectAll: any = null;\r\n private stmtSelectByProject: any = null;\r\n private stmtSelectActive: any = null;\r\n private _stmtCompleteActive: any = null;\r\n\r\n async init(dataDir: string): Promise<void> {\r\n this.dataDir = dataDir;\r\n this.db = getDatabase(dataDir);\r\n\r\n // Prepare statements\r\n this.stmtInsert = this.db.prepare(`\r\n INSERT OR REPLACE INTO sessions\r\n (id, projectId, startedAt, endedAt, status, summary, agent)\r\n VALUES\r\n (@id, @projectId, @startedAt, @endedAt, @status, @summary, @agent)\r\n `);\r\n this.stmtSelectAll = this.db.prepare(`SELECT * FROM sessions ORDER BY startedAt DESC`);\r\n this.stmtSelectByProject = this.db.prepare(`SELECT * FROM sessions WHERE projectId = ? ORDER BY startedAt DESC`);\r\n this.stmtSelectActive = this.db.prepare(`SELECT * FROM sessions WHERE projectId = ? AND status = 'active' ORDER BY startedAt DESC`);\r\n\r\n // One-time migration from sessions.json\r\n await this.migrateFromJsonIfNeeded();\r\n }\r\n\r\n // ── Migration ────────────────────────────────────────────────────\r\n\r\n private async migrateFromJsonIfNeeded(): Promise<void> {\r\n const count = this.db.prepare(`SELECT COUNT(*) AS cnt FROM sessions`).get();\r\n if (count.cnt > 0) return;\r\n\r\n const jsonPath = path.join(this.dataDir, 'sessions.json');\r\n if (!fs.existsSync(jsonPath)) return;\r\n\r\n try {\r\n const raw = fs.readFileSync(jsonPath, 'utf-8');\r\n const sessions: Session[] = JSON.parse(raw);\r\n if (!Array.isArray(sessions) || sessions.length === 0) return;\r\n\r\n console.error(`[memorix] Migrating ${sessions.length} sessions from JSON to SQLite...`);\r\n\r\n const insertMany = this.db.transaction((list: Session[]) => {\r\n for (const s of list) {\r\n this.stmtInsert.run(sessionToRow(s));\r\n }\r\n });\r\n insertMany(sessions);\r\n\r\n console.error(`[memorix] Sessions migration complete. ${sessions.length} sessions now in SQLite.`);\r\n } catch (err) {\r\n console.error(`[memorix] Sessions JSON->SQLite migration failed (non-fatal): ${err}`);\r\n }\r\n }\r\n\r\n // ── Public read ──────────────────────────────────────────────────\r\n\r\n async loadAll(): Promise<Session[]> {\r\n return this.stmtSelectAll.all().map(rowToSession);\r\n }\r\n\r\n async loadByProject(projectId: string): Promise<Session[]> {\r\n return this.stmtSelectByProject.all(projectId).map(rowToSession);\r\n }\r\n\r\n async loadActive(projectId: string): Promise<Session[]> {\r\n return this.stmtSelectActive.all(projectId).map(rowToSession);\r\n }\r\n\r\n // ── Public write ─────────────────────────────────────────────────\r\n\r\n async insert(session: Session): Promise<void> {\r\n this.stmtInsert.run(sessionToRow(session));\r\n }\r\n\r\n async update(session: Session): Promise<void> {\r\n this.stmtInsert.run(sessionToRow(session)); // INSERT OR REPLACE\r\n }\r\n\r\n async bulkUpdate(sessions: Session[]): Promise<void> {\r\n const run = this.db.transaction((list: Session[]) => {\r\n for (const s of list) {\r\n this.stmtInsert.run(sessionToRow(s));\r\n }\r\n });\r\n run(sessions);\r\n }\r\n\r\n /**\r\n * Atomic rollover: complete all active sessions for the given project IDs\r\n * and insert a new active session in a single SQLite transaction.\r\n * SQLite serializes write transactions, so concurrent calls are safely sequenced.\r\n */\r\n async atomicRolloverInsert(newSession: Session, projectIds: string[], now: string): Promise<number> {\r\n if (!this._stmtCompleteActive) {\r\n this._stmtCompleteActive = this.db.prepare(\r\n `UPDATE sessions SET status = 'completed', endedAt = @now, summary = COALESCE(NULLIF(summary, ''), '(session ended implicitly by new session start)') WHERE projectId = @pid AND status = 'active'`\r\n );\r\n }\r\n const stmtComplete = this._stmtCompleteActive;\r\n const stmtIns = this.stmtInsert;\r\n\r\n const result = this.db.transaction(() => {\r\n let completedCount = 0;\r\n for (const pid of projectIds) {\r\n const info = stmtComplete.run({ pid, now });\r\n completedCount += info.changes;\r\n }\r\n stmtIns.run(sessionToRow(newSession));\r\n return completedCount;\r\n })();\r\n return result;\r\n }\r\n\r\n getBackendName(): 'sqlite' | 'degraded' {\r\n return 'sqlite';\r\n }\r\n}\r\n\r\n// ── Graceful Degrade Fallback ────────────────────────────────────────\r\n//\r\n// Phase 2 debt-zero rule: sessions have NO writable JSON fallback.\r\n// In JSON-only environments (no better-sqlite3), reads return empty\r\n// and writes are no-ops with a warning.\r\n\r\nexport class SessionGracefulDegrade implements SessionStoreInterface {\r\n private warned = false;\r\n\r\n private warn(): void {\r\n if (!this.warned) {\r\n console.error('[memorix] SessionStore: SQLite unavailable — sessions are disabled (read-only empty). Install better-sqlite3 for full functionality.');\r\n this.warned = true;\r\n }\r\n }\r\n\r\n async init(_dataDir: string): Promise<void> {\r\n this.warn();\r\n }\r\n\r\n async loadAll(): Promise<Session[]> { return []; }\r\n async loadByProject(_projectId: string): Promise<Session[]> { return []; }\r\n async loadActive(_projectId: string): Promise<Session[]> { return []; }\r\n\r\n async insert(_session: Session): Promise<void> { this.warn(); }\r\n async update(_session: Session): Promise<void> { this.warn(); }\r\n async bulkUpdate(_sessions: Session[]): Promise<void> { this.warn(); }\r\n async atomicRolloverInsert(_newSession: Session, _projectIds: string[], _now: string): Promise<number> { this.warn(); return 0; }\r\n\r\n getBackendName(): 'sqlite' | 'degraded' { return 'degraded'; }\r\n}\r\n\r\n// ── Singleton access ────────────────────────────────────────────────\r\n\r\nlet _store: SessionStoreInterface | null = null;\r\nlet _storeDataDir: string | null = null;\r\n\r\nexport function getSessionStore(): SessionStoreInterface {\r\n if (!_store) {\r\n throw new Error('[memorix] SessionStore not initialized — call initSessionStore() first');\r\n }\r\n return _store;\r\n}\r\n\r\nexport function resetSessionStore(): void {\r\n _store = null;\r\n _storeDataDir = null;\r\n}\r\n\r\nexport async function initSessionStore(dataDir: string): Promise<SessionStoreInterface> {\r\n if (_store && _storeDataDir === dataDir) return _store;\r\n\r\n _store = null;\r\n _storeDataDir = null;\r\n\r\n // Try SQLite first\r\n try {\r\n const store = new SessionSqliteStore();\r\n await store.init(dataDir);\r\n _store = store;\r\n _storeDataDir = dataDir;\r\n return store;\r\n } catch (err) {\r\n console.error(`[memorix] SessionSqliteStore unavailable, running in degraded read-only mode: ${err instanceof Error ? err.message : err}`);\r\n }\r\n\r\n // Fallback: graceful degrade (no writable JSON backend per debt-zero rule)\r\n const store = new SessionGracefulDegrade();\r\n await store.init(dataDir);\r\n _store = store;\r\n _storeDataDir = dataDir;\r\n return store;\r\n}\r\n","/**\r\n * Disclosure Policy\r\n *\r\n * Lightweight helper that classifies an observation or index entry into\r\n * an L1 / L2 / L3 disclosure layer based on its provenance fields.\r\n *\r\n * Rules (phase 2 first-cut):\r\n * L2 — default working-context: explicit, undefined, or core-valued\r\n * L1 — routing signal: hook auto-captures (non-core)\r\n * L3 — evidence layer: git-ingest (non-core), or any other low-trust source\r\n *\r\n * git-ingest defaults to L3 but can be promoted to L2 by valueCategory=core.\r\n * Rules are kept explicit and easy to extend in future phases.\r\n */\r\n\r\nexport type DisclosureLayer = 'L1' | 'L2' | 'L3';\r\n\r\n/**\r\n * Evidence basis: how well-grounded a memory is in verifiable sources.\r\n *\r\n * Computed from existing fields — not stored separately.\r\n * 'repository' — directly backed by a git commit or repository evidence\r\n * 'synthesized' — explicit agent analysis that cites repository evidence\r\n * via relatedCommits (no direct commitHash — not raw evidence)\r\n * 'direct' — explicitly agent-recorded, no git backing\r\n * undefined — hook trace, legacy, or unknown origin → neutral\r\n */\r\nexport type EvidenceBasis = 'repository' | 'synthesized' | 'direct' | undefined;\r\n\r\n/**\r\n * Derive the evidence basis from existing provenance fields.\r\n * Conservative: only labels what can be clearly determined.\r\n * Neutral (undefined) is preferred over incorrect labeling.\r\n */\r\nexport function resolveEvidenceBasis(fields: {\r\n sourceDetail?: string;\r\n source?: string;\r\n commitHash?: string;\r\n relatedCommits?: string[];\r\n}): EvidenceBasis {\r\n // Repository-backed: commitHash present = direct git evidence (highest confidence).\r\n // Also covers git-ingest source and legacy source='git'.\r\n if (\r\n fields.commitHash ||\r\n fields.source === 'git' ||\r\n fields.sourceDetail === 'git-ingest'\r\n ) {\r\n return 'repository';\r\n }\r\n // Synthesized: explicit agent analysis that cites commits via relatedCommits,\r\n // but has no direct commitHash (so it is analysis OF repository evidence, not raw evidence).\r\n // Conservative: requires explicit sourceDetail, relatedCommits present, no commitHash.\r\n if (\r\n fields.sourceDetail === 'explicit' &&\r\n (fields.relatedCommits?.length ?? 0) > 0\r\n ) {\r\n return 'synthesized';\r\n }\r\n // relatedCommits without explicit sourceDetail — legacy or unknown → repository fallback.\r\n if ((fields.relatedCommits?.length ?? 0) > 0) {\r\n return 'repository';\r\n }\r\n // Direct: explicitly agent-recorded, no git backing\r\n if (fields.sourceDetail === 'explicit') return 'direct';\r\n // Hook trace, manual, legacy, unknown → neutral\r\n return undefined;\r\n}\r\n\r\n/**\r\n * Return a compact one-line verification annotation for provenance headers.\r\n * Returns empty string when basis is 'direct' or undefined (not shown to avoid noise).\r\n * The commit hash is shown only in the detail path (commitHash present).\r\n */\r\nexport function evidenceBasisLine(basis: EvidenceBasis, commitHash?: string): string {\r\n if (basis === 'repository') {\r\n const commit = commitHash ? ` — commit ${commitHash.substring(0, 7)}` : '';\r\n return `[OK] Repository-backed${commit}`;\r\n }\r\n if (basis === 'synthesized') {\r\n return '[SYNTHESIZED] Synthesized — explicit analysis citing repository evidence';\n }\r\n return '';\r\n}\r\n\r\nexport interface ProvenanceFields {\r\n sourceDetail?: string;\r\n valueCategory?: string;\r\n /** Legacy fallback: observations ingested before Phase 1 only have source='git'. */\r\n source?: string;\r\n}\r\n\r\n/**\r\n * Resolve the effective sourceDetail for an observation, supporting legacy\r\n * observations that only have source='git' and no sourceDetail.\r\n *\r\n * This is the single fallback point — call this instead of reading sourceDetail\r\n * directly whenever provenance classification or display is needed.\r\n */\r\nexport function resolveSourceDetail(\r\n sourceDetail?: string,\r\n source?: string,\r\n): 'explicit' | 'hook' | 'git-ingest' | undefined {\r\n if (sourceDetail === 'explicit' || sourceDetail === 'hook' || sourceDetail === 'git-ingest') {\r\n return sourceDetail;\r\n }\r\n // Legacy git memories: source='git' with no sourceDetail → treat as git-ingest.\r\n if (source === 'git') return 'git-ingest';\r\n return undefined;\r\n}\r\n\r\n/**\r\n * Classify a single observation or index entry into a disclosure layer.\r\n */\r\nexport function classifyLayer(fields: ProvenanceFields): DisclosureLayer {\r\n const { valueCategory } = fields;\r\n const sd = resolveSourceDetail(fields.sourceDetail, fields.source);\r\n\r\n // Core-valued memories are always promoted to L2, regardless of source.\r\n if (valueCategory === 'core') return 'L2';\r\n\r\n // Hook auto-captures without core classification → L1 routing signal.\r\n if (sd === 'hook') return 'L1';\r\n\r\n // Git-ingest (including legacy source='git') defaults to L3.\r\n if (sd === 'git-ingest') return 'L3';\r\n\r\n // Explicit, undefined/legacy, manual → L2 working context.\r\n return 'L2';\r\n}\r\n\r\n/**\r\n * Return a compact source badge string for display in search tables.\r\n * Accepts both sourceDetail and legacy source for fallback resolution.\r\n * Keeps existing table structure stable — fits in a narrow column.\r\n */\r\nexport function sourceBadge(sourceDetail?: string, source?: string): string {\r\n const sd = resolveSourceDetail(sourceDetail, source);\r\n if (sd === 'explicit') return 'ex';\r\n if (sd === 'hook') return 'hk';\r\n if (sd === 'git-ingest') return 'git';\r\n return '';\r\n}\r\n","/**\r\n * Project Detector\r\n *\r\n * Strict .git-based project detection.\r\n * No .git = not a project. No fallbacks, no accommodations.\r\n *\r\n * ID strategy:\r\n * - .git + remote → normalizeGitRemote(remote) (globally unique, e.g. \"user/repo\")\r\n * - .git + no remote → \"local/<dirname>\" (local git repo, no remote yet)\r\n * - no .git → null (not a project)\r\n */\r\n\r\nimport { execSync } from 'node:child_process';\r\nimport { existsSync, readFileSync, readdirSync, statSync } from 'node:fs';\r\nimport path from 'node:path';\r\nimport type { ProjectInfo, DetectionResult, DetectionFailure } from '../types.js';\r\n\r\n/**\r\n * Detect the current project identity from Git.\r\n * Returns null if no .git directory is found — caller must handle this.\r\n * @param cwd - Working directory to detect from (defaults to process.cwd())\r\n */\r\nexport function detectProject(cwd?: string): ProjectInfo | null {\r\n return detectProjectWithDiagnostics(cwd).project;\r\n}\r\n\r\n/**\r\n * Detect project with full diagnostic info.\r\n * Returns both the project (if found) and a failure descriptor (if not).\r\n * Callers can use failure.reason to produce actionable error messages.\r\n */\r\nexport function detectProjectWithDiagnostics(cwd?: string): DetectionResult {\r\n const basePath = cwd ?? process.cwd();\r\n\r\n // Check: does the path exist?\r\n if (!existsSync(basePath)) {\r\n return {\r\n project: null,\r\n failure: { reason: 'path_not_found', path: basePath, detail: `Path does not exist: \"${basePath}\"` },\r\n };\r\n }\r\n\r\n // Check: is it a directory?\r\n try {\r\n if (!statSync(basePath).isDirectory()) {\r\n return {\r\n project: null,\r\n failure: { reason: 'not_a_directory', path: basePath, detail: `Path is not a directory: \"${basePath}\"` },\r\n };\r\n }\r\n } catch {\r\n return {\r\n project: null,\r\n failure: { reason: 'path_not_found', path: basePath, detail: `Cannot stat path: \"${basePath}\"` },\r\n };\r\n }\r\n\r\n // Check: git root\r\n const gitRootResult = getGitRootWithDiagnostics(basePath);\r\n if (!gitRootResult.root) {\r\n return {\r\n project: null,\r\n failure: gitRootResult.failure ?? {\r\n reason: 'no_git',\r\n path: basePath,\r\n detail: `No .git directory found in \"${basePath}\" or any parent directory.`,\r\n },\r\n };\r\n }\r\n\r\n const gitRoot = gitRootResult.root;\r\n const gitRemote = getGitRemote(gitRoot);\r\n\r\n if (gitRemote) {\r\n const id = normalizeGitRemote(gitRemote);\r\n const name = id.split('/').pop() ?? path.basename(gitRoot);\r\n return { project: { id, name, gitRemote, rootPath: gitRoot }, failure: null };\r\n }\r\n\r\n // Git repo without remote — local-only project\r\n const name = path.basename(gitRoot);\r\n const id = `local/${name}`;\r\n return { project: { id, name, rootPath: gitRoot }, failure: null };\r\n}\r\n\r\n/**\r\n * Get the Git repository root directory.\r\n * Returns null if not inside a git repository.\r\n */\r\nfunction getGitRoot(cwd: string): string | null {\r\n return getGitRootWithDiagnostics(cwd).root;\r\n}\r\n\r\n/**\r\n * Get git root with diagnostic failure info.\r\n * Distinguishes: no_git, git_worktree_error, git_safe_directory.\r\n */\r\nfunction getGitRootWithDiagnostics(cwd: string): { root: string | null; failure: DetectionFailure | null } {\r\n // Fast path: walk up to find .git directory (instant, no subprocess)\r\n let dir = path.resolve(cwd);\r\n const fsRoot = path.parse(dir).root;\r\n while (dir !== fsRoot) {\r\n const gitPath = path.join(dir, '.git');\r\n if (existsSync(gitPath)) {\r\n // .git may be a file (worktree) or directory (normal repo)\r\n try {\r\n const st = statSync(gitPath);\r\n if (st.isDirectory() || st.isFile()) return { root: dir, failure: null };\r\n } catch {\r\n return {\r\n root: null,\r\n failure: {\r\n reason: 'git_worktree_error',\r\n path: cwd,\r\n detail: `Found .git at \"${gitPath}\" but cannot stat it (permission denied or broken worktree link).`,\r\n },\r\n };\r\n }\r\n }\r\n dir = path.dirname(dir);\r\n }\r\n\r\n // Slow path: git CLI for edge cases (submodules, worktrees, bare repos)\r\n try {\r\n const root = execSync('git -c safe.directory=* rev-parse --show-toplevel', {\r\n cwd,\r\n encoding: 'utf-8',\r\n stdio: ['pipe', 'pipe', 'pipe'],\r\n timeout: 5000,\r\n }).trim();\r\n return root ? { root, failure: null } : { root: null, failure: null };\r\n } catch (err) {\r\n // Inspect stderr for known git error patterns\r\n const msg = err instanceof Error ? err.message : String(err);\r\n if (msg.includes('safe.directory') || msg.includes('dubious ownership')) {\r\n return {\r\n root: null,\r\n failure: {\r\n reason: 'git_safe_directory',\r\n path: cwd,\r\n detail: `Git refuses to operate in \"${cwd}\" due to ownership/safe.directory restrictions. ` +\r\n 'Run: git config --global --add safe.directory \"' + cwd + '\"',\r\n },\r\n };\r\n }\r\n return {\r\n root: null,\r\n failure: { reason: 'no_git', path: cwd, detail: `No git repository found at \"${cwd}\" or any parent directory.` },\r\n };\r\n }\r\n}\r\n\r\n/**\r\n * Get the Git remote URL for the given directory.\r\n * Returns null if not a git repository or no remote configured.\r\n */\r\nfunction getGitRemote(cwd: string): string | null {\r\n // Fast path: read .git/config directly (instant, no subprocess)\r\n const fsRemote = readGitConfigRemote(cwd);\r\n if (fsRemote) return fsRemote;\r\n\r\n // Slow path: git CLI for edge cases (submodules, worktrees, non-standard layouts)\r\n try {\r\n const remote = execSync('git -c safe.directory=* remote get-url origin', {\r\n cwd,\r\n encoding: 'utf-8',\r\n stdio: ['pipe', 'pipe', 'pipe'],\r\n timeout: 5000,\r\n }).trim();\r\n return remote || null;\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Fallback: parse remote.origin.url from .git/config when git CLI fails.\r\n * Handles Windows \"dubious ownership\" and other permission issues.\r\n */\r\nfunction readGitConfigRemote(cwd: string): string | null {\r\n try {\r\n const configPath = path.join(cwd, '.git', 'config');\r\n if (!existsSync(configPath)) return null;\r\n const content = readFileSync(configPath, 'utf-8');\r\n // Parse INI-style: [remote \"origin\"] section, url = ...\r\n const remoteMatch = content.match(/\\[remote\\s+\"origin\"\\]([\\s\\S]*?)(?=\\n\\[|$)/);\r\n if (!remoteMatch) return null;\r\n const urlMatch = remoteMatch[1].match(/^\\s*url\\s*=\\s*(.+)$/m);\r\n return urlMatch ? urlMatch[1].trim() : null;\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Detect if a directory is a \"system directory\" that's clearly not a user workspace.\r\n * These include Windows system dirs, IDE installation dirs, and temp dirs.\r\n */\r\nexport function isSystemDirectory(dir: string): boolean {\r\n const lower = dir.toLowerCase().replace(/\\\\/g, '/');\r\n return (\r\n lower.includes('/windows/') || lower.endsWith('/windows') ||\r\n lower.includes('/program files') ||\r\n lower.includes('/appdata/') ||\r\n // IDE installation directories\r\n /\\/(windsurf|cursor|code|vscode)\\/\\1/i.test(lower) ||\r\n /\\/windsurf\\b/i.test(lower) && !lower.includes('.windsurf') ||\r\n // Node / npm internal paths\r\n lower.includes('/node_modules/') ||\r\n lower.includes('/nvm') ||\r\n // System root\r\n /^[a-z]:\\/$/i.test(lower)\r\n );\r\n}\r\n\r\n/**\r\n * Scan immediate subdirectories for a .git directory.\r\n * Used when the workspace root itself isn't a git repo (multi-project workspace).\r\n * Returns the first subdirectory containing .git, or null.\r\n */\r\nexport function findGitInSubdirs(dir: string): string | null {\r\n try {\r\n const resolved = path.resolve(dir);\r\n const entries = readdirSync(resolved);\r\n for (const entry of entries) {\r\n if (entry.startsWith('.')) continue; // skip hidden dirs\r\n const fullPath = path.join(resolved, entry);\r\n try {\r\n if (statSync(fullPath).isDirectory() && existsSync(path.join(fullPath, '.git'))) {\r\n return fullPath;\r\n }\r\n } catch { /* permission error, skip */ }\r\n }\r\n } catch { /* readdir failed */ }\r\n return null;\r\n}\r\n\r\n/**\r\n * Normalize a Git remote URL to a consistent project ID.\r\n *\r\n * Examples:\r\n * https://github.com/user/repo.git → user/repo\r\n * git@github.com:user/repo.git → user/repo\r\n * ssh://git@github.com/user/repo → user/repo\r\n */\r\nfunction normalizeGitRemote(remote: string): string {\r\n let normalized = remote;\r\n\r\n // Remove trailing .git\r\n normalized = normalized.replace(/\\.git$/, '');\r\n\r\n // Handle SSH format: git@github.com:user/repo\r\n const sshMatch = normalized.match(/^[\\w-]+@[\\w.-]+:(.+)$/);\r\n if (sshMatch) {\r\n return sshMatch[1];\r\n }\r\n\r\n // Handle HTTPS/SSH URL format\r\n try {\r\n const url = new URL(normalized);\r\n // Remove leading slash\r\n return url.pathname.replace(/^\\//, '');\r\n } catch {\r\n // If URL parsing fails, take last two segments\r\n const segments = normalized.split('/').filter(Boolean);\r\n return segments.slice(-2).join('/');\r\n }\r\n}\r\n","/**\r\n * Memory Compact Engine\r\n *\r\n * Dual-mode memory management inspired by:\r\n * - Mem0's ADD/UPDATE/DELETE/NONE decision model with content merging\r\n * - Cipher's dual-mode architecture (LLM + heuristic fallback)\r\n *\r\n * Two paths:\r\n * 1. LLM mode (compactOnWrite): Single LLM call → extract facts + compare + decide + merge\r\n * 2. Free mode (heuristicCompact): Vector similarity → rule-based ADD/UPDATE/NONE\r\n *\r\n * Both paths produce a CompactDecision that the caller executes.\r\n */\r\n\r\nimport { callLLM, isLLMEnabled } from './provider.js';\r\n\r\n/** The decision the compact engine makes for each memory operation */\r\nexport type MemoryAction = 'ADD' | 'UPDATE' | 'DELETE' | 'NONE';\r\n\r\n/** Existing memory entry for comparison */\r\nexport interface ExistingMemory {\r\n id: number;\r\n title: string;\r\n narrative: string;\r\n facts: string;\r\n score: number;\r\n}\r\n\r\n/** The compact decision — what to do with the new memory */\r\nexport interface CompactDecision {\r\n action: MemoryAction;\r\n /** ID of existing memory to UPDATE/DELETE */\r\n targetId?: number;\r\n /** Brief explanation of why this action was chosen */\r\n reason: string;\r\n /** Merged narrative for UPDATE (Mem0-style rewrite) */\r\n mergedNarrative?: string;\r\n /** Merged facts for UPDATE */\r\n mergedFacts?: string[];\r\n /** LLM-extracted enriched facts (only in LLM mode) */\r\n enrichedFacts?: string[];\r\n /** Whether LLM was used for this decision */\r\n usedLLM: boolean;\r\n}\r\n\r\n/**\r\n * Unified Compact on Write prompt (Mem0-inspired, single LLM call).\r\n *\r\n * This prompt does 3 things in 1 call:\r\n * 1. Extract structured facts from the new content\r\n * 2. Compare with existing similar memories\r\n * 3. Decide ADD/UPDATE/DELETE/NONE and merge if needed\r\n */\r\nconst COMPACT_ON_WRITE_PROMPT = `You are a smart coding memory manager. You control the memory of a cross-IDE coding assistant.\r\n\r\nYou receive a NEW MEMORY to store and a list of EXISTING similar memories. Your job:\r\n1. Extract the key facts from the new memory\r\n2. Compare with existing memories\r\n3. Decide the best action\r\n\r\nActions:\r\n- ADD: New memory contains unique information. Store it as-is.\r\n- UPDATE: New memory supersedes or improves an existing one. Merge them into a single, comprehensive memory.\r\n- DELETE: An existing memory is outdated/contradicted by the new one. Remove it.\r\n- NONE: New memory is redundant. Existing memories already cover this. Skip storing.\r\n\r\nDecision rules:\r\n- Same topic updated (e.g., \"MySQL → PostgreSQL\"): UPDATE the old memory with merged content\r\n- Bug fixed that was reported as open: UPDATE the bug report to include the fix\r\n- Task completed that was tracked as in-progress: UPDATE to mark completed\r\n- Minor variation of existing memory: NONE (skip)\r\n- Completely new topic: ADD\r\n- Old info directly contradicted: DELETE the old one\r\n- Prefer UPDATE over ADD — keep memory count low, merge information\r\n\r\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.\r\n\r\nRespond in JSON only:\r\n{\r\n \"action\": \"ADD\" | \"UPDATE\" | \"DELETE\" | \"NONE\",\r\n \"targetId\": null or existing_memory_id_number,\r\n \"reason\": \"brief explanation of decision\",\r\n \"mergedNarrative\": \"merged narrative text (required for UPDATE, null otherwise)\",\r\n \"mergedFacts\": [\"merged fact 1\", \"merged fact 2\"] or null,\r\n \"extractedFacts\": [\"fact extracted from new content 1\", \"fact 2\"]\r\n}`;\r\n\r\n// ─── Heuristic Constants (Cipher-inspired) ───────────────────────────\r\n\r\n/** Similarity threshold above which we consider memories as \"same topic\" */\r\nconst SIMILARITY_HIGH = 0.75;\r\n/** Similarity threshold for \"related but different\" */\r\nconst SIMILARITY_MEDIUM = 0.5;\r\n\r\n// ─── LLM Mode ────────────────────────────────────────────────────────\r\n\r\n/**\r\n * Compact on Write — LLM mode.\r\n *\r\n * Single LLM call that extracts facts, compares with existing memories,\r\n * and decides ADD/UPDATE/DELETE/NONE with merged content.\r\n *\r\n * Inspired by Mem0's `get_update_memory_messages` but unified into 1 call.\r\n */\r\nexport async function compactOnWrite(\r\n newMemory: { title: string; narrative: string; facts: string[] },\r\n existingMemories: ExistingMemory[],\r\n): Promise<CompactDecision> {\r\n if (!isLLMEnabled()) {\r\n return heuristicCompact(newMemory, existingMemories);\r\n }\r\n\r\n if (existingMemories.length === 0) {\r\n return { action: 'ADD', reason: 'No existing memories to compare', usedLLM: false };\r\n }\r\n\r\n // Build the prompt with new + existing memories (Mem0's temp_uuid_mapping approach)\r\n const existingList = existingMemories\r\n .map(m => `[ID: ${m.id}] (similarity: ${m.score.toFixed(2)}) ${m.title}\\n Narrative: ${m.narrative}\\n Facts: ${m.facts}`)\r\n .join('\\n\\n');\r\n\r\n const userMessage = `NEW MEMORY:\r\nTitle: ${newMemory.title}\r\nNarrative: ${newMemory.narrative}\r\nFacts: ${newMemory.facts.join('; ')}\r\n\r\nEXISTING SIMILAR MEMORIES:\r\n${existingList}`;\r\n\r\n try {\r\n const response = await callLLM(COMPACT_ON_WRITE_PROMPT, userMessage);\r\n\r\n // Parse response — handle markdown code blocks\r\n let content = response.content.trim();\r\n if (content.startsWith('```')) {\r\n content = content.replace(/^```(?:json)?\\s*/, '').replace(/\\s*```$/, '');\r\n }\r\n\r\n const parsed = JSON.parse(content) as {\r\n action: string;\r\n targetId?: number | null;\r\n reason?: string;\r\n mergedNarrative?: string | null;\r\n mergedFacts?: string[] | null;\r\n extractedFacts?: string[] | null;\r\n };\r\n\r\n // Validate action\r\n const action = parsed.action?.toUpperCase() as MemoryAction;\r\n if (!action || !['ADD', 'UPDATE', 'DELETE', 'NONE'].includes(action)) {\r\n return { action: 'ADD', reason: 'LLM response invalid, defaulting to ADD', usedLLM: true };\r\n }\r\n\r\n // Validate targetId exists in existing memories for UPDATE/DELETE\r\n if ((action === 'UPDATE' || action === 'DELETE') && parsed.targetId != null) {\r\n const targetExists = existingMemories.some(m => m.id === parsed.targetId);\r\n if (!targetExists) {\r\n // LLM hallucinated an ID (common issue noted in Mem0's code)\r\n return { action: 'ADD', reason: `LLM referenced non-existent memory #${parsed.targetId}, defaulting to ADD`, usedLLM: true };\r\n }\r\n }\r\n\r\n return {\r\n action,\r\n targetId: parsed.targetId ?? undefined,\r\n reason: parsed.reason ?? 'LLM decision',\r\n mergedNarrative: parsed.mergedNarrative ?? undefined,\r\n mergedFacts: parsed.mergedFacts ?? undefined,\r\n enrichedFacts: parsed.extractedFacts ?? undefined,\r\n usedLLM: true,\r\n };\r\n } catch (err) {\r\n // LLM failed — fall back to heuristic\r\n console.error(`[memorix] LLM compact failed, falling back to heuristic:`, (err as Error)?.message ?? err);\r\n return heuristicCompact(newMemory, existingMemories);\r\n }\r\n}\r\n\r\n// ─── Free Mode (Heuristic) ───────────────────────────────────────────\r\n\r\n/**\r\n * Heuristic Compact — Free mode, no LLM needed.\r\n *\r\n * Uses vector similarity scores from search results to make decisions.\r\n * Inspired by Cipher's fallback logic in extract_and_operate_memory.ts.\r\n *\r\n * Decision logic:\r\n * - score >= 0.75: Very similar → check if new is more complete\r\n * - New is longer/richer → UPDATE (merge)\r\n * - Otherwise → NONE (skip, already covered)\r\n * - score >= 0.50: Related topic\r\n * - Same entity + same type → UPDATE if new has more facts\r\n * - Otherwise → ADD (different enough)\r\n * - score < 0.50: Different topic → ADD\r\n */\r\nexport function heuristicCompact(\r\n newMemory: { title: string; narrative: string; facts: string[] },\r\n existingMemories: ExistingMemory[],\r\n): CompactDecision {\r\n if (existingMemories.length === 0) {\r\n return { action: 'ADD', reason: 'No existing memories to compare', usedLLM: false };\r\n }\r\n\r\n const best = existingMemories[0]; // Already sorted by score\r\n\r\n // High similarity — very likely same topic\r\n if (best.score >= SIMILARITY_HIGH) {\r\n const newLength = newMemory.narrative.length + newMemory.facts.join(' ').length;\r\n const oldLength = best.narrative.length + best.facts.length;\r\n\r\n if (newLength > oldLength * 1.2) {\r\n // New memory is substantially richer — UPDATE with merged content\r\n const mergedNarrative = mergeTexts(best.narrative, newMemory.narrative);\r\n const mergedFacts = mergeFacts(best.facts, newMemory.facts.join('\\n'));\r\n return {\r\n action: 'UPDATE',\r\n targetId: best.id,\r\n reason: `New memory is more comprehensive (${newLength} > ${oldLength} chars)`,\r\n mergedNarrative,\r\n mergedFacts,\r\n usedLLM: false,\r\n };\r\n }\r\n\r\n // New memory is not richer — skip it\r\n return {\r\n action: 'NONE',\r\n targetId: best.id,\r\n reason: `Existing memory #${best.id} already covers this topic (similarity: ${best.score.toFixed(2)})`,\r\n usedLLM: false,\r\n };\r\n }\r\n\r\n // Medium similarity — related but might be different enough\r\n if (best.score >= SIMILARITY_MEDIUM) {\r\n const newFactCount = newMemory.facts.length;\r\n const oldFactCount = best.facts.split('\\n').filter(Boolean).length;\r\n\r\n if (newFactCount > oldFactCount) {\r\n // New has more facts — UPDATE\r\n const mergedNarrative = mergeTexts(best.narrative, newMemory.narrative);\r\n const mergedFacts = mergeFacts(best.facts, newMemory.facts.join('\\n'));\r\n return {\r\n action: 'UPDATE',\r\n targetId: best.id,\r\n reason: `New memory has more facts (${newFactCount} > ${oldFactCount}), merging`,\r\n mergedNarrative,\r\n mergedFacts,\r\n usedLLM: false,\r\n };\r\n }\r\n\r\n // Related but not richer — ADD as separate memory\r\n return { action: 'ADD', reason: `Related to #${best.id} but different enough to keep separate`, usedLLM: false };\r\n }\r\n\r\n // Low similarity — new topic\r\n return { action: 'ADD', reason: 'No similar memories found', usedLLM: false };\r\n}\r\n\r\n// ─── Content Merging Utilities ───────────────────────────────────────\r\n\r\n/**\r\n * Merge two narrative texts, keeping the more comprehensive version\r\n * while preserving unique information from both.\r\n */\r\nfunction mergeTexts(oldText: string, newText: string): string {\r\n // If new text is significantly longer, prefer it\r\n if (newText.length > oldText.length * 1.5) return newText;\r\n // If old text is significantly longer, append new info\r\n if (oldText.length > newText.length * 1.5) return oldText;\r\n // Similar length — combine with separator\r\n return `${newText}\\n\\n[Previous context]: ${oldText}`;\r\n}\r\n\r\n/**\r\n * Merge two fact lists, removing duplicates.\r\n * oldFacts is newline-separated string, newFacts is array.\r\n */\r\nfunction mergeFacts(oldFactsStr: string, newFactsStr: string): string[] {\r\n const oldFacts = oldFactsStr.split('\\n').filter(Boolean).map(f => f.trim());\r\n const newFacts = newFactsStr.split('\\n').filter(Boolean).map(f => f.trim());\r\n\r\n const seen = new Set<string>();\r\n const merged: string[] = [];\r\n\r\n // Add new facts first (they're more recent)\r\n for (const f of newFacts) {\r\n const normalized = f.toLowerCase();\r\n if (!seen.has(normalized)) {\r\n seen.add(normalized);\r\n merged.push(f);\r\n }\r\n }\r\n\r\n // Add old facts that aren't duplicates\r\n for (const f of oldFacts) {\r\n const normalized = f.toLowerCase();\r\n if (!seen.has(normalized)) {\r\n seen.add(normalized);\r\n merged.push(f);\r\n }\r\n }\r\n\r\n return merged;\r\n}\r\n\r\n// ─── Batch Dedup (for memorix_deduplicate tool) ──────────────────────\r\n\r\n/**\r\n * LLM-powered dedup for batch cleanup.\r\n * Compares a new memory against existing ones and returns a decision.\r\n * Used by memorix_deduplicate tool.\r\n */\r\nexport async function deduplicateMemory(\r\n newMemory: { title: string; narrative: string; facts: string[] },\r\n existingMemories: Array<{ id: number; title: string; narrative: string; facts: string }>,\r\n): Promise<CompactDecision | null> {\r\n if (!isLLMEnabled()) return null;\r\n if (existingMemories.length === 0) return { action: 'ADD', reason: 'No existing memories', usedLLM: false };\r\n\r\n const asExisting: ExistingMemory[] = existingMemories.map(m => ({\r\n ...m,\r\n score: 0.8, // Batch dedup assumes high similarity (pre-filtered)\r\n }));\r\n\r\n return compactOnWrite(newMemory, asExisting);\r\n}\r\n","/**\r\n * Memory Formation — Stage 1: Extract\r\n *\r\n * Enriches raw memory input with system-extracted facts, normalized titles,\r\n * resolved entity names, and verified observation types.\r\n *\r\n * Rules-based mode (no LLM):\r\n * - Fact extraction: key-value patterns, error messages, version numbers, paths\r\n * - Title normalization: replace generic titles with first meaningful sentence\r\n * - Entity resolution: match against existing Knowledge Graph entities\r\n * - Type inference: verify type matches content signals\r\n */\r\n\r\nimport type { ObservationType } from '../../types.js';\r\nimport type { FormationInput, ExtractResult } from './types.js';\r\n\r\n// ── Fact Extraction Patterns ──────────────────────────────────────\r\n\r\n/** Patterns that extract structured facts from narrative text */\r\nconst FACT_PATTERNS: Array<{ pattern: RegExp; format: (m: RegExpMatchArray) => string }> = [\r\n // Key: Value pairs (e.g., \"Port: 3000\", \"Timeout = 60s\")\r\n {\r\n pattern: /\\b([A-Z][a-zA-Z_-]{2,30})\\s*[:=]\\s*([^\\n,;]{2,60})/g,\r\n format: (m) => `${m[1]}: ${m[2].trim()}`,\r\n },\r\n // Arrow notation (e.g., \"MySQL -> PostgreSQL\", \"v1.0 -> v2.0\")\n {\n pattern: /\\b(\\S{2,30})\\s*(?:->|=>|>)\\s*(\\S{2,30})/g,\n format: (m) => `${m[1]} -> ${m[2]}`,\n },\n // Version numbers (e.g., \"v1.2.3\", \"version 2.0\")\r\n {\r\n pattern: /\\b(?:v(?:ersion)?\\s*)(\\d+\\.\\d+(?:\\.\\d+)?(?:-[\\w.]+)?)\\b/gi,\r\n format: (m) => `Version: ${m[1]}`,\r\n },\r\n // Error messages (e.g., \"Error: ...\", \"ERR_...\")\r\n {\r\n pattern: /\\b(?:Error|ERR|ENOENT|ECONNREFUSED|TypeError|RangeError|SyntaxError|ReferenceError)[:\\s]+([^\\n]{5,80})/gi,\r\n format: (m) => `Error: ${m[1].trim()}`,\r\n },\r\n // Port numbers in context\r\n {\r\n pattern: /\\b(?:port|PORT)\\s*[:=]?\\s*(\\d{2,5})\\b/gi,\r\n format: (m) => `Port: ${m[1]}`,\r\n },\r\n // Environment variables\r\n {\r\n pattern: /\\b([A-Z][A-Z0-9_]{3,30})\\s*=\\s*(\\S{1,60})/g,\r\n format: (m) => `${m[1]}=${m[2]}`,\r\n },\r\n // npm/package versions (e.g., \"react@18.2.0\")\r\n {\r\n pattern: /\\b([@a-z][\\w./-]+)@(\\d+\\.\\d+\\.\\d+(?:-[\\w.]+)?)\\b/g,\r\n format: (m) => `${m[1]}@${m[2]}`,\r\n },\r\n];\r\n\r\n/** Patterns indicating generic/low-quality titles that should be improved */\r\nconst GENERIC_TITLE_PATTERNS = [\r\n /^Updated \\S+\\.\\w+$/i,\r\n /^Created \\S+\\.\\w+$/i,\r\n /^Deleted \\S+\\.\\w+$/i,\r\n /^Modified \\S+\\.\\w+$/i,\r\n /^Changed \\S+\\.\\w+$/i,\r\n /^Session activity/i,\r\n /^Activity \\(/i,\r\n /^Used \\w+$/i,\r\n /^Ran: /i,\r\n];\r\n\r\n/** Content signals mapped to observation types */\r\nconst TYPE_SIGNALS: Array<{ type: ObservationType; patterns: RegExp[] }> = [\r\n {\r\n type: 'problem-solution',\r\n patterns: [\r\n /\\b(fix|fixed|bug|error|issue|crash|broken|resolved|workaround|patch)\\b/i,\r\n /\\b(修复|修正|解决|报错|崩溃|异常)\\b/,\r\n ],\r\n },\r\n {\r\n type: 'gotcha',\r\n patterns: [\r\n /\\b(gotcha|pitfall|trap|careful|warning|caveat|footgun|unexpected|beware)\\b/i,\r\n /\\b(坑|陷阱|注意|小心|踩坑)\\b/,\r\n ],\r\n },\r\n {\r\n type: 'decision',\r\n patterns: [\r\n /\\b(decided|chose|chosen|selected|adopted|rejected|evaluated|compared)\\b/i,\r\n /\\b(决定|选择|采用|弃用|对比|评估)\\b/,\r\n ],\r\n },\r\n {\r\n type: 'what-changed',\r\n patterns: [\r\n /\\b(changed|migrated|upgraded|refactored|replaced|renamed|moved|removed|added)\\b/i,\r\n /\\b(改|迁移|升级|重构|替换|重命名|删除|新增)\\b/,\r\n ],\r\n },\r\n {\r\n type: 'how-it-works',\r\n patterns: [\r\n /\\b(works by|architecture|mechanism|pipeline|flow|under the hood|internally)\\b/i,\r\n /\\b(原理|机制|流程|架构|内部)\\b/,\r\n ],\r\n },\r\n {\r\n type: 'trade-off',\r\n patterns: [\r\n /\\b(trade.?off|compromise|downside|cost|benefit|pro|con|versus|vs)\\b/i,\r\n /\\b(权衡|折中|代价|收益|优缺点)\\b/,\r\n ],\r\n },\r\n];\r\n\r\n// ── Extract Implementation ───────────────────────────────────────\r\n\r\n/**\r\n * Extract structured facts from narrative text using regex patterns.\r\n * Returns only facts not already present in the caller-provided list.\r\n */\r\nfunction extractFacts(narrative: string, existingFacts: string[]): string[] {\r\n const existingLower = new Set(existingFacts.map(f => f.toLowerCase().trim()));\r\n const extracted: string[] = [];\r\n const seen = new Set<string>();\r\n\r\n for (const { pattern, format } of FACT_PATTERNS) {\r\n pattern.lastIndex = 0;\r\n let match: RegExpExecArray | null;\r\n while ((match = pattern.exec(narrative)) !== null) {\r\n const fact = format(match);\r\n const normalized = fact.toLowerCase().trim();\r\n\r\n // Skip if already provided by caller or already extracted\r\n if (existingLower.has(normalized) || seen.has(normalized)) continue;\r\n\r\n // Skip very short or very long facts\r\n if (fact.length < 5 || fact.length > 120) continue;\r\n\r\n seen.add(normalized);\r\n extracted.push(fact);\r\n }\r\n }\r\n\r\n return extracted.slice(0, 10); // Cap at 10 system-extracted facts\r\n}\r\n\r\n/**\r\n * Improve a generic title by extracting the first meaningful sentence\r\n * from the narrative.\r\n */\r\nfunction improveTitle(title: string, narrative: string): { title: string; improved: boolean } {\r\n const isGeneric = GENERIC_TITLE_PATTERNS.some(p => p.test(title));\r\n if (!isGeneric) return { title, improved: false };\r\n\r\n // Try to extract first meaningful sentence from narrative\r\n const sentences = narrative\r\n .replace(/```[\\s\\S]*?```/g, '') // Remove code blocks\r\n .split(/[.。!!?\\n]/)\r\n .map(s => s.trim())\r\n .filter(s => s.length >= 15);\r\n\r\n if (sentences.length > 0) {\r\n return { title: sentences[0].slice(0, 60), improved: true };\r\n }\r\n\r\n return { title, improved: false };\r\n}\r\n\r\n/**\r\n * Resolve entity name against existing Knowledge Graph entities.\r\n * If a close match is found, use the canonical entity name.\r\n */\r\nfunction resolveEntity(\r\n entityName: string,\r\n existingEntities: string[],\r\n): { entityName: string; resolved: boolean } {\r\n if (existingEntities.length === 0) return { entityName, resolved: false };\r\n\r\n const lower = entityName.toLowerCase().replace(/[-_]/g, '');\r\n\r\n for (const existing of existingEntities) {\r\n const existingLower = existing.toLowerCase().replace(/[-_]/g, '');\r\n\r\n // Exact match (case-insensitive, ignoring hyphens/underscores)\r\n if (lower === existingLower) {\r\n return { entityName: existing, resolved: existing !== entityName };\r\n }\r\n\r\n // Substring match: one contains the other (e.g., \"auth\" matches \"auth-module\")\r\n if (lower.length >= 3 && existingLower.length >= 3) {\r\n if (existingLower.includes(lower) || lower.includes(existingLower)) {\r\n // Prefer the longer (more specific) name\r\n const canonical = existing.length >= entityName.length ? existing : entityName;\r\n return { entityName: canonical, resolved: canonical !== entityName };\r\n }\r\n }\r\n }\r\n\r\n return { entityName, resolved: false };\r\n}\r\n\r\n/**\r\n * Verify observation type against content signals.\r\n * If content strongly suggests a different type, correct it.\r\n */\r\nfunction verifyType(\r\n declaredType: ObservationType,\r\n narrative: string,\r\n title: string,\r\n): { type: ObservationType; corrected: boolean } {\r\n const content = `${title} ${narrative}`;\r\n\r\n // Score each type by counting individual keyword hits across all patterns\r\n const scores: Array<{ type: ObservationType; score: number }> = [];\r\n for (const { type, patterns } of TYPE_SIGNALS) {\r\n let score = 0;\r\n for (const p of patterns) {\r\n // Use matchAll to count individual keyword matches\r\n const regex = new RegExp(p.source, p.flags.includes('g') ? p.flags : p.flags + 'g');\r\n const matches = [...content.matchAll(regex)];\r\n score += matches.length;\r\n }\r\n if (score > 0) scores.push({ type, score });\r\n }\r\n\r\n if (scores.length === 0) return { type: declaredType, corrected: false };\r\n\r\n // Sort by score descending\r\n scores.sort((a, b) => b.score - a.score);\r\n const best = scores[0];\r\n\r\n // Only correct if the best match is significantly stronger than declared type\r\n // Requires: best type has >= 2 keyword hits AND declared type has 0 signals\r\n if (best.type !== declaredType && best.score >= 2) {\r\n const declaredScore = scores.find(s => s.type === declaredType)?.score ?? 0;\r\n if (declaredScore === 0) {\r\n return { type: best.type, corrected: true };\r\n }\r\n }\r\n\r\n return { type: declaredType, corrected: false };\r\n}\r\n\r\n// ── LLM Fact Extraction ─────────────────────────────────────────\r\n\r\n/** Prompt for LLM-based fact extraction (inspired by Mem0's approach) */\r\nconst LLM_EXTRACT_PROMPT = `You are a Software Engineering Knowledge Extractor.\r\nExtract structured facts from the given development context.\r\n\r\nFocus on:\r\n1. Technical decisions and their reasoning\r\n2. Bug root causes and fixes\r\n3. Configuration values (ports, versions, env vars)\r\n4. Architecture patterns and constraints\r\n5. Gotchas, pitfalls, and workarounds\r\n6. File paths and their roles\r\n\r\nRules:\r\n- Return ONLY a JSON object with a \"facts\" key containing an array of strings\r\n- Each fact should be a concise, self-contained statement\r\n- Include specific values (versions, ports, paths) when present\r\n- Detect the language of the input and record facts in the same language\r\n- If no meaningful facts exist, return {\"facts\": []}\r\n- Do NOT include trivial information (file read, directory listing)\r\n- Maximum 10 facts\r\n\r\nExample:\r\nInput: \"Fixed Redis connection leak. The pool wasn't being closed on shutdown. Added defer pool.Close() in main.go. Port 6379.\"\r\nOutput: {\"facts\": [\"Redis connection leak caused by pool not closed on shutdown\", \"Fix: added defer pool.Close() in main.go\", \"Redis port: 6379\"]}`;\r\n\r\n/**\r\n * Extract facts using LLM (Mem0-style structured extraction).\r\n * Returns extracted facts or empty array on failure.\r\n */\r\nasync function extractFactsWithLLM(\r\n narrative: string,\r\n title: string,\r\n existingFacts: string[],\r\n): Promise<string[]> {\r\n try {\r\n const { callLLM } = await import('../../llm/provider.js');\r\n const input = `Title: ${title}\\nContent: ${narrative}${existingFacts.length > 0 ? `\\nAlready known facts (don't repeat): ${existingFacts.join('; ')}` : ''}`;\r\n const response = await callLLM(LLM_EXTRACT_PROMPT, input);\r\n const text = response.content.trim();\r\n\r\n // Parse JSON response\r\n const jsonMatch = text.match(/\\{[\\s\\S]*\\}/);\r\n if (!jsonMatch) return [];\r\n const parsed = JSON.parse(jsonMatch[0]);\r\n const facts = parsed.facts;\r\n if (!Array.isArray(facts)) return [];\r\n\r\n // Filter: remove duplicates with existing facts\r\n const existingLower = new Set(existingFacts.map(f => f.toLowerCase().trim()));\r\n return facts\r\n .filter((f: unknown): f is string => typeof f === 'string' && f.length >= 5)\r\n .filter((f: string) => !existingLower.has(f.toLowerCase().trim()))\r\n .slice(0, 10);\r\n } catch {\r\n return []; // LLM failure → fall back to rules\r\n }\r\n}\r\n\r\n// ── Public API ───────────────────────────────────────────────────\r\n\r\n/**\r\n * Run Stage 1: Extract.\r\n *\r\n * Enriches raw input with system-extracted facts, normalized titles,\r\n * resolved entities, and verified types.\r\n *\r\n * When useLLM=true, uses LLM for fact extraction (Mem0-style).\r\n * Falls back to rules-based extraction on LLM failure.\r\n */\r\nexport async function runExtract(\r\n input: FormationInput,\r\n existingEntities: string[],\r\n useLLM = false,\r\n): Promise<ExtractResult> {\r\n const callerFacts = input.facts ?? [];\r\n\r\n // 1. Extract facts from narrative\r\n let extractedFacts: string[];\r\n if (useLLM) {\r\n // LLM extraction (quality-first, Mem0-style)\r\n extractedFacts = await extractFactsWithLLM(input.narrative, input.title, callerFacts);\r\n // If LLM returned nothing, fall back to rules\r\n if (extractedFacts.length === 0) {\r\n extractedFacts = extractFacts(input.narrative, callerFacts);\r\n }\r\n } else {\r\n // Rules-based extraction (free mode)\r\n extractedFacts = extractFacts(input.narrative, callerFacts);\r\n }\r\n const allFacts = [...callerFacts, ...extractedFacts];\r\n\r\n // 2. Improve title if generic\r\n const { title, improved: titleImproved } = improveTitle(input.title, input.narrative);\r\n\r\n // 3. Resolve entity name\r\n const { entityName, resolved: entityResolved } = resolveEntity(\r\n input.entityName,\r\n existingEntities,\r\n );\r\n\r\n // 4. Verify observation type\r\n const { type, corrected: typeCorrected } = verifyType(\r\n input.type,\r\n input.narrative,\r\n input.title,\r\n );\r\n\r\n return {\r\n title,\r\n titleImproved,\r\n narrative: input.narrative,\r\n facts: allFacts,\r\n extractedFacts,\r\n entityName,\r\n entityResolved,\r\n type,\r\n typeCorrected,\r\n };\r\n}\r\n","/**\r\n * Memory Formation — Stage 2: Resolve\r\n *\r\n * Determines what to do with an enriched memory: create new, merge into\r\n * existing, evolve (supersede), or discard as redundant.\r\n *\r\n * This stage absorbs and replaces the previous \"Compact on Write\" logic\r\n * (src/llm/memory-manager.ts) with a richer resolution model:\r\n *\r\n * - new: Truly new knowledge → proceed to store\r\n * - merge: Same topic as existing → UPDATE with combined content\r\n * - evolve: Existing is outdated → UPDATE with new content as primary\r\n * - discard: Redundant or noise → skip storage entirely\r\n *\r\n * Rules-based mode uses similarity scores, entity overlap, fact comparison,\r\n * and contradiction detection to make decisions without LLM.\r\n */\r\n\r\nimport type { ExtractResult, ResolveResult, SearchHit, ExistingMemoryRef } from './types.js';\r\n\r\n// ── Thresholds ───────────────────────────────────────────────────\r\n\r\n/** Above this: very likely same topic */\r\nconst SIMILARITY_HIGH = 0.75;\r\n/** Above this: related topic */\r\nconst SIMILARITY_MEDIUM = 0.50;\r\n/** Above this: exact duplicate — discard */\r\nconst SIMILARITY_DUPLICATE = 0.90;\r\n\r\n// ── Content Comparison Utilities ─────────────────────────────────\r\n\r\n/**\r\n * Compute Jaccard similarity between two sets of normalized words.\r\n */\r\nfunction wordOverlap(a: string, b: string): number {\r\n const wordsA = new Set(a.toLowerCase().split(/\\s+/).filter(w => w.length > 2));\r\n const wordsB = new Set(b.toLowerCase().split(/\\s+/).filter(w => w.length > 2));\r\n if (wordsA.size === 0 || wordsB.size === 0) return 0;\r\n\r\n let intersection = 0;\r\n for (const w of wordsA) {\r\n if (wordsB.has(w)) intersection++;\r\n }\r\n return intersection / Math.max(wordsA.size, wordsB.size);\r\n}\r\n\r\n/**\r\n * Check if two entity names refer to the same concept.\r\n */\r\nfunction entitiesMatch(a: string, b: string): boolean {\r\n const na = a.toLowerCase().replace(/[-_]/g, '');\r\n const nb = b.toLowerCase().replace(/[-_]/g, '');\r\n if (na === nb) return true;\r\n if (na.length >= 3 && nb.length >= 3) {\r\n if (na.includes(nb) || nb.includes(na)) return true;\r\n }\r\n return false;\r\n}\r\n\r\n/**\r\n * Detect potential contradiction between old and new content.\r\n * Looks for negation patterns and opposing statements.\r\n */\r\nfunction hasContradiction(oldText: string, newText: string): boolean {\r\n // Simple heuristic: check for \"not X\" in new when \"X\" is in old\r\n const negationPatterns = [\r\n /\\bnot\\s+(\\w+)/gi,\r\n /\\bno longer\\b/i,\r\n /\\binstead of\\b/i,\r\n /\\breplaced\\b.*\\bwith\\b/i,\r\n /\\bremoved\\b/i,\r\n /\\bdeprecated\\b/i,\r\n /\\bobsolete\\b/i,\r\n /不再/,\r\n /已弃用/,\r\n /替换为/,\r\n /改为/,\r\n ];\r\n\r\n return negationPatterns.some(p => p.test(newText));\r\n}\r\n\r\n/**\r\n * Merge two narratives, keeping the most comprehensive version.\r\n */\r\nfunction mergeNarratives(oldNarrative: string, newNarrative: string): string {\r\n if (newNarrative.length > oldNarrative.length * 1.5) return newNarrative;\r\n if (oldNarrative.length > newNarrative.length * 1.5) return oldNarrative;\r\n return `${newNarrative}\\n\\n[Previous context]: ${oldNarrative}`;\r\n}\r\n\r\n/**\r\n * Merge two fact lists, deduplicating by normalized text.\r\n */\r\nfunction mergeFacts(oldFacts: string[], newFacts: string[]): string[] {\r\n const seen = new Set<string>();\r\n const merged: string[] = [];\r\n\r\n // New facts first (more recent)\r\n for (const f of newFacts) {\r\n const norm = f.toLowerCase().trim();\r\n if (!seen.has(norm) && f.trim().length > 0) {\r\n seen.add(norm);\r\n merged.push(f);\r\n }\r\n }\r\n for (const f of oldFacts) {\r\n const norm = f.toLowerCase().trim();\r\n if (!seen.has(norm) && f.trim().length > 0) {\r\n seen.add(norm);\r\n merged.push(f);\r\n }\r\n }\r\n\r\n return merged;\r\n}\r\n\r\n// ── LLM Resolution (Mem0-style) ───────────────────────────────\r\n\r\nconst LLM_RESOLVE_PROMPT = `You are a Memory Consolidation Manager for a software engineering knowledge base.\r\n\r\nYou must decide what to do with a NEW memory given EXISTING memories that are similar.\r\n\r\nOperations:\r\n- ADD: The new memory contains genuinely new information not present in existing memories.\r\n- UPDATE: The new memory adds to or refines an existing memory. Specify which existing memory ID to update.\r\n- DELETE: The new memory contradicts an existing memory. Specify which existing memory ID to delete.\r\n- NOOP: The new memory is redundant (already covered by existing memories). Skip storage.\r\n\r\nRules:\r\n- Return ONLY a JSON object\r\n- If UPDATE: merge the best information from both old and new\r\n- If DELETE: the new memory supersedes the old (contradiction detected)\r\n- Prefer UPDATE over ADD when the topic is the same but information differs\r\n- Prefer NOOP over ADD when the information is essentially the same\r\n\r\nResponse format:\r\n{\"action\": \"ADD|UPDATE|DELETE|NOOP\", \"targetId\": <number or null>, \"reason\": \"<brief explanation>\", \"mergedText\": \"<merged content for UPDATE, or null>\"}`;\r\n\r\nasync function resolveWithLLM(\r\n extracted: ExtractResult,\r\n hits: SearchHit[],\r\n getObservation: (id: number) => ExistingMemoryRef | null,\r\n): Promise<ResolveResult | null> {\r\n try {\r\n const { callLLM } = await import('../../llm/provider.js');\r\n\r\n // Build context for LLM\r\n const existingMemories = hits.slice(0, 5).map((h, i) => ({\r\n id: h.observationId,\r\n index: i,\r\n title: h.title,\r\n content: h.narrative.substring(0, 300),\r\n facts: h.facts.substring(0, 200),\r\n }));\r\n\r\n const input = `NEW MEMORY:\r\nTitle: ${extracted.title}\r\nContent: ${extracted.narrative.substring(0, 500)}\r\nFacts: ${extracted.facts.join('; ')}\r\n\r\nEXISTING MEMORIES:\r\n${existingMemories.map(m => `[ID:${m.id}] ${m.title} | ${m.content} | Facts: ${m.facts}`).join('\\n')}`;\r\n\r\n const response = await callLLM(LLM_RESOLVE_PROMPT, input);\r\n const text = response.content.trim();\r\n\r\n const jsonMatch = text.match(/\\{[\\s\\S]*\\}/);\r\n if (!jsonMatch) return null;\r\n const parsed = JSON.parse(jsonMatch[0]);\r\n\r\n const action = parsed.action?.toUpperCase();\r\n const targetId = parsed.targetId ? Number(parsed.targetId) : undefined;\r\n const reason = parsed.reason || 'LLM decision';\r\n\r\n if (action === 'NOOP') {\r\n return { action: 'discard', targetId, reason: `LLM: ${reason}` };\r\n }\r\n if (action === 'ADD') {\r\n return { action: 'new', reason: `LLM: ${reason}` };\r\n }\r\n if (action === 'UPDATE' && targetId) {\r\n const existing = getObservation(targetId);\r\n const oldFacts = existing?.facts ?? [];\r\n return {\r\n action: 'merge',\r\n targetId,\r\n reason: `LLM: ${reason}`,\r\n mergedNarrative: parsed.mergedText || mergeNarratives(existing?.narrative ?? '', extracted.narrative),\r\n mergedFacts: mergeFacts(oldFacts, extracted.facts),\r\n };\r\n }\r\n if (action === 'DELETE' && targetId) {\r\n const existing = getObservation(targetId);\r\n const oldFacts = existing?.facts ?? [];\r\n return {\r\n action: 'evolve',\r\n targetId,\r\n reason: `LLM: ${reason}`,\r\n mergedNarrative: extracted.narrative,\r\n mergedFacts: mergeFacts(oldFacts, extracted.facts),\r\n };\r\n }\r\n\r\n return null; // Unrecognized action\r\n } catch {\r\n return null; // LLM failure → fall back to rules\r\n }\r\n}\r\n\r\n// ── Resolve Implementation ───────────────────────────────────────\r\n\r\n/**\r\n * Score a candidate match for resolution.\r\n * Returns a composite score considering similarity, entity overlap, and content richness.\r\n */\r\nfunction scoreCandidate(\r\n extracted: ExtractResult,\r\n candidate: SearchHit,\r\n): { score: number; entityMatch: boolean; richer: boolean; contradiction: boolean } {\r\n const entityMatch = entitiesMatch(extracted.entityName, candidate.entityName);\r\n const contentOverlap = wordOverlap(\r\n `${extracted.title} ${extracted.narrative}`,\r\n `${candidate.title} ${candidate.narrative}`,\r\n );\r\n\r\n // Composite score: search similarity + entity match bonus + content overlap\r\n const score = candidate.score * 0.6\r\n + (entityMatch ? 0.2 : 0)\r\n + contentOverlap * 0.2;\r\n\r\n // Is new memory richer?\r\n const newLength = extracted.narrative.length + extracted.facts.join(' ').length;\r\n const oldLength = candidate.narrative.length + candidate.facts.length;\r\n const richer = newLength > oldLength * 1.15;\r\n\r\n const contradiction = hasContradiction(candidate.narrative, extracted.narrative);\r\n\r\n return { score, entityMatch, richer, contradiction };\r\n}\r\n\r\n/**\r\n * Run Stage 2: Resolve.\r\n *\r\n * Determines the resolution action for an enriched memory by comparing\r\n * it against existing memories found via search.\r\n */\r\nexport async function runResolve(\r\n extracted: ExtractResult,\r\n projectId: string,\r\n searchMemories: (query: string, limit: number, projectId: string) => Promise<SearchHit[]>,\r\n getObservation: (id: number) => ExistingMemoryRef | null,\r\n useLLM = false,\r\n): Promise<ResolveResult> {\r\n // Search for similar existing memories\r\n const query = `${extracted.title} ${extracted.narrative.substring(0, 200)}`;\r\n let hits: SearchHit[];\r\n try {\r\n hits = await searchMemories(query, 5, projectId);\r\n } catch {\r\n // Search failed — default to ADD\r\n return { action: 'new', reason: 'Search unavailable, defaulting to new' };\r\n }\r\n\r\n if (hits.length === 0) {\r\n return { action: 'new', reason: 'No similar existing memories found' };\r\n }\r\n\r\n // LLM-powered resolution (Mem0-style, quality-first)\r\n if (useLLM) {\r\n const llmResult = await resolveWithLLM(extracted, hits, getObservation);\r\n if (llmResult) return llmResult;\r\n // LLM failed → fall through to rules-based resolution\r\n }\r\n\r\n // Rules-based resolution (free mode fallback)\r\n const scored = hits.map(hit => ({\r\n hit,\r\n ...scoreCandidate(extracted, hit),\r\n }));\r\n\r\n // Sort by composite score descending\r\n scored.sort((a, b) => b.score - a.score);\r\n const best = scored[0];\r\n\r\n // ── Decision logic ──\r\n\r\n // Very high raw search similarity → likely duplicate (use raw score, not composite)\r\n if (best.hit.score >= SIMILARITY_DUPLICATE) {\r\n if (best.richer) {\r\n // New is richer → evolve (supersede)\r\n const existing = getObservation(best.hit.observationId);\r\n const oldFacts = existing?.facts ?? best.hit.facts.split('\\n').filter(Boolean);\r\n return {\r\n action: 'evolve',\r\n targetId: best.hit.observationId,\r\n reason: `Near-duplicate of #${best.hit.observationId} but richer content (score: ${best.score.toFixed(2)})`,\r\n mergedNarrative: mergeNarratives(best.hit.narrative, extracted.narrative),\r\n mergedFacts: mergeFacts(oldFacts, extracted.facts),\r\n };\r\n }\r\n return {\r\n action: 'discard',\r\n targetId: best.hit.observationId,\r\n reason: `Duplicate of #${best.hit.observationId} (score: ${best.score.toFixed(2)})`,\r\n };\r\n }\r\n\r\n // High similarity → same topic\r\n if (best.score >= SIMILARITY_HIGH) {\r\n if (best.contradiction) {\r\n // Content contradicts existing → evolve\r\n const existing = getObservation(best.hit.observationId);\r\n const oldFacts = existing?.facts ?? best.hit.facts.split('\\n').filter(Boolean);\r\n return {\r\n action: 'evolve',\r\n targetId: best.hit.observationId,\r\n reason: `Supersedes #${best.hit.observationId}: contradiction detected (score: ${best.score.toFixed(2)})`,\r\n mergedNarrative: extracted.narrative,\r\n mergedFacts: mergeFacts(oldFacts, extracted.facts),\r\n };\r\n }\r\n\r\n if (best.richer) {\r\n // New is richer → merge\r\n const existing = getObservation(best.hit.observationId);\r\n const oldFacts = existing?.facts ?? best.hit.facts.split('\\n').filter(Boolean);\r\n return {\r\n action: 'merge',\r\n targetId: best.hit.observationId,\r\n reason: `Merging with #${best.hit.observationId}: same topic, new content is richer (score: ${best.score.toFixed(2)})`,\r\n mergedNarrative: mergeNarratives(best.hit.narrative, extracted.narrative),\r\n mergedFacts: mergeFacts(oldFacts, extracted.facts),\r\n };\r\n }\r\n\r\n // Not richer → discard\r\n return {\r\n action: 'discard',\r\n targetId: best.hit.observationId,\r\n reason: `Already covered by #${best.hit.observationId} (score: ${best.score.toFixed(2)})`,\r\n };\r\n }\r\n\r\n // Medium similarity + entity match → merge\r\n if (best.score >= SIMILARITY_MEDIUM && best.entityMatch) {\r\n const existing = getObservation(best.hit.observationId);\r\n const oldFacts = existing?.facts ?? best.hit.facts.split('\\n').filter(Boolean);\r\n const newFactCount = extracted.facts.length;\r\n const oldFactCount = oldFacts.length;\r\n\r\n if (newFactCount > oldFactCount) {\r\n return {\r\n action: 'merge',\r\n targetId: best.hit.observationId,\r\n reason: `Same entity \"${extracted.entityName}\", new memory has more facts (${newFactCount} > ${oldFactCount})`,\r\n mergedNarrative: mergeNarratives(best.hit.narrative, extracted.narrative),\r\n mergedFacts: mergeFacts(oldFacts, extracted.facts),\r\n };\r\n }\r\n }\r\n\r\n // Low similarity or different entity → new memory\r\n return { action: 'new', reason: `Different from existing memories (best score: ${best.score.toFixed(2)})` };\r\n}\r\n","/**\r\n * Memory Formation — Stage 3: Evaluate\r\n *\r\n * Assesses the long-term knowledge value of a memory and classifies it\r\n * into one of three categories:\r\n *\r\n * - core: High-value reusable knowledge (decisions, gotchas, root causes)\r\n * - contextual: Moderately useful context (file changes, command results)\r\n * - ephemeral: Low-value process noise (trivial edits, status logs)\r\n *\r\n * The value score determines storage behavior:\r\n * - core (>= 0.7): Store with high importance, never auto-decay\r\n * - contextual (0.4-0.7): Store normally, subject to retention decay\r\n * - ephemeral (< 0.4): Discard or store with aggressive auto-decay\r\n */\r\n\r\nimport type { ObservationType } from '../../types.js';\r\nimport type { ExtractResult, EvaluateResult, ValueCategory } from './types.js';\r\n\r\n// ── Scoring Weights ──────────────────────────────────────────────\r\n\r\n/** Base value weight per observation type */\r\nconst TYPE_WEIGHTS: Record<ObservationType, number> = {\r\n 'gotcha': 0.85,\r\n 'decision': 0.80,\r\n 'problem-solution': 0.75,\r\n 'trade-off': 0.70,\r\n 'reasoning': 0.70,\r\n 'why-it-exists': 0.65,\r\n 'how-it-works': 0.60,\r\n 'discovery': 0.55,\r\n 'what-changed': 0.45,\r\n 'session-request': 0.40,\r\n};\r\n\r\n/** Patterns indicating high-specificity content (boost value) */\r\nconst SPECIFICITY_PATTERNS = [\r\n /\\b\\d+\\.\\d+\\.\\d+\\b/, // Semantic version numbers\r\n /\\b(ERR_|ENOENT|ECONNREFUSED|E[A-Z]{3,})\\b/, // Error codes\r\n /\\b(port|PORT)\\s*[:=]?\\s*\\d{2,5}\\b/i, // Port numbers\r\n /\\bhttps?:\\/\\/\\S+/, // URLs\r\n /`[^`]{3,60}`/, // Inline code references\r\n /\\b[A-Z][A-Z0-9_]{3,}\\b/, // Constants (e.g., MAX_RETRIES)\r\n /\\b\\d+\\s*(ms|s|sec|min|MB|GB|KB)\\b/i, // Measurements with units\r\n];\r\n\r\n/** Patterns indicating causal reasoning (boost value) */\r\nconst CAUSAL_PATTERNS = [\r\n /\\b(because|therefore|due to|caused by|as a result|fixed by|resolved by)\\b/i,\r\n /\\b(so that|in order to|leads to|results in|prevents)\\b/i,\r\n /(?:因为|所以|由于|导致|造成|因此|为了|解决)/,\r\n];\r\n\r\n/** Patterns indicating low-quality / noise content (reduce value) */\r\nconst NOISE_PATTERNS = [\r\n /^Session activity/i,\r\n /^Updated \\S+\\.\\w+$/i,\r\n /^Created \\S+\\.\\w+$/i,\r\n /^Deleted \\S+\\.\\w+$/i,\r\n /^File written successfully/i,\r\n /^Command executed/i,\r\n /^Tool: (read_file|list_dir|find_by_name)/i,\r\n /^\\s*$/,\r\n];\r\n\r\n/** Patterns indicating the content is just tool output, not knowledge */\r\nconst TOOL_OUTPUT_PATTERNS = [\r\n /^(file|directory|folder)\\s+(created|deleted|moved|copied)/i,\r\n /^Successfully\\s+(installed|updated|removed)/i,\r\n /^\\d+ files? changed/i,\r\n /^npm (WARN|notice)/i,\r\n /^\\s*at\\s+\\S+\\s+\\(/, // Stack trace lines\r\n];\r\n\r\n// ── Evaluation Implementation ────────────────────────────────────\r\n\r\n/**\r\n * Compute fact density: ratio of structured facts to narrative length.\r\n * Higher density = more structured, likely higher value.\r\n */\r\nfunction factDensity(facts: string[], narrativeLength: number): number {\r\n if (narrativeLength === 0) return 0;\r\n // Each fact is worth ~20 chars of \"structured knowledge\"\r\n const structuredChars = facts.reduce((sum, f) => sum + f.length, 0);\r\n return Math.min(1, structuredChars / Math.max(narrativeLength, 100));\r\n}\r\n\r\n/**\r\n * Count how many specificity indicators are present in the content.\r\n */\r\nfunction specificityScore(content: string): number {\r\n let count = 0;\r\n for (const p of SPECIFICITY_PATTERNS) {\r\n p.lastIndex = 0;\r\n if (p.test(content)) count++;\r\n }\r\n return Math.min(1, count / 3); // Normalize: 3+ indicators = max score\r\n}\r\n\r\n/**\r\n * Check if content contains causal reasoning.\r\n */\r\nfunction causalScore(content: string): number {\r\n let count = 0;\r\n for (const p of CAUSAL_PATTERNS) {\r\n p.lastIndex = 0;\r\n if (p.test(content)) count++;\r\n }\r\n return Math.min(1, count / 2); // Normalize: 2+ causal patterns = max\r\n}\r\n\r\n/**\r\n * Check if content matches noise patterns.\r\n */\r\nfunction noiseScore(title: string, narrative: string): number {\r\n let noisiness = 0;\r\n\r\n // Title noise\r\n for (const p of NOISE_PATTERNS) {\r\n if (p.test(title)) { noisiness += 0.3; break; }\r\n }\r\n\r\n // Narrative noise\r\n const lines = narrative.split('\\n').filter(l => l.trim().length > 0);\r\n let toolOutputLines = 0;\r\n for (const line of lines) {\r\n for (const p of TOOL_OUTPUT_PATTERNS) {\r\n if (p.test(line)) { toolOutputLines++; break; }\r\n }\r\n }\r\n if (lines.length > 0) {\r\n noisiness += (toolOutputLines / lines.length) * 0.5;\r\n }\r\n\r\n // Very short narrative with no facts\r\n if (narrative.length < 50) noisiness += 0.2;\r\n\r\n return Math.min(1, noisiness);\r\n}\r\n\r\n/**\r\n * Classify value score into a category.\r\n */\r\nfunction categorize(score: number): ValueCategory {\r\n if (score >= 0.6) return 'core';\r\n if (score >= 0.35) return 'contextual';\r\n return 'ephemeral';\r\n}\r\n\r\n/**\r\n * Build a human-readable reason string explaining the assessment.\r\n */\r\nfunction buildReason(\r\n typeWeight: number,\r\n factDens: number,\r\n specificity: number,\r\n causal: number,\r\n noise: number,\r\n category: ValueCategory,\r\n): string {\r\n const parts: string[] = [];\r\n\r\n if (typeWeight >= 0.7) parts.push('high-value type');\r\n else if (typeWeight <= 0.45) parts.push('low-value type');\r\n\r\n if (factDens > 0.3) parts.push('fact-dense');\r\n if (specificity > 0.3) parts.push('specific (versions/codes/paths)');\r\n if (causal > 0.3) parts.push('causal reasoning');\r\n if (noise > 0.3) parts.push('noisy content');\r\n\r\n const detail = parts.length > 0 ? parts.join(', ') : 'average content';\r\n return `${category}: ${detail}`;\r\n}\r\n\r\n// ── Public API ───────────────────────────────────────────────────\r\n\r\n/**\r\n * Run Stage 3: Evaluate.\r\n *\r\n * Assesses the knowledge value of an enriched memory using multi-factor\r\n * scoring. Returns a score (0-1), category, and explanation.\r\n */\r\nexport function runEvaluate(extracted: ExtractResult): EvaluateResult {\r\n const content = `${extracted.title} ${extracted.narrative} ${extracted.facts.join(' ')}`;\r\n\r\n // ── Factor scores ──\r\n const typeWeight = TYPE_WEIGHTS[extracted.type] ?? 0.5;\r\n const factDens = factDensity(extracted.facts, extracted.narrative.length);\r\n const specificity = specificityScore(content);\r\n const causal = causalScore(content);\r\n const noise = noiseScore(extracted.title, extracted.narrative);\r\n\r\n // ── Composite score ──\r\n // Weighted combination with noise as penalty\r\n // Type is the strongest signal (50%) — a gotcha or decision is inherently more valuable\r\n const rawScore = typeWeight * 0.50\r\n + factDens * 0.12\r\n + specificity * 0.12\r\n + causal * 0.12\r\n - noise * 0.14;\r\n\r\n // Bonus: system-extracted facts indicate the content has structure\r\n const extractionBonus = extracted.extractedFacts.length > 0 ? 0.05 : 0;\r\n\r\n // Bonus: title was improved (means original was generic → slightly penalize)\r\n const titlePenalty = extracted.titleImproved ? -0.03 : 0;\r\n\r\n // Bonus: type was auto-corrected (system found a better match → content has signals)\r\n const correctionBonus = extracted.typeCorrected ? 0.03 : 0;\r\n\r\n const score = Math.max(0, Math.min(1, rawScore + extractionBonus + titlePenalty + correctionBonus));\r\n const category = categorize(score);\r\n const reason = buildReason(typeWeight, factDens, specificity, causal, noise, category);\r\n\r\n return { score, category, reason };\r\n}\r\n","/**\r\n * Memory Formation Pipeline — Orchestrator\r\n *\r\n * Runs the three-stage pipeline: Extract → Resolve → Evaluate.\r\n *\r\n * Supports two execution modes:\r\n * - **Active mode**: Pipeline output drives storage decisions (replaces compact-on-write)\r\n * - **Shadow mode**: Pipeline runs in parallel with existing compact-on-write,\r\n * producing metrics for comparison without affecting storage\r\n *\r\n * Design: Pipeline is a pure function with injected dependencies (search, getObservation).\r\n * It does not import server.ts or storeObservation directly.\r\n */\r\n\r\nimport type {\r\n FormationInput,\r\n FormedMemory,\r\n FormationConfig,\r\n FormationMetrics,\r\n BeforeAfterMetrics,\r\n FormationStage,\r\n} from './types.js';\r\nimport { runExtract } from './extract.js';\r\nimport { runResolve } from './resolve.js';\r\nimport { runEvaluate } from './evaluate.js';\r\n\r\n// ── Shadow Mode Metrics Collection ──────────────────────────────\r\n\r\n/** In-memory metrics buffer for shadow mode analysis */\r\nconst metricsBuffer: FormationMetrics[] = [];\r\nconst MAX_METRICS_BUFFER = 500;\r\n\r\n/** In-memory before/after comparison metrics buffer */\r\nconst beforeAfterBuffer: Array<{\r\n formationAction: string;\r\n formationTargetId?: number;\r\n oldCompactAction: 'ADD' | 'UPDATE' | 'NONE' | 'DELETE';\r\n oldCompactTargetId?: number;\r\n oldCompactReason?: string;\r\n formationValueScore: number;\r\n formationValueCategory: string;\r\n formationDurationMs: number;\r\n compactDurationMs?: number;\r\n}> = [];\r\nconst MAX_BEFORE_AFTER_BUFFER = 500;\r\n\r\n/**\r\n * Get collected shadow mode metrics (for analysis/dashboard).\r\n */\r\nexport function getFormationMetrics(): readonly FormationMetrics[] {\r\n return metricsBuffer;\r\n}\r\n\r\n/**\r\n * Clear metrics buffer.\r\n */\r\nexport function clearFormationMetrics(): void {\r\n metricsBuffer.length = 0;\r\n}\r\n\r\n/**\r\n * Record before/after comparison metrics.\r\n */\r\nexport function recordBeforeAfterMetrics(data: {\r\n formationAction: string;\r\n formationTargetId?: number;\r\n oldCompactAction: 'ADD' | 'UPDATE' | 'NONE' | 'DELETE';\r\n oldCompactTargetId?: number;\r\n oldCompactReason?: string;\r\n formationValueScore: number;\r\n formationValueCategory: string;\r\n formationDurationMs: number;\r\n compactDurationMs?: number;\r\n}): void {\r\n if (beforeAfterBuffer.length >= MAX_BEFORE_AFTER_BUFFER) {\r\n beforeAfterBuffer.shift();\r\n }\r\n beforeAfterBuffer.push(data);\r\n}\r\n\r\n/**\r\n * Get before/after comparison metrics.\r\n */\r\nexport function getBeforeAfterMetrics(): BeforeAfterMetrics {\r\n const totalProcessed = beforeAfterBuffer.length;\r\n if (totalProcessed === 0) {\r\n return {\r\n totalProcessed: 0,\r\n agreements: 0,\r\n disagreements: 0,\r\n disagreementBreakdown: {\r\n formationDiscardedCompactAdded: 0,\r\n formationMergedCompactAdded: 0,\r\n formationAddedCompactDiscarded: 0,\r\n formationAddedCompactMerged: 0,\r\n formationEvolvedCompactAdded: 0,\r\n other: 0,\r\n },\r\n quality: {\r\n formationDiscardedLowValue: 0,\r\n formationMergedDuplicates: 0,\r\n formationEvolvedOutdated: 0,\r\n compactMissedDuplicates: 0,\r\n compactKeptLowValue: 0,\r\n },\r\n duration: {\r\n formationAvgMs: 0,\r\n compactAvgMs: 0,\r\n diffMs: 0,\r\n },\r\n };\r\n }\r\n\r\n let agreements = 0;\r\n let disagreements = 0;\r\n const disagreementBreakdown = {\r\n formationDiscardedCompactAdded: 0,\r\n formationMergedCompactAdded: 0,\r\n formationAddedCompactDiscarded: 0,\r\n formationAddedCompactMerged: 0,\r\n formationEvolvedCompactAdded: 0,\r\n other: 0,\r\n };\r\n const quality = {\r\n formationDiscardedLowValue: 0,\r\n formationMergedDuplicates: 0,\r\n formationEvolvedOutdated: 0,\r\n compactMissedDuplicates: 0,\r\n compactKeptLowValue: 0,\r\n };\r\n let formationTotalDuration = 0;\r\n let compactTotalDuration = 0;\r\n let compactDurationCount = 0;\r\n \r\n for (const data of beforeAfterBuffer) {\r\n formationTotalDuration += data.formationDurationMs;\r\n if (data.compactDurationMs !== undefined) {\r\n compactTotalDuration += data.compactDurationMs;\r\n compactDurationCount++;\r\n }\r\n\r\n // Determine if decisions agree\r\n const formationAction = data.formationAction;\r\n const oldCompactAction = data.oldCompactAction;\r\n\r\n // Map Formation actions to old compact actions for comparison\r\n let formationMapped: 'ADD' | 'UPDATE' | 'NONE' | 'DELETE' = 'ADD';\r\n if (formationAction === 'merge' || formationAction === 'evolve') {\r\n formationMapped = 'UPDATE';\r\n } else if (formationAction === 'discard') {\r\n formationMapped = 'NONE';\r\n }\r\n\r\n if (formationMapped === oldCompactAction) {\r\n agreements++;\r\n } else {\r\n disagreements++;\r\n // Track disagreement breakdown\r\n if (formationAction === 'discard' && oldCompactAction === 'ADD') {\r\n disagreementBreakdown.formationDiscardedCompactAdded++;\r\n if (data.formationValueCategory === 'ephemeral') {\r\n quality.formationDiscardedLowValue++;\r\n }\r\n } else if (formationAction === 'merge' && oldCompactAction === 'ADD') {\r\n disagreementBreakdown.formationMergedCompactAdded++;\r\n quality.formationMergedDuplicates++;\r\n } else if (formationAction === 'new' && oldCompactAction === 'NONE') {\r\n disagreementBreakdown.formationAddedCompactDiscarded++;\r\n quality.compactMissedDuplicates++;\r\n } else if (formationAction === 'new' && oldCompactAction === 'UPDATE') {\r\n disagreementBreakdown.formationAddedCompactMerged++;\r\n } else if (formationAction === 'evolve' && oldCompactAction === 'ADD') {\r\n disagreementBreakdown.formationEvolvedCompactAdded++;\r\n quality.formationEvolvedOutdated++;\r\n } else if (formationAction === 'new' && oldCompactAction === 'ADD') {\r\n // Formation decided to add, but compact also decided to add (should be rare)\r\n // This might indicate compact missed a duplicate or Formation was too conservative\r\n if (data.formationValueCategory === 'ephemeral') {\r\n quality.compactKeptLowValue++;\r\n }\r\n } else {\r\n disagreementBreakdown.other++;\r\n }\r\n }\r\n }\r\n\r\n const compactAvgMs = compactDurationCount > 0 ? compactTotalDuration / compactDurationCount : 0;\r\n const formationAvgMs = totalProcessed > 0 ? formationTotalDuration / totalProcessed : 0;\r\n\r\n return {\r\n totalProcessed,\r\n agreements,\r\n disagreements,\r\n disagreementBreakdown,\r\n quality,\r\n duration: {\r\n formationAvgMs,\r\n compactAvgMs,\r\n diffMs: compactAvgMs - formationAvgMs,\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * Get aggregated metrics summary.\r\n */\r\nexport function getMetricsSummary(): {\r\n total: number;\r\n avgValueScore: number;\r\n avgExtractedFacts: number;\r\n titleImprovedRate: number;\r\n entityResolvedRate: number;\r\n typeCorectedRate: number;\r\n resolutionBreakdown: Record<string, number>;\r\n categoryBreakdown: Record<string, number>;\r\n avgDurationMs: number;\r\n} {\r\n const total = metricsBuffer.length;\r\n if (total === 0) {\r\n return {\r\n total: 0,\r\n avgValueScore: 0,\r\n avgExtractedFacts: 0,\r\n titleImprovedRate: 0,\r\n entityResolvedRate: 0,\r\n typeCorectedRate: 0,\r\n resolutionBreakdown: {},\r\n categoryBreakdown: {},\r\n avgDurationMs: 0,\r\n };\r\n }\r\n\r\n const sum = (fn: (m: FormationMetrics) => number) =>\r\n metricsBuffer.reduce((s, m) => s + fn(m), 0);\r\n\r\n const resolutionBreakdown: Record<string, number> = {};\r\n const categoryBreakdown: Record<string, number> = {};\r\n for (const m of metricsBuffer) {\r\n resolutionBreakdown[m.resolutionAction] = (resolutionBreakdown[m.resolutionAction] ?? 0) + 1;\r\n categoryBreakdown[m.valueCategory] = (categoryBreakdown[m.valueCategory] ?? 0) + 1;\r\n }\r\n\r\n return {\r\n total,\r\n avgValueScore: sum(m => m.valueScore) / total,\r\n avgExtractedFacts: sum(m => m.systemExtractedFacts) / total,\r\n titleImprovedRate: sum(m => m.titleImproved ? 1 : 0) / total,\r\n entityResolvedRate: sum(m => m.entityResolved ? 1 : 0) / total,\r\n typeCorectedRate: sum(m => m.typeCorrected ? 1 : 0) / total,\r\n resolutionBreakdown,\r\n categoryBreakdown,\r\n avgDurationMs: sum(m => m.durationMs) / total,\r\n };\r\n}\r\n\r\n// ── Pipeline Orchestrator ────────────────────────────────────────\r\n\r\n/**\r\n * Run the Memory Formation Pipeline.\r\n *\r\n * Three stages:\r\n * 1. Extract: Enrich with system-extracted facts, normalize title/entity/type\r\n * 2. Resolve: Compare against existing memories, decide new/merge/evolve/discard\r\n * 3. Evaluate: Assess knowledge value (core/contextual/ephemeral)\r\n *\r\n * In shadow mode, metrics are collected but no storage decisions are enforced.\r\n */\r\nexport async function runFormation(\r\n input: FormationInput,\r\n config: FormationConfig,\r\n): Promise<FormedMemory> {\r\n const startTime = Date.now();\r\n let stagesCompleted = 0;\r\n const stageDurationsMs: Partial<Record<FormationStage, number>> = {};\r\n const emitStageEvent = (\r\n stage: FormationStage,\r\n status: 'start' | 'success' | 'skipped',\r\n stageDurationMs?: number,\r\n ): void => {\r\n try {\r\n config.onStageEvent?.({\r\n stage,\r\n status,\r\n stageDurationMs,\r\n totalElapsedMs: Date.now() - startTime,\r\n });\r\n } catch {\r\n // Diagnostics hooks must never break the formation pipeline.\r\n }\r\n };\r\n\r\n // ── Stage 1: Extract ──\r\n const existingEntities = config.getEntityNames();\r\n const extractStartTime = Date.now();\r\n emitStageEvent('extract', 'start');\r\n const extraction = await runExtract(input, existingEntities, config.useLLM);\r\n stageDurationsMs.extract = Date.now() - extractStartTime;\r\n emitStageEvent('extract', 'success', stageDurationsMs.extract);\r\n stagesCompleted = 1;\r\n\r\n // ── Stage 2: Resolve ──\r\n // Skip resolve for topicKey upserts (they have their own resolution via topicKey)\r\n let resolution;\r\n if (input.topicKey) {\r\n stageDurationsMs.resolve = 0;\r\n emitStageEvent('resolve', 'skipped', 0);\r\n resolution = {\r\n action: 'new' as const,\r\n reason: 'TopicKey upsert — bypasses resolve stage',\r\n };\r\n } else {\r\n const resolveStartTime = Date.now();\r\n emitStageEvent('resolve', 'start');\r\n resolution = await runResolve(\r\n extraction,\r\n input.projectId,\r\n config.searchMemories,\r\n config.getObservation,\r\n config.useLLM,\r\n );\r\n stageDurationsMs.resolve = Date.now() - resolveStartTime;\r\n emitStageEvent('resolve', 'success', stageDurationsMs.resolve);\r\n }\r\n stagesCompleted = 2;\r\n\r\n // ── Stage 3: Evaluate ──\r\n const evaluateStartTime = Date.now();\r\n emitStageEvent('evaluate', 'start');\r\n const evaluation = runEvaluate(extraction);\r\n stageDurationsMs.evaluate = Date.now() - evaluateStartTime;\r\n emitStageEvent('evaluate', 'success', stageDurationsMs.evaluate);\r\n stagesCompleted = 3;\r\n\r\n const durationMs = Date.now() - startTime;\r\n\r\n const formed: FormedMemory = {\r\n // Final enriched data\r\n entityName: extraction.entityName,\r\n type: extraction.type,\r\n title: extraction.title,\r\n narrative: resolution.mergedNarrative ?? extraction.narrative,\r\n facts: resolution.mergedFacts ?? extraction.facts,\r\n\r\n // Stage results\r\n extraction,\r\n resolution,\r\n evaluation,\r\n\r\n // Pipeline metadata\r\n pipeline: {\r\n mode: config.useLLM ? 'llm' : 'rules',\r\n durationMs,\r\n stagesCompleted,\r\n shadow: config.mode === 'shadow',\r\n stageDurationsMs,\r\n },\r\n\r\n // Governance fields\r\n governance: {\r\n provenance: {\r\n creator: input.source === 'explicit' ? 'user' : 'system',\r\n createdAt: new Date().toISOString(),\r\n source: input.source,\r\n },\r\n confidence: {\r\n score: evaluation.score,\r\n breakdown: {\r\n extractionConfidence: extraction.extractedFacts.length > 0 ? 0.8 : 0.5,\r\n resolutionConfidence: resolution.action === 'new' ? 0.7 : 0.9,\r\n evaluationConfidence: evaluation.score,\r\n },\r\n reason: `Value score ${evaluation.score.toFixed(2)} in ${evaluation.category} category`,\r\n },\r\n supersession: (resolution.action === 'merge' || resolution.action === 'evolve') && resolution.targetId ? {\r\n replacedIds: [resolution.targetId],\r\n reason: resolution.reason,\r\n replacementType: resolution.action === 'evolve' ? 'hard' : 'soft',\r\n } : undefined,\r\n },\r\n };\r\n\r\n // ── Collect metrics ──\r\n const metrics: FormationMetrics = {\r\n systemExtractedFacts: extraction.extractedFacts.length,\r\n titleImproved: extraction.titleImproved,\r\n entityResolved: extraction.entityResolved,\r\n typeCorrected: extraction.typeCorrected,\r\n resolutionAction: resolution.action,\r\n valueScore: evaluation.score,\r\n valueCategory: evaluation.category,\r\n durationMs,\r\n mode: 'rules',\r\n };\r\n\r\n if (metricsBuffer.length >= MAX_METRICS_BUFFER) {\r\n metricsBuffer.shift();\r\n }\r\n metricsBuffer.push(metrics);\r\n\r\n return formed;\r\n}\r\n\r\n// ── Re-exports for convenience ──────────────────────────────────\r\n\r\nexport type {\r\n FormationInput,\r\n FormedMemory,\r\n FormationConfig,\r\n FormationMetrics,\r\n ExtractResult,\r\n ResolveResult,\r\n EvaluateResult,\r\n ValueCategory,\r\n ResolutionAction,\r\n SearchHit,\r\n ExistingMemoryRef,\r\n} from './types.js';\r\n","/**\r\n * Behavior Configuration Reader\r\n *\r\n * Reads behavior settings from ~/.memorix/config.json.\r\n * Falls back to sensible defaults if config is missing.\r\n */\r\n\r\nimport { readFileSync } from 'node:fs';\r\nimport { join } from 'node:path';\r\nimport { homedir } from 'node:os';\r\n\r\nexport interface BehaviorConfig {\r\n sessionInject: 'full' | 'minimal' | 'silent';\r\n syncAdvisory: boolean;\r\n autoCleanup: boolean;\r\n formationMode: 'shadow' | 'active' | 'fallback';\r\n}\r\n\r\nconst DEFAULTS: BehaviorConfig = {\r\n sessionInject: 'minimal',\r\n syncAdvisory: true,\r\n autoCleanup: true,\r\n formationMode: 'active',\r\n};\r\n\r\nlet cached: BehaviorConfig | null = null;\r\n\r\n/**\r\n * Load behavior config from ~/.memorix/config.json.\r\n * Caches after first read. Returns defaults if file is missing.\r\n */\r\nexport function getBehaviorConfig(): BehaviorConfig {\r\n if (cached) return cached;\r\n\r\n try {\r\n const configPath = join(homedir(), '.memorix', 'config.json');\r\n const raw = readFileSync(configPath, 'utf-8');\r\n const config = JSON.parse(raw);\r\n const behavior = config.behavior ?? {};\r\n\r\n cached = {\r\n sessionInject: behavior.sessionInject ?? DEFAULTS.sessionInject,\r\n syncAdvisory: behavior.syncAdvisory ?? DEFAULTS.syncAdvisory,\r\n autoCleanup: behavior.autoCleanup ?? DEFAULTS.autoCleanup,\r\n formationMode: behavior.formationMode ?? DEFAULTS.formationMode,\r\n };\r\n } catch {\r\n cached = { ...DEFAULTS };\r\n }\r\n\r\n return cached;\r\n}\r\n\r\n/**\r\n * Reset cached config (for testing or after config change).\r\n */\r\nexport function resetBehaviorConfigCache(): void {\r\n cached = null;\r\n}\r\n","/**\r\n * Session Lifecycle Manager\r\n *\r\n * Tracks coding sessions across agents and provides context injection\r\n * for new sessions. Inspired by Engram's session management pattern.\r\n *\r\n * Key features:\r\n * - Start/end session tracking\r\n * - Structured session summaries (Goal/Discoveries/Accomplished/Files)\r\n * - Auto-inject previous session context on session start\r\n * - Cross-agent session awareness (all agents share session data)\r\n */\r\n\r\nimport type { Observation, Session } from '../types.js';\r\nimport { classifyLayer } from './disclosure-policy.js';\r\nimport { resolveAliases } from '../project/aliases.js';\r\nimport { getObservationStore } from '../store/obs-store.js';\r\nimport { getSessionStore } from '../store/session-store.js';\r\nimport { KnowledgeGraphManager } from './graph.js';\r\nimport { redactCredentials, sanitizeCredentials } from './secret-filter.js';\r\n\r\nconst PRIORITY_TYPES = new Set(['gotcha', 'decision', 'problem-solution', 'trade-off', 'discovery']);\r\nconst TYPE_EMOJI: Record<string, string> = {\r\n 'gotcha': '[DISCOVERY]',\r\n 'decision': '[WHY]',\r\n 'problem-solution': '[FIX]',\r\n 'trade-off': '[TRADEOFF]',\r\n 'discovery': '[DISCOVERY]',\r\n 'how-it-works': '[INFO]',\r\n 'what-changed': '[CHANGE]',\r\n 'why-it-exists': '[DECISION]',\r\n 'session-request': '[SESSION]',\r\n};\r\nconst TYPE_WEIGHTS: Record<string, number> = {\r\n 'gotcha': 6,\r\n 'decision': 5.5,\r\n 'problem-solution': 5.25,\r\n 'trade-off': 4.75,\r\n 'discovery': 4.25,\r\n};\r\nconst NOISE_PATTERNS = [\r\n /\\[测试\\]/i,\r\n /\\[test\\]/i,\r\n /验证/i,\r\n /兼容/i,\r\n /\\bcompat(?:ibility)?\\b/i,\r\n /\\bdemo\\b/i,\r\n /展示/i,\r\n /全能力/i,\r\n /handoff/i,\r\n /交接/i,\r\n /for_memmcp_test/i,\r\n /\\bbenchmark\\b/i,\r\n /\\bsandbox\\b/i,\r\n /\\bplayground\\b/i,\r\n];\r\n\r\n// Command-trace observations (debug commands, shell output) are low-value noise\r\n// in session context. They may have been stored by hooks but shouldn't surface.\r\nconst COMMAND_TRACE_PATTERNS = [\r\n /^Ran:\\s/i,\r\n /^Command:\\s/i,\r\n /^Executed:\\s/i,\r\n /\\b2>&1\\b/,\r\n /\\bSelect-String\\b/i,\r\n /\\bGet-Content\\b/i,\r\n /\\bnpx\\s+vitest\\b/i,\r\n /\\bnpx\\s+tsc\\b/i,\r\n];\r\n\r\n// Observations about Memorix itself (its tools, internals, runtime modes) should almost\r\n// never be injected into unrelated projects. These get a much heavier penalty.\r\nconst SYSTEM_SELF_PATTERNS = [\r\n /memorix.demo/i,\r\n /memorix.*全能力/i,\r\n /memorix.*工具.*能力/i,\r\n /memorix.*runtime.*mode/i,\r\n /memorix.*运行模式/i,\r\n /memorix.*control.plane/i,\r\n /session.*inject(?:ion)?/i,\r\n /注入.*逻辑/i,\r\n /\\b22\\s*(?:个|tools?).*(?:工具|能力|capabilit)/i,\r\n /memorix.*(?:v\\d|版本|version)/i,\r\n /memorix.*(?:兼容|compat)/i,\r\n /memorix.*(?:测试|test)/i,\r\n /memmcp/i,\r\n];\r\n\r\n/**\r\n * Resolve a projectId into a Set of all known aliases.\r\n * Ensures sessions stored under any alias are found regardless of which IDE stored them.\r\n */\r\nasync function resolveProjectIds(projectId: string): Promise<Set<string>> {\r\n try {\r\n const aliases = await resolveAliases(projectId);\r\n return new Set(aliases);\r\n } catch {\r\n return new Set([projectId]);\r\n }\r\n}\r\n\r\n/**\r\n * Generate a unique session ID.\r\n */\r\nfunction generateSessionId(): string {\r\n const ts = Date.now().toString(36);\r\n const rand = Math.random().toString(36).slice(2, 8);\r\n return `sess-${ts}-${rand}`;\r\n}\r\n\r\nfunction tokenizeProjectId(projectId: string): string[] {\r\n const leaf = projectId.split('/').at(-1) ?? projectId;\r\n return Array.from(\r\n new Set(\r\n leaf\r\n .toLowerCase()\r\n .split(/[^a-z0-9]+/i)\r\n .map((token) => token.trim())\r\n .filter((token) => token.length >= 2),\r\n ),\r\n );\r\n}\r\n\r\nfunction stringifyObservation(obs: Observation, includeFiles: boolean = true): string {\r\n const parts = [\r\n obs.title,\r\n obs.narrative,\r\n obs.entityName,\r\n ...(obs.facts ?? []),\r\n ...(obs.concepts ?? []),\r\n ];\r\n\r\n if (includeFiles) {\r\n parts.push(...(obs.filesModified ?? []));\r\n }\r\n\r\n return parts\r\n .filter(Boolean)\r\n .join('\\n')\r\n .toLowerCase();\r\n}\r\n\r\nfunction isCommandTrace(obs: Observation): boolean {\r\n const title = obs.title ?? '';\r\n return COMMAND_TRACE_PATTERNS.some((pattern) => pattern.test(title));\r\n}\r\n\r\nfunction isNoiseObservation(obs: Observation): boolean {\r\n const text = stringifyObservation(obs, false);\r\n return NOISE_PATTERNS.some((pattern) => pattern.test(text)) || isCommandTrace(obs);\r\n}\r\n\r\nfunction isSystemSelfObservation(obs: Observation): boolean {\r\n const text = stringifyObservation(obs, false);\r\n return SYSTEM_SELF_PATTERNS.some((pattern) => pattern.test(text));\r\n}\r\n\r\nexport function scoreObservationForSessionContext(obs: Observation, projectTokens: string[], now = Date.now()): number {\r\n let score = TYPE_WEIGHTS[obs.type] ?? 1;\r\n const text = stringifyObservation(obs);\r\n const ageDays = Math.max(0, (now - new Date(obs.createdAt).getTime()) / (1000 * 60 * 60 * 24));\r\n\r\n // Recency still matters, but should not dominate everything.\r\n score += Math.max(0.2, 2.5 - Math.min(ageDays, 45) * 0.05);\r\n\r\n // Prefer observations that mention the current project name or touch its paths.\r\n if (projectTokens.length > 0) {\r\n const matchingTokens = projectTokens.filter((token) => text.includes(token));\r\n if (matchingTokens.length > 0) {\r\n score += 2 + matchingTokens.length * 0.6;\r\n } else if ((obs.filesModified?.length ?? 0) > 0) {\r\n score -= 1.25;\r\n }\r\n }\r\n\r\n // Avoid injecting obviously stale or completed memories back into new sessions.\r\n if (obs.status === 'resolved' || obs.status === 'archived') {\r\n score -= 100;\r\n }\r\n\r\n // Downrank demos, tests, migrations, and handoff records.\r\n if (isNoiseObservation(obs)) {\r\n score -= 8;\r\n }\r\n\r\n // Heavy penalty for observations about Memorix itself (system self-reference).\r\n // These should almost never surface in unrelated project sessions.\r\n if (isSystemSelfObservation(obs)) {\r\n score -= 15;\r\n }\r\n\r\n // Source-aware adjustments (neutral when sourceDetail/valueCategory absent — backward-compatible)\r\n if (obs.sourceDetail === 'hook') {\r\n // Hook auto-captures are L1 routing signals, not L2 working context\r\n score -= 3;\r\n if (obs.valueCategory === 'ephemeral') {\r\n // Hook + ephemeral = high-noise auto-capture with no lasting value\r\n score -= 5;\r\n }\r\n }\r\n if (obs.valueCategory === 'core') {\r\n // Formation-classified core memory: high-value, prefer in working context\r\n score += 2;\r\n }\r\n\r\n return score;\r\n}\r\n\r\n/**\r\n * Start a new coding session.\r\n *\r\n * Creates a session record and returns context from previous sessions\r\n * so the agent can resume work without re-explaining everything.\r\n */\r\nexport async function startSession(\r\n projectDir: string,\r\n projectId: string,\r\n opts?: { sessionId?: string; agent?: string },\r\n): Promise<{ session: Session; previousContext: string }> {\r\n const sessionId = opts?.sessionId || generateSessionId();\r\n const now = new Date().toISOString();\r\n\r\n const session: Session = {\r\n id: sessionId,\r\n projectId,\r\n startedAt: now,\r\n status: 'active',\r\n agent: opts?.agent,\r\n };\r\n\r\n // Load previous context before creating new session\r\n const previousContext = await getSessionContext(projectDir, projectId);\r\n\r\n // Atomic rollover: complete all active sessions for this project's aliases\r\n // and insert the new session in a single SQLite transaction.\r\n // Prevents concurrent startSession() from leaving multiple active sessions.\r\n const sessionStore = getSessionStore();\r\n const aliasSet = await resolveProjectIds(projectId);\r\n await sessionStore.atomicRolloverInsert(session, [...aliasSet], now);\r\n\r\n return { session, previousContext };\r\n}\r\n\r\n/**\r\n * End a coding session with an optional structured summary.\r\n *\r\n * Summary format (following Engram's convention):\r\n * ## Goal\r\n * ## Discoveries\r\n * ## Accomplished\r\n * ## Relevant Files\r\n */\r\nexport async function endSession(\r\n projectDir: string,\r\n sessionId: string,\r\n summary?: string,\r\n): Promise<Session | null> {\r\n const sessionStore = getSessionStore();\r\n const sessions = await sessionStore.loadAll();\r\n const session = sessions.find((entry) => entry.id === sessionId);\r\n\r\n if (!session) return null;\r\n\r\n session.status = 'completed';\r\n session.endedAt = new Date().toISOString();\r\n if (summary) {\r\n session.summary = sanitizeCredentials(summary);\r\n }\r\n\r\n await sessionStore.update(session);\r\n return session;\r\n}\r\n\r\n/**\r\n * Get formatted context from previous sessions for injection into a new session.\r\n *\r\n * Returns a layered context packet:\r\n * L1 Routing — recent hook signals + search guidance\r\n * Recent Handoff — last session summary (L2)\r\n * Key Memories — durable explicit working context (L2)\r\n * Session History— orientation log\r\n * L3 Evidence — pointers to git-memory and hook traces (on-demand)\r\n */\r\nexport async function getSessionContext(\r\n projectDir: string,\r\n projectId: string,\r\n limit: number = 3,\r\n): Promise<string> {\r\n const sessions = await getSessionStore().loadAll();\r\n const allObs = await getObservationStore().loadAll();\r\n\r\n const aliasSet = await resolveProjectIds(projectId);\r\n /** Check if a session summary contains noise/system-self content */\r\n const isNoisySummary = (summary: string | undefined): boolean => {\r\n if (!summary) return false;\r\n return NOISE_PATTERNS.some((p) => p.test(summary)) || SYSTEM_SELF_PATTERNS.some((p) => p.test(summary));\r\n };\r\n\r\n const projectSessions = sessions\r\n .filter((session) => aliasSet.has(session.projectId) && session.status === 'completed')\r\n .filter((session) => !isNoisySummary(session.summary))\r\n .sort((a, b) => new Date(b.endedAt || b.startedAt).getTime() - new Date(a.endedAt || a.startedAt).getTime())\r\n .slice(0, limit);\r\n\r\n if (projectSessions.length === 0 && allObs.length === 0) {\r\n return '';\r\n }\r\n\r\n const lines: string[] = [];\r\n const projectTokens = tokenizeProjectId(projectId);\r\n\r\n // ── Partition project observations by disclosure layer ─────────────\r\n const projectObs = allObs\r\n .filter((obs) => aliasSet.has(obs.projectId) && (obs.status ?? 'active') === 'active')\r\n .filter((obs) => !isNoiseObservation(obs) && !isSystemSelfObservation(obs));\r\n\r\n // L2: durable working context (explicit/undefined/core), priority types only\r\n const l2Scored = projectObs\r\n .filter((obs) => PRIORITY_TYPES.has(obs.type) && classifyLayer(obs) === 'L2')\r\n .map((obs) => ({ obs, score: scoreObservationForSessionContext(obs, projectTokens) }))\r\n .sort((a, b) => {\r\n if (b.score !== a.score) return b.score - a.score;\r\n return new Date(b.obs.createdAt).getTime() - new Date(a.obs.createdAt).getTime();\r\n });\r\n\r\n // Per-entity cap: only when multiple distinct entities are present.\r\n // Prevents one workstream from monopolizing session context.\r\n // When all candidates belong to a single entity, skip the cap — no pollution risk.\r\n const distinctL2Entities = new Set(l2Scored.map(({ obs }) => obs.entityName).filter(Boolean)).size;\r\n const l2Obs = (distinctL2Entities > 1\r\n ? (() => {\r\n const entityCount = new Map<string, number>();\r\n const ENTITY_CAP = 3;\r\n return l2Scored.filter(({ obs }) => {\r\n const key = obs.entityName ?? '';\r\n const count = entityCount.get(key) ?? 0;\r\n if (count >= ENTITY_CAP) return false;\r\n entityCount.set(key, count + 1);\r\n return true;\r\n });\r\n })()\r\n : l2Scored\r\n ).slice(0, 5).map(({ obs }) => obs);\r\n\r\n // L1: recent hook activity signals (titles only, most recent first)\r\n const l1HookObs = projectObs\r\n .filter((obs) => classifyLayer(obs) === 'L1')\r\n .sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime())\r\n .slice(0, 3);\r\n\r\n // L3: git-ingest evidence count (pointer only, not injected)\r\n const l3GitCount = projectObs.filter((obs) => classifyLayer(obs) === 'L3').length;\r\n const totalHookCount = projectObs.filter((obs) => classifyLayer(obs) === 'L1').length;\r\n\r\n // Active entities: unique entity names from top-scored L2 memories.\r\n // Surfaced in L1 Routing as next-hop search guidance — not working context.\r\n // Capped at 5, derived from the same l2Obs already scored above.\r\n const activeEntities = [\r\n ...new Set(l2Obs.map((o) => o.entityName).filter((n): n is string => !!n && n.trim().length > 0)),\r\n ].slice(0, 5);\r\n\r\n // ── L1 Routing ─────────────────────────────────────────────────────\r\n // L1 Routing requires actual L1/L3 signals (hooks or git evidence).\r\n // Active entities enrich the section when it is shown but do not open it alone.\r\n const hasL1Content = l1HookObs.length > 0 || l3GitCount > 0;\r\n if (hasL1Content) {\r\n // Graph neighbor routing hint: 1-hop neighbors of activeEntities from the\r\n // knowledge graph. Routing only — no query expansion, no rerank, no 2-hop\r\n // traversal. Silently skipped if graph is absent, empty, or throws.\r\n let graphNeighbors: string[] = [];\r\n if (activeEntities.length > 0) {\r\n try {\r\n const graphMgr = new KnowledgeGraphManager(projectDir);\r\n await graphMgr.init();\r\n const { relations } = await graphMgr.readGraph();\r\n const activeSet = new Set(activeEntities.map((n) => n.toLowerCase()));\r\n const neighborSet = new Set<string>();\r\n for (const rel of relations) {\r\n const fromLower = rel.from.toLowerCase();\r\n const toLower = rel.to.toLowerCase();\r\n if (activeSet.has(fromLower) && !activeSet.has(toLower)) neighborSet.add(rel.to);\r\n if (activeSet.has(toLower) && !activeSet.has(fromLower)) neighborSet.add(rel.from);\r\n }\r\n graphNeighbors = [...neighborSet].slice(0, 5);\r\n } catch {\r\n // Graph unavailable or empty — silently skip\r\n }\r\n }\r\n\r\n lines.push('## L1 Routing');\r\n lines.push('*Recent activity signals and search guidance for this session.*');\r\n\r\n if (l1HookObs.length > 0) {\r\n for (const obs of l1HookObs) {\r\n lines.push(`[HOOK] ${redactCredentials(obs.title)}`);\r\n }\r\n lines.push('');\r\n }\r\n\r\n const hints: string[] = [];\r\n if (activeEntities.length > 0) {\r\n hints.push(`Active entities: ${activeEntities.join(', ')}`);\r\n }\r\n if (graphNeighbors.length > 0) {\r\n hints.push(`Graph neighbors: ${graphNeighbors.join(', ')}`);\r\n }\r\n if (l3GitCount > 0) {\r\n hints.push(`${l3GitCount} git-memory item(s) available — search \\`what-changed\\` or by entity/commit`);\r\n }\r\n if (totalHookCount > 0) {\r\n hints.push(`${totalHookCount} hook trace(s) available — use \\`memorix_timeline\\` for activity expansion`);\r\n }\r\n for (const hint of hints) {\r\n lines.push(`[TIP] ${hint}`);\r\n }\r\n lines.push('');\r\n }\r\n\r\n // ── L2 Recent Handoff ──────────────────────────────────────────────\r\n if (projectSessions.length > 0) {\r\n // Walk back to find the most recent session with a real summary.\r\n let handoff = projectSessions[0];\r\n for (const s of projectSessions) {\r\n if (s.summary && s.summary !== '(session ended implicitly by new session start)') {\r\n handoff = s;\r\n break;\r\n }\r\n }\r\n lines.push('## Recent Handoff');\r\n lines.push('*Last session with a recorded summary — pick up where it left off.*');\r\n if (handoff.agent) {\r\n lines.push(`Agent: ${handoff.agent}`);\r\n }\r\n lines.push(`Ended: ${handoff.endedAt || handoff.startedAt}`);\r\n if (handoff.summary && handoff.summary !== '(session ended implicitly by new session start)') {\r\n lines.push('', redactCredentials(handoff.summary));\r\n }\r\n lines.push('');\r\n }\r\n\r\n // ── L2 Key Project Memories ────────────────────────────────────────\r\n if (l2Obs.length > 0) {\r\n lines.push('## Key Project Memories');\r\n lines.push('*Durable working context — explicit decisions, gotchas, and discoveries.*');\r\n for (const obs of l2Obs) {\r\n const emoji = TYPE_EMOJI[obs.type] ?? '[PIN]';\r\n const fact = obs.facts?.[0] ? ` — ${redactCredentials(obs.facts[0])}` : '';\r\n lines.push(`${emoji} ${redactCredentials(obs.title)}${fact}`);\r\n }\r\n lines.push('');\r\n }\r\n\r\n // ── Session History ────────────────────────────────────────────────\r\n if (projectSessions.length > 1) {\r\n lines.push(`## Recent Session History (last ${projectSessions.length})`);\r\n lines.push('*Chronological session log — for orientation, not action.*');\r\n for (const session of projectSessions) {\r\n const date = (session.endedAt || session.startedAt).slice(0, 10);\r\n const agent = session.agent ? ` [${session.agent}]` : '';\r\n const rawSummary = session.summary && session.summary !== '(session ended implicitly by new session start)'\r\n ? session.summary : null;\r\n const summary = rawSummary\r\n ? ` — ${redactCredentials(rawSummary.split('\\n')[0].replace(/^#+\\s*/, '')).slice(0, 80)}`\r\n : '';\r\n lines.push(`- ${date}${agent}${summary}`);\r\n }\r\n lines.push('');\r\n }\r\n\r\n // ── L3 Evidence Hints ─────────────────────────────────────────────\r\n const l3Lines: string[] = [];\r\n if (l3GitCount > 0) {\r\n l3Lines.push(`[PIN] ${l3GitCount} git-memory item(s) — use \\`memorix_search\\` to retrieve repository evidence`);\r\n }\r\n if (totalHookCount > 0) {\r\n l3Lines.push(`[HOOK] ${totalHookCount} hook trace(s) — use \\`memorix_timeline\\` for full activity expansion`);\r\n }\r\n if (l3Lines.length > 0) {\r\n lines.push('## L3 Evidence');\r\n lines.push('*Deeper context available on demand — kept out of working context to stay compact.*');\r\n for (const l of l3Lines) {\r\n lines.push(l);\r\n }\r\n lines.push('');\r\n }\r\n\r\n return lines.join('\\n');\r\n}\r\n\r\n/**\r\n * List all sessions for a project.\r\n */\r\nexport async function listSessions(\r\n projectDir: string,\r\n projectId?: string,\r\n): Promise<Session[]> {\r\n const sessionStore = getSessionStore();\r\n if (projectId) {\r\n const aliasSet = await resolveProjectIds(projectId);\r\n const all = await sessionStore.loadAll();\r\n return all.filter((session) => aliasSet.has(session.projectId));\r\n }\r\n return sessionStore.loadAll();\r\n}\r\n\r\n/**\r\n * Get the currently active session for a project (if any).\r\n */\r\nexport async function getActiveSession(\r\n projectDir: string,\r\n projectId: string,\r\n): Promise<Session | null> {\r\n const sessionStore = getSessionStore();\r\n const sessions = await sessionStore.loadAll();\r\n const aliasSet = await resolveProjectIds(projectId);\r\n return sessions.find((session) => aliasSet.has(session.projectId) && session.status === 'active') || null;\r\n}\r\n","/**\r\n * Retention & Decay Engine\r\n *\r\n * Manages memory relevance over time using exponential decay.\r\n * Sources:\r\n * - mcp-memory-service: ExponentialDecayCalculator (importance × decay × access_boost)\r\n * - MemCP: Active → Archive → Purge lifecycle with immunity rules\r\n *\r\n * Relevance formula:\r\n * score = baseImportance × e^(-ageDays / retentionPeriod) × accessBoost × connectionBoost\r\n *\r\n * Immunity: observations with importance=critical, valueCategory=core, accessCount>=3,\r\n * or tagged \"keep\"/\"pinned\" are never auto-archived.\r\n * High-importance types (gotcha/decision/trade-off/reasoning) retain a long 180-day\r\n * retention period but are no longer permanently immune — they decay normally.\r\n */\r\n\r\nimport type { MemorixDocument, Observation } from '../types.js';\r\nimport { getObservationStore } from '../store/obs-store.js';\r\n\r\n// ── Importance → Retention Period mapping ────────────────────────────\r\n\r\nexport type ImportanceLevel = 'critical' | 'high' | 'medium' | 'low';\r\n\r\nconst RETENTION_DAYS: Record<ImportanceLevel, number> = {\r\n critical: 365,\r\n high: 180,\r\n medium: 90,\r\n low: 30,\r\n};\r\n\r\nconst BASE_IMPORTANCE: Record<ImportanceLevel, number> = {\r\n critical: 1.0,\r\n high: 0.8,\r\n medium: 0.5,\r\n low: 0.3,\r\n};\r\n\r\n// ── Observation Type → Default Importance ────────────────────────────\r\n\r\nconst TYPE_IMPORTANCE: Record<string, ImportanceLevel> = {\r\n gotcha: 'high',\r\n decision: 'high',\r\n 'trade-off': 'high',\r\n reasoning: 'high',\r\n 'problem-solution': 'medium',\r\n 'how-it-works': 'medium',\r\n 'what-changed': 'low',\r\n 'why-it-exists': 'medium',\r\n discovery: 'low',\r\n 'session-request': 'low',\r\n};\r\n\r\n// ── Immunity ─────────────────────────────────────────────────────────\r\n\r\nconst PROTECTED_TAGS = new Set(['keep', 'important', 'pinned', 'critical']);\r\nconst MIN_ACCESS_FOR_IMMUNITY = 3;\r\n\r\n/** Minimum effective retention period in days — prevents extreme multiplier combinations\r\n * (e.g. hook × ephemeral = 0.25×) from producing unreasonably short windows. */\r\nconst MIN_RETENTION_DAYS = 7;\r\n\r\n/**\r\n * Get retention period multiplier based on sourceDetail.\r\n * Neutral (1.0) for unknown/undefined sourceDetail — backward-compatible.\r\n */\r\nfunction getSourceRetentionMultiplier(doc: MemorixDocument): number {\r\n if (doc.sourceDetail === 'hook') return 0.5; // hook auto-captures: half the retention period\r\n if (doc.sourceDetail === 'git-ingest') return 1.5; // git-backed truth: extend retention\r\n return 1.0; // explicit/undefined: neutral\r\n}\r\n\r\n/**\r\n * Get retention period multiplier based on valueCategory.\r\n * Neutral (1.0) for undefined/contextual — backward-compatible.\r\n */\r\nfunction getValueCategoryMultiplier(doc: MemorixDocument): number {\r\n if (doc.valueCategory === 'ephemeral') return 0.5; // short-lived context: decay faster\r\n if (doc.valueCategory === 'core') return 2.0; // durable knowledge: extend retention\r\n return 1.0; // contextual/undefined: neutral\r\n}\r\n\r\n/**\r\n * Compute the effective retention period in days, with floor applied.\r\n * Combines base retention (from importance/type) with source and valueCategory multipliers.\r\n */\r\nexport function getEffectiveRetentionDays(doc: MemorixDocument): number {\r\n const importance = getImportanceLevel(doc);\r\n const raw = RETENTION_DAYS[importance] * getSourceRetentionMultiplier(doc) * getValueCategoryMultiplier(doc);\r\n return Math.max(MIN_RETENTION_DAYS, raw);\r\n}\r\n\r\n/**\r\n * Check if an observation is immune from archiving/decay.\r\n * Immune observations maintain a minimum relevance score.\r\n */\r\nexport function isImmune(doc: MemorixDocument): boolean {\r\n // formation-classified core memories are immune regardless of type\r\n if (doc.valueCategory === 'core') return true;\r\n\r\n const importance = getImportanceLevel(doc);\r\n // Only 'critical' importance grants type-based immunity.\r\n // 'high' importance types (gotcha/decision/trade-off/reasoning) keep their long\r\n // 180-day retention period but are no longer permanently immune — this prevents\r\n // unbounded growth of never-accessed high-type observations.\r\n if (importance === 'critical') return true;\r\n if ((doc.accessCount ?? 0) >= MIN_ACCESS_FOR_IMMUNITY) return true;\r\n\r\n const concepts = doc.concepts?.split(', ').map((c) => c.toLowerCase()) ?? [];\r\n return concepts.some((c) => PROTECTED_TAGS.has(c));\r\n}\r\n\r\n/**\r\n * Return a human-readable reason for why an observation is immune, or null if not immune.\r\n */\r\nexport function getImmunityReason(doc: MemorixDocument): string | null {\r\n if (doc.valueCategory === 'core') return 'core valueCategory (formation-classified)';\r\n const importance = getImportanceLevel(doc);\r\n if (importance === 'critical') return 'critical importance';\r\n if ((doc.accessCount ?? 0) >= MIN_ACCESS_FOR_IMMUNITY) return `frequently accessed (${doc.accessCount}×)`;\r\n const concepts = doc.concepts?.split(', ').map((c) => c.toLowerCase()) ?? [];\r\n if (concepts.some((c) => PROTECTED_TAGS.has(c))) return 'protected tag';\r\n return null;\r\n}\r\n\r\n// ── Relevance Scoring ────────────────────────────────────────────────\r\n\r\nexport interface RelevanceScore {\r\n observationId: number;\r\n totalScore: number;\r\n baseImportance: number;\r\n decayFactor: number;\r\n accessBoost: number;\r\n ageDays: number;\r\n isImmune: boolean;\r\n}\r\n\r\n/**\r\n * Get the importance level for an observation based on its type.\r\n */\r\nexport function getImportanceLevel(doc: MemorixDocument): ImportanceLevel {\r\n return TYPE_IMPORTANCE[doc.type] ?? 'medium';\r\n}\r\n\r\n/**\r\n * Calculate the relevance score for a single observation.\r\n *\r\n * Formula (from mcp-memory-service):\r\n * score = baseImportance × e^(-ageDays / retentionPeriod) × accessBoost\r\n *\r\n * Access boost (from mcp-memory-service):\r\n * 1 + 0.1 × accessCount (10% boost per access, capped at 2.0)\r\n */\r\nexport function calculateRelevance(\r\n doc: MemorixDocument,\r\n referenceTime?: Date,\r\n): RelevanceScore {\r\n const now = referenceTime ?? new Date();\r\n const importance = getImportanceLevel(doc);\r\n const base = BASE_IMPORTANCE[importance];\r\n const retention = getEffectiveRetentionDays(doc);\r\n\r\n // Age in days\r\n const createdAt = new Date(doc.createdAt);\r\n const ageDays = Math.max(0, (now.getTime() - createdAt.getTime()) / (1000 * 60 * 60 * 24));\r\n\r\n // Exponential decay\r\n const decayFactor = Math.exp(-ageDays / retention);\r\n\r\n // Access boost: 10% per access, capped at 2.0×\r\n const accessCount = doc.accessCount ?? 0;\r\n const accessBoost = Math.min(2.0, 1 + 0.1 * accessCount);\r\n\r\n let totalScore = base * decayFactor * accessBoost;\r\n\r\n // Immune observations get minimum 0.5 relevance\r\n const immune = isImmune(doc);\r\n if (immune) {\r\n totalScore = Math.max(totalScore, 0.5);\r\n }\r\n\r\n return {\r\n observationId: doc.observationId,\r\n totalScore,\r\n baseImportance: base,\r\n decayFactor,\r\n accessBoost,\r\n ageDays,\r\n isImmune: immune,\r\n };\r\n}\r\n\r\n/**\r\n * Score and rank observations by relevance.\r\n * Returns sorted (highest relevance first) with scores.\r\n */\r\nexport function rankByRelevance(\r\n docs: MemorixDocument[],\r\n referenceTime?: Date,\r\n): RelevanceScore[] {\r\n return docs\r\n .map((doc) => calculateRelevance(doc, referenceTime))\r\n .sort((a, b) => b.totalScore - a.totalScore);\r\n}\r\n\r\n// ── Retention Lifecycle ──────────────────────────────────────────────\r\n\r\nexport type RetentionZone = 'active' | 'stale' | 'archive-candidate';\r\n\r\n/**\r\n * Classify an observation into a retention zone.\r\n *\r\n * Lifecycle (from MemCP):\r\n * Active: recently accessed or high importance\r\n * Stale: not accessed, beyond 50% of retention period\r\n * Archive-candidate: not accessed, beyond 100% of retention period, not immune\r\n */\r\nexport function getRetentionZone(doc: MemorixDocument, referenceTime?: Date): RetentionZone {\r\n const now = referenceTime ?? new Date();\r\n const importance = getImportanceLevel(doc);\r\n const retention = getEffectiveRetentionDays(doc);\r\n\r\n const createdAt = new Date(doc.createdAt);\r\n const ageDays = (now.getTime() - createdAt.getTime()) / (1000 * 60 * 60 * 24);\r\n\r\n // Recently accessed = active regardless of age\r\n if (doc.lastAccessedAt) {\r\n const lastAccess = new Date(doc.lastAccessedAt);\r\n const daysSinceAccess = (now.getTime() - lastAccess.getTime()) / (1000 * 60 * 60 * 24);\r\n if (daysSinceAccess < 7) return 'active';\r\n }\r\n\r\n if (isImmune(doc)) return 'active';\r\n if (ageDays > retention) return 'archive-candidate';\r\n if (ageDays > retention * 0.5) return 'stale';\r\n return 'active';\r\n}\r\n\r\n/**\r\n * Get archive candidates from a list of observations.\r\n * Returns observations that are beyond their retention period and not immune.\r\n */\r\nexport function getArchiveCandidates(\r\n docs: MemorixDocument[],\r\n referenceTime?: Date,\r\n): MemorixDocument[] {\r\n return docs.filter((doc) => getRetentionZone(doc, referenceTime) === 'archive-candidate');\r\n}\r\n\r\n/**\r\n * Get retention summary statistics.\r\n */\r\nexport function getRetentionSummary(\r\n docs: MemorixDocument[],\r\n referenceTime?: Date,\r\n): { active: number; stale: number; archiveCandidates: number; immune: number } {\r\n let active = 0;\r\n let stale = 0;\r\n let archiveCandidates = 0;\r\n let immune = 0;\r\n\r\n for (const doc of docs) {\r\n const zone = getRetentionZone(doc, referenceTime);\r\n if (zone === 'active') active++;\r\n else if (zone === 'stale') stale++;\r\n else archiveCandidates++;\r\n if (isImmune(doc)) immune++;\r\n }\r\n\r\n return { active, stale, archiveCandidates, immune };\r\n}\r\n\r\n// ── Retention Explainability ─────────────────────────────────────────\r\n\r\nexport interface RetentionExplanation {\r\n observationId: number;\r\n importanceLevel: ImportanceLevel;\r\n baseRetentionDays: number;\r\n sourceMultiplier: number;\r\n valueCategoryMultiplier: number;\r\n effectiveRetentionDays: number;\r\n zone: RetentionZone;\r\n immune: boolean;\r\n /** Human-readable reason for immunity, or null when not immune. */\r\n immunityReason: string | null;\r\n ageDays: number;\r\n /** Short human-readable summary of the retention posture. */\r\n summary: string;\r\n}\r\n\r\n/**\r\n * Produce a structured explanation of why an observation has its current\r\n * retention posture. Designed for operator-facing reporting.\r\n */\r\nexport function explainRetention(\r\n doc: MemorixDocument,\r\n referenceTime?: Date,\r\n): RetentionExplanation {\r\n const importance = getImportanceLevel(doc);\r\n const baseRetention = RETENTION_DAYS[importance];\r\n const srcMul = getSourceRetentionMultiplier(doc);\r\n const vcMul = getValueCategoryMultiplier(doc);\r\n const effective = getEffectiveRetentionDays(doc);\r\n const zone = getRetentionZone(doc, referenceTime);\r\n const immuneFlag = isImmune(doc);\r\n const immunityReason = getImmunityReason(doc);\r\n\r\n const now = referenceTime ?? new Date();\r\n const ageDays = Math.max(\r\n 0,\r\n (now.getTime() - new Date(doc.createdAt).getTime()) / (1000 * 60 * 60 * 24),\r\n );\r\n\r\n // Build a concise human-readable summary\r\n const parts: string[] = [];\r\n parts.push(`${importance} importance (${baseRetention}d base)`);\r\n if (srcMul !== 1.0) parts.push(`source ${srcMul}×`);\r\n if (vcMul !== 1.0) parts.push(`valueCategory ${vcMul}×`);\r\n parts.push(`→ ${effective}d effective`);\r\n if (immuneFlag) {\r\n parts.push(`immune: ${immunityReason}`);\r\n } else {\r\n parts.push(`zone: ${zone}`);\r\n }\r\n\r\n return {\r\n observationId: doc.observationId,\r\n importanceLevel: importance,\r\n baseRetentionDays: baseRetention,\r\n sourceMultiplier: srcMul,\r\n valueCategoryMultiplier: vcMul,\r\n effectiveRetentionDays: effective,\r\n zone,\r\n immune: immuneFlag,\r\n immunityReason,\r\n ageDays: Math.round(ageDays),\r\n // Summary is rendered inside markdown table cells in memorix_retention output,\r\n // so avoid pipe separators that would split the row into extra columns.\r\n summary: parts.join(' ; '),\r\n };\r\n}\r\n\r\n// ── Auto-Archive ────────────────────────────────────────────────────\r\n\r\n/**\r\n * Archive expired observations by setting status='archived' in-place.\r\n *\r\n * Phase 2 change: instead of moving observations to a separate\r\n * observations.archived.json file, we update their status in the\r\n * canonical store (SQLite or JSON). This eliminates the separate\r\n * archive file and keeps all observation data in one place.\r\n *\r\n * Returns the count of archived observations.\r\n */\r\nexport async function archiveExpired(\r\n projectDir: string,\r\n referenceTime?: Date,\r\n accessMap?: Map<number, { accessCount: number; lastAccessedAt: string }>,\r\n): Promise<{ archived: number; remaining: number }> {\r\n const store = getObservationStore();\r\n return await store.atomic(async (tx) => {\r\n const allObs = await tx.loadAll();\r\n\r\n // Convert to MemorixDocument-like shape for zone calculation\r\n // Use accessMap (from Orama index) when available for accurate immunity checks\r\n const toDoc = (obs: Observation): MemorixDocument => {\r\n const access = accessMap?.get(obs.id);\r\n return {\r\n id: `obs-${obs.id}`,\r\n observationId: obs.id,\r\n entityName: obs.entityName,\r\n type: obs.type,\r\n title: obs.title,\r\n narrative: obs.narrative,\r\n facts: obs.facts.join('\\n'),\r\n filesModified: obs.filesModified.join('\\n'),\r\n concepts: obs.concepts.join(', '),\r\n tokens: obs.tokens,\r\n createdAt: obs.createdAt,\r\n projectId: obs.projectId,\r\n accessCount: access?.accessCount ?? 0,\r\n lastAccessedAt: access?.lastAccessedAt ?? '',\r\n status: obs.status ?? 'active',\r\n source: obs.source ?? 'agent',\r\n sourceDetail: obs.sourceDetail ?? '',\r\n valueCategory: obs.valueCategory ?? '',\r\n };\r\n };\r\n\r\n // Only consider active observations for archiving\r\n const activeObs = allObs.filter(o => (o.status ?? 'active') === 'active');\r\n let archivedCount = 0;\r\n\r\n for (const obs of activeObs) {\r\n const doc = toDoc(obs);\r\n const zone = getRetentionZone(doc, referenceTime);\r\n if (zone === 'archive-candidate') {\r\n obs.status = 'archived';\r\n archivedCount++;\r\n }\r\n }\r\n\r\n if (archivedCount === 0) {\r\n return { archived: 0, remaining: activeObs.length };\r\n }\r\n\r\n // Persist all observations with updated statuses\r\n await tx.saveAll(allObs);\r\n\r\n return { archived: archivedCount, remaining: activeObs.length - archivedCount };\r\n });\r\n}\r\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 status?: string;\r\n source?: 'agent' | 'git' | 'manual';\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 'gemini-cli': [],\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\nconst LOW_SIGNAL_TITLE_PATTERNS = [\r\n /^ran:/i,\r\n /^command:/i,\r\n];\r\nconst LOW_SIGNAL_ENTITY_PATTERNS = [\r\n /^(?:bash|sh|cmd|powershell|pwsh|node|npm|npx|pnpm|yarn|gh|git)$/i,\r\n /^mcp[_-]/i,\r\n];\r\nconst COMMAND_TRACE_PATTERNS = [\r\n /\\bcommand:\\b/i,\r\n /\\b2>&1\\b/i,\r\n /\\bselect-string\\b/i,\r\n /\\bget-content\\b/i,\r\n /\\bget-command\\b/i,\r\n /\\bpowershell\\b/i,\r\n /\\bcmd(?:\\.exe)?\\b/i,\r\n /\\bnpm\\b/i,\r\n /\\bnpx\\b/i,\r\n /\\bpnpm\\b/i,\r\n /\\byarn\\b/i,\r\n /\\bgit\\b/i,\r\n /\\bgh\\b/i,\r\n /\\|/,\r\n /&&/,\r\n];\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 const candidates = observations.filter((obs) => !this.isLowSignalObservation(obs));\r\n\r\n // 1. Cluster observations by entity\r\n const clusters = this.clusterByEntity(candidates);\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 isLowSignalObservation(obs: ObsData): boolean {\r\n if (obs.status === 'archived') return true;\r\n\r\n const title = obs.title.trim();\r\n const narrative = obs.narrative.trim();\r\n const entity = (obs.entityName || '').trim();\r\n const haystack = `${title}\\n${narrative}`;\r\n\r\n if (LOW_SIGNAL_TITLE_PATTERNS.some((pattern) => pattern.test(title))) {\r\n return true;\r\n }\r\n\r\n // Generic command/tool entities don't form useful project skills, even if\r\n // the observation came from git ingestion rather than an agent trace.\r\n if (LOW_SIGNAL_ENTITY_PATTERNS.some((pattern) => pattern.test(entity))) {\r\n return true;\r\n }\r\n\r\n if (obs.source !== 'git' && COMMAND_TRACE_PATTERNS.filter((pattern) => pattern.test(haystack)).length >= 2) {\r\n return true;\r\n }\r\n\r\n return false;\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('## [WARN] 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('## [BUILD] 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('## [DOCS] 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('## [TOOL] 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('## [TRADEOFF] 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('## [PLAN] 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('## [TAG] 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('## [PIN] 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","/**\r\n * Memory Consolidation Engine\r\n *\r\n * Merges similar observations into consolidated summaries to prevent data bloat.\r\n * Uses text similarity (Jaccard on token n-grams) to find clusters of related\r\n * observations, then merges them into a single observation preserving key facts.\r\n *\r\n * Strategy:\r\n * 1. Group observations by entity + type\r\n * 2. Within each group, compute pairwise similarity\r\n * 3. Cluster observations above a similarity threshold\r\n * 4. Merge each cluster into a consolidated observation\r\n * 5. Remove originals, keep the merged result\r\n *\r\n * Inspired by Engram's duplicate_count and MemCP's MAGMA consolidation.\r\n */\r\n\r\nimport type { Observation } from '../types.js';\r\nimport { getObservationStore } from '../store/obs-store.js';\r\n\r\n/** Default similarity threshold for merging (0.0-1.0) */\r\nconst DEFAULT_SIMILARITY_THRESHOLD = 0.45;\r\n\r\n/** Higher threshold for high-value types — only near-duplicates should merge */\r\nconst HIGH_VALUE_SIMILARITY_THRESHOLD = 0.85;\r\n\r\n/** Types that require much higher similarity to merge (carry unique implementation detail) */\r\nconst HIGH_VALUE_TYPES = new Set(['gotcha', 'decision', 'trade-off', 'reasoning', 'problem-solution']);\r\n\r\n/** Minimum cluster size to trigger consolidation */\r\nconst MIN_CLUSTER_SIZE = 2;\r\n\r\n/** Maximum observations to process in one consolidation run */\r\nconst MAX_BATCH_SIZE = 500;\r\n\r\n/**\r\n * Tokenize text into word-level tokens for similarity comparison.\r\n */\r\nfunction tokenize(text: string): Set<string> {\r\n return new Set(\r\n text\r\n .toLowerCase()\r\n .replace(/[^a-z0-9\\u4e00-\\u9fff\\s-]/g, ' ')\r\n .split(/\\s+/)\r\n .filter(t => t.length > 1),\r\n );\r\n}\r\n\r\n/**\r\n * Compute Jaccard similarity between two sets of tokens.\r\n */\r\nfunction jaccardSimilarity(a: Set<string>, b: Set<string>): number {\r\n if (a.size === 0 && b.size === 0) return 1;\r\n let intersection = 0;\r\n for (const token of a) {\r\n if (b.has(token)) intersection++;\r\n }\r\n const union = a.size + b.size - intersection;\r\n return union === 0 ? 0 : intersection / union;\r\n}\r\n\r\n/**\r\n * Build a text fingerprint from an observation for similarity matching.\r\n */\r\nfunction observationFingerprint(obs: Observation): string {\r\n return [obs.title, obs.narrative, ...obs.facts, ...obs.concepts].join(' ');\r\n}\r\n\r\n/** A cluster of similar observations to be merged */\r\nexport interface ConsolidationCluster {\r\n /** IDs of observations in this cluster */\r\n ids: number[];\r\n /** Titles of observations in this cluster */\r\n titles: string[];\r\n /** Average pairwise similarity */\r\n similarity: number;\r\n /** The entity these belong to */\r\n entityName: string;\r\n /** The observation type */\r\n type: string;\r\n}\r\n\r\n/** Result of a consolidation run */\r\nexport interface ConsolidationResult {\r\n /** Number of clusters found */\r\n clustersFound: number;\r\n /** Number of observations merged */\r\n observationsMerged: number;\r\n /** Number of observations after consolidation */\r\n observationsAfter: number;\r\n /** Details of each merge */\r\n merges: Array<{\r\n clusterId: number;\r\n mergedIds: number[];\r\n resultTitle: string;\r\n factCount: number;\r\n }>;\r\n}\r\n\r\n/**\r\n * Find clusters of similar observations that could be consolidated.\r\n * Does NOT modify data — use this for preview / dry run.\r\n */\r\nexport async function findConsolidationCandidates(\r\n projectDir: string,\r\n projectId: string,\r\n opts?: { threshold?: number; limit?: number },\r\n): Promise<ConsolidationCluster[]> {\r\n const threshold = opts?.threshold ?? DEFAULT_SIMILARITY_THRESHOLD;\r\n const limit = opts?.limit ?? MAX_BATCH_SIZE;\r\n\r\n const store = getObservationStore();\r\n const allObs = await store.loadAll();\r\n const projectObs = allObs\r\n .filter(o => o.projectId === projectId)\r\n .slice(0, limit);\r\n\r\n if (projectObs.length < MIN_CLUSTER_SIZE) return [];\r\n\r\n // Group by entity + type\r\n const groups = new Map<string, Observation[]>();\r\n for (const obs of projectObs) {\r\n const key = `${obs.entityName}::${obs.type}`;\r\n if (!groups.has(key)) groups.set(key, []);\r\n groups.get(key)!.push(obs);\r\n }\r\n\r\n const clusters: ConsolidationCluster[] = [];\r\n\r\n for (const [, group] of groups) {\r\n if (group.length < MIN_CLUSTER_SIZE) continue;\r\n\r\n // High-value types require much higher similarity to merge\r\n const groupType = group[0].type;\r\n const effectiveThreshold = HIGH_VALUE_TYPES.has(groupType)\r\n ? Math.max(threshold, HIGH_VALUE_SIMILARITY_THRESHOLD)\r\n : threshold;\r\n\r\n // Pre-compute fingerprints\r\n const fingerprints = group.map(obs => ({\r\n obs,\r\n tokens: tokenize(observationFingerprint(obs)),\r\n }));\r\n\r\n // Track which observations are already clustered\r\n const clustered = new Set<number>();\r\n\r\n // Greedy clustering: for each unclustered obs, find similar ones\r\n for (let i = 0; i < fingerprints.length; i++) {\r\n if (clustered.has(fingerprints[i].obs.id)) continue;\r\n\r\n const cluster: Observation[] = [fingerprints[i].obs];\r\n let totalSim = 0;\r\n let simCount = 0;\r\n\r\n for (let j = i + 1; j < fingerprints.length; j++) {\r\n if (clustered.has(fingerprints[j].obs.id)) continue;\r\n\r\n const sim = jaccardSimilarity(fingerprints[i].tokens, fingerprints[j].tokens);\r\n if (sim >= effectiveThreshold) {\r\n cluster.push(fingerprints[j].obs);\r\n totalSim += sim;\r\n simCount++;\r\n }\r\n }\r\n\r\n if (cluster.length >= MIN_CLUSTER_SIZE) {\r\n for (const obs of cluster) clustered.add(obs.id);\r\n clusters.push({\r\n ids: cluster.map(o => o.id),\r\n titles: cluster.map(o => o.title),\r\n similarity: simCount > 0 ? totalSim / simCount : 0,\r\n entityName: cluster[0].entityName,\r\n type: cluster[0].type,\r\n });\r\n }\r\n }\r\n }\r\n\r\n return clusters;\r\n}\r\n\r\n/**\r\n * Execute consolidation — merge clusters into single observations.\r\n *\r\n * For each cluster:\r\n * 1. Keep the most recent observation as the \"primary\"\r\n * 2. Merge facts, files, concepts from all members (deduplicated)\r\n * 3. Create a consolidated narrative\r\n * 4. Remove the other members\r\n */\r\nexport async function executeConsolidation(\r\n projectDir: string,\r\n projectId: string,\r\n opts?: { threshold?: number; limit?: number },\r\n): Promise<ConsolidationResult> {\r\n const clusters = await findConsolidationCandidates(projectDir, projectId, opts);\r\n\r\n const store = getObservationStore();\r\n\r\n if (clusters.length === 0) {\r\n const allObs = await store.loadAll();\r\n return {\r\n clustersFound: 0,\r\n observationsMerged: 0,\r\n observationsAfter: allObs.filter(o => o.projectId === projectId).length,\r\n merges: [],\r\n };\r\n }\r\n\r\n const result: ConsolidationResult = {\r\n clustersFound: clusters.length,\r\n observationsMerged: 0,\r\n observationsAfter: 0,\r\n merges: [],\r\n };\r\n\r\n await store.atomic(async (tx) => {\r\n const allObs = await tx.loadAll();\r\n const obsMap = new Map(allObs.map(o => [o.id, o]));\r\n const idsToRemove = new Set<number>();\r\n\r\n for (let ci = 0; ci < clusters.length; ci++) {\r\n const cluster = clusters[ci];\r\n const members = cluster.ids\r\n .map(id => obsMap.get(id))\r\n .filter((o): o is Observation => o !== undefined);\r\n\r\n if (members.length < MIN_CLUSTER_SIZE) continue;\r\n\r\n // Sort by date — most recent first\r\n members.sort((a, b) =>\r\n new Date(b.updatedAt || b.createdAt).getTime() -\r\n new Date(a.updatedAt || a.createdAt).getTime(),\r\n );\r\n\r\n const primary = members[0];\r\n const others = members.slice(1);\r\n\r\n // Merge facts (deduplicated)\r\n const allFacts = new Set(primary.facts);\r\n for (const other of others) {\r\n for (const fact of other.facts) allFacts.add(fact);\r\n }\r\n\r\n // Merge files (deduplicated, case-insensitive)\r\n const fileSet = new Set(primary.filesModified.map(f => f.toLowerCase()));\r\n const allFiles = [...primary.filesModified];\r\n for (const other of others) {\r\n for (const f of other.filesModified) {\r\n if (!fileSet.has(f.toLowerCase())) {\r\n fileSet.add(f.toLowerCase());\r\n allFiles.push(f);\r\n }\r\n }\r\n }\r\n\r\n // Merge concepts (deduplicated)\r\n const conceptSet = new Set(primary.concepts);\r\n for (const other of others) {\r\n for (const c of other.concepts) conceptSet.add(c);\r\n }\r\n\r\n // Build consolidated narrative\r\n const narrativeParts = [primary.narrative];\r\n for (const other of others) {\r\n if (other.narrative !== primary.narrative) {\r\n narrativeParts.push(`[Consolidated from #${other.id}] ${other.narrative}`);\r\n }\r\n }\r\n\r\n // Update primary\r\n primary.facts = [...allFacts];\r\n primary.filesModified = allFiles;\r\n primary.concepts = [...conceptSet];\r\n primary.narrative = narrativeParts.join('\\n\\n');\r\n primary.updatedAt = new Date().toISOString();\r\n primary.revisionCount = (primary.revisionCount ?? 1) + others.length;\r\n\r\n // Mark others for removal\r\n for (const other of others) {\r\n idsToRemove.add(other.id);\r\n }\r\n\r\n result.observationsMerged += others.length;\r\n result.merges.push({\r\n clusterId: ci,\r\n mergedIds: cluster.ids,\r\n resultTitle: primary.title,\r\n factCount: primary.facts.length,\r\n });\r\n }\r\n\r\n // Remove merged observations\r\n const remaining = allObs.filter(o => !idsToRemove.has(o.id));\r\n await tx.saveAll(remaining);\r\n\r\n result.observationsAfter = remaining.filter(o => o.projectId === projectId).length;\r\n });\r\n\r\n return result;\r\n}\r\n","/**\r\n * TeamStore - SQLite-backed persistence for autonomous Agent Team state.\n *\r\n * Phase 4a: Replaces the file-based team-state.json persistence with\r\n * SQLite prepared statements on the shared DB handle (memorix.db).\r\n *\r\n * Provides:\r\n * - Singleton init/get/reset pattern (same as SessionStore)\r\n * - Shared DB handle via getDatabase()\r\n * - One-time migration from team-state.json\r\n * - Prepared statements for all team CRUD operations\r\n *\r\n * All team modules (registry, messages, tasks, locks) delegate to this store.\r\n */\r\n\r\nimport { randomUUID } from 'node:crypto';\r\nimport { getDatabase } from '../store/sqlite-db.js';\r\nimport path from 'node:path';\r\nimport fs from 'node:fs';\r\nimport type { TeamEventBus } from './event-bus.js';\r\n\r\n// ── Types ───────────────────────────────────────────────────────────\r\n\r\nexport interface TeamAgentRow {\r\n agent_id: string;\r\n project_id: string;\r\n agent_type: string;\r\n instance_id: string;\r\n name: string;\r\n role: string | null;\r\n capabilities: string | null; // JSON array\r\n status: 'active' | 'inactive';\r\n joined_at: number;\r\n last_heartbeat: number;\r\n left_at: number | null;\r\n last_seen_obs_generation: number;\r\n}\r\n\r\nexport interface TeamMessageRow {\r\n id: string;\r\n project_id: string;\r\n sender_agent_id: string;\r\n recipient_agent_id: string | null; // NULL = broadcast\r\n type: string;\r\n content: string;\r\n payload: string | null; // JSON\r\n task_id: string | null;\r\n read_at: number | null;\r\n created_at: number;\r\n to_role: string | null;\r\n handoff_status: string | null; // 'open' | 'claimed' | 'completed' | 'archived'\r\n}\r\n\r\nexport interface TeamTaskRow {\r\n task_id: string;\r\n project_id: string;\r\n description: string;\r\n status: 'pending' | 'in_progress' | 'completed' | 'failed';\r\n assignee_agent_id: string | null;\r\n result: string | null;\r\n metadata: string | null; // JSON\r\n created_by: string | null;\r\n created_at: number;\r\n updated_at: number;\r\n required_role: string | null;\r\n preferred_role: string | null;\r\n}\r\n\r\nexport interface TeamLockRow {\r\n file: string;\r\n project_id: string;\r\n locked_by: string;\r\n locked_at: number;\r\n expires_at: number;\r\n}\r\n\r\nexport interface TeamRoleRow {\r\n role_id: string;\r\n project_id: string;\r\n label: string;\r\n description: string | null;\r\n preferred_agent_types: string; // JSON array\r\n max_concurrent: number;\r\n created_at: number;\r\n}\r\n\r\n/** Default role definitions seeded per project */\r\nexport const DEFAULT_ROLES: Array<{ roleId: string; label: string; description: string; preferredAgentTypes: string[]; maxConcurrent: number }> = [\r\n { roleId: 'planner', label: 'Planner', description: 'Breaks down requirements, creates tasks, defines dependencies', preferredAgentTypes: ['claude-code', 'cursor', 'codex'], maxConcurrent: 2 },\r\n { roleId: 'researcher', label: 'Researcher', description: 'Investigates codebase, gathers context, answers questions', preferredAgentTypes: ['claude-code', 'cursor', 'gemini-cli'], maxConcurrent: 2 },\r\n { roleId: 'engineer', label: 'Engineer', description: 'Implements features, fixes bugs, writes tests', preferredAgentTypes: ['claude-code', 'cursor', 'codex', 'windsurf', 'opencode'], maxConcurrent: 4 },\r\n { roleId: 'reviewer', label: 'Reviewer', description: 'Reviews code, validates quality, checks consistency', preferredAgentTypes: ['claude-code', 'codex'], maxConcurrent: 2 },\r\n { roleId: 'qa', label: 'QA', description: 'Runs tests, verifies fixes, validates edge cases', preferredAgentTypes: ['codex', 'claude-code'], maxConcurrent: 2 },\r\n { roleId: 'ops', label: 'Ops', description: 'Deploys, monitors, manages infrastructure and configuration', preferredAgentTypes: ['codex', 'claude-code'], maxConcurrent: 1 },\r\n];\r\n\r\n/** Map agentType → default role */\r\nexport const AGENT_TYPE_ROLE_MAP: Record<string, string> = {\r\n 'claude-code': 'engineer',\r\n 'cursor': 'engineer',\r\n 'codex': 'engineer',\r\n 'windsurf': 'engineer',\r\n 'opencode': 'engineer',\r\n 'gemini-cli': 'researcher',\r\n 'antigravity': 'researcher',\r\n 'copilot': 'engineer',\r\n 'kiro': 'engineer',\r\n 'trae': 'engineer',\r\n};\r\n\r\n// ── TeamStore ────────────────────────────────────────────────────────\r\n\r\nexport class TeamStore {\r\n private db: any = null;\r\n private dataDir: string = '';\r\n\r\n /** Optional event bus for same-process lifecycle notifications.\r\n * Set via setEventBus(). Emit failures never block TeamStore writes. */\r\n private eventBus: TeamEventBus | null = null;\r\n\r\n setEventBus(bus: TeamEventBus): void { this.eventBus = bus; }\r\n getEventBus(): TeamEventBus | null { return this.eventBus; }\r\n\r\n // ── Agent prepared statements\r\n private stmtAgentUpsert: any = null;\r\n private stmtAgentFindByInstance: any = null;\r\n private stmtAgentFindById: any = null;\r\n private stmtAgentListByProject: any = null;\r\n private stmtAgentUpdateHeartbeat: any = null;\r\n private stmtAgentLeave: any = null;\r\n private stmtAgentUpdateWatermark: any = null;\r\n\r\n // ── Message prepared statements\r\n private stmtMsgInsert: any = null;\r\n private stmtMsgInbox: any = null;\r\n private stmtMsgMarkRead: any = null;\r\n private stmtMsgMarkAllRead: any = null;\r\n private stmtMsgUnreadCount: any = null;\r\n private stmtMsgPruneRead: any = null;\r\n private stmtMsgClearInbox: any = null;\r\n private stmtMsgById: any = null;\r\n\r\n // ── Task prepared statements\r\n private stmtTaskInsert: any = null;\r\n private stmtTaskClaim: any = null;\r\n private stmtTaskReClaim: any = null;\r\n private stmtTaskComplete: any = null;\r\n private stmtTaskFail: any = null;\r\n private stmtTaskRelease: any = null;\r\n private stmtTaskReleaseByAgent: any = null;\r\n private stmtTaskById: any = null;\r\n private stmtTaskListByProject: any = null;\r\n private stmtTaskAvailable: any = null;\r\n private stmtTaskDepInsert: any = null;\r\n private stmtTaskDepsByTask: any = null;\r\n private stmtTaskUnmetDeps: any = null;\r\n\r\n // ── Lock prepared statements\r\n private stmtLockUpsert: any = null;\r\n private stmtLockGet: any = null;\r\n private stmtLockDelete: any = null;\r\n private stmtLockListByProject: any = null;\r\n private stmtLockListByAgent: any = null;\r\n private stmtLockDeleteByAgent: any = null;\r\n private stmtLockDeleteExpired: any = null;\r\n\r\n // ── Role prepared statements\r\n private stmtRoleInsert: any = null;\r\n private stmtRoleDelete: any = null;\r\n private stmtRoleListByProject: any = null;\r\n private stmtRoleGetById: any = null;\r\n private stmtRoleCountByProject: any = null;\r\n\r\n async init(dataDir: string): Promise<void> {\r\n this.dataDir = dataDir;\r\n this.db = getDatabase(dataDir);\r\n\r\n this.prepareAgentStatements();\r\n this.prepareMessageStatements();\r\n this.prepareTaskStatements();\r\n this.prepareLockStatements();\r\n this.prepareRoleStatements();\r\n\r\n // Seed default roles for this project if none exist\r\n this.seedDefaultRoles(dataDir);\r\n\r\n // One-time migration from team-state.json\r\n await this.migrateFromJsonIfNeeded();\r\n }\r\n\r\n // ── Agent statements ──────────────────────────────────────────────\r\n\r\n private prepareAgentStatements(): void {\r\n this.stmtAgentUpsert = this.db.prepare(`\r\n INSERT INTO team_agents\r\n (agent_id, project_id, agent_type, instance_id, name, role, capabilities, status, joined_at, last_heartbeat, left_at, last_seen_obs_generation)\r\n VALUES\r\n (@agent_id, @project_id, @agent_type, @instance_id, @name, @role, @capabilities, @status, @joined_at, @last_heartbeat, @left_at, @last_seen_obs_generation)\r\n ON CONFLICT(project_id, agent_type, instance_id) DO UPDATE SET\r\n name = excluded.name,\r\n role = excluded.role,\r\n capabilities = excluded.capabilities,\r\n status = excluded.status,\r\n last_heartbeat = excluded.last_heartbeat,\r\n left_at = excluded.left_at\r\n `);\r\n\r\n this.stmtAgentFindByInstance = this.db.prepare(\r\n `SELECT * FROM team_agents WHERE project_id = ? AND agent_type = ? AND instance_id = ?`\r\n );\r\n\r\n this.stmtAgentFindById = this.db.prepare(\r\n `SELECT * FROM team_agents WHERE agent_id = ?`\r\n );\r\n\r\n this.stmtAgentListByProject = this.db.prepare(\r\n `SELECT * FROM team_agents WHERE project_id = ? ORDER BY joined_at DESC`\r\n );\r\n\r\n this.stmtAgentUpdateHeartbeat = this.db.prepare(\r\n `UPDATE team_agents SET last_heartbeat = ? WHERE agent_id = ?`\r\n );\r\n\r\n this.stmtAgentLeave = this.db.prepare(\r\n `UPDATE team_agents SET status = 'inactive', left_at = ? WHERE agent_id = ?`\r\n );\r\n\r\n this.stmtAgentUpdateWatermark = this.db.prepare(\r\n `UPDATE team_agents SET last_seen_obs_generation = ?, last_heartbeat = ? WHERE agent_id = ?`\r\n );\r\n }\r\n\r\n // ── Message statements ────────────────────────────────────────────\r\n\r\n private prepareMessageStatements(): void {\r\n this.stmtMsgInsert = this.db.prepare(`\r\n INSERT INTO team_messages\r\n (id, project_id, sender_agent_id, recipient_agent_id, type, content, payload, task_id, read_at, created_at, to_role, handoff_status)\r\n VALUES\r\n (@id, @project_id, @sender_agent_id, @recipient_agent_id, @type, @content, @payload, @task_id, @read_at, @created_at, @to_role, @handoff_status)\r\n `);\r\n\r\n // Inbox: messages where I am the recipient OR recipient is NULL (broadcast)\r\n this.stmtMsgInbox = this.db.prepare(`\r\n SELECT * FROM team_messages\r\n WHERE project_id = ?\r\n AND (recipient_agent_id = ? OR recipient_agent_id IS NULL)\r\n ORDER BY created_at ASC\r\n `);\r\n\r\n this.stmtMsgMarkRead = this.db.prepare(\r\n `UPDATE team_messages SET read_at = ? WHERE id = ? AND read_at IS NULL`\r\n );\r\n\r\n this.stmtMsgMarkAllRead = this.db.prepare(\r\n `UPDATE team_messages SET read_at = ?\r\n WHERE project_id = ?\r\n AND (recipient_agent_id = ? OR recipient_agent_id IS NULL)\r\n AND read_at IS NULL`\r\n );\r\n\r\n this.stmtMsgUnreadCount = this.db.prepare(`\r\n SELECT COUNT(*) AS cnt FROM team_messages\r\n WHERE project_id = ?\r\n AND (recipient_agent_id = ? OR recipient_agent_id IS NULL)\r\n AND read_at IS NULL\r\n `);\r\n\r\n this.stmtMsgPruneRead = this.db.prepare(\r\n `DELETE FROM team_messages WHERE project_id = ? AND read_at IS NOT NULL AND read_at < ?`\r\n );\r\n\r\n this.stmtMsgClearInbox = this.db.prepare(\r\n `DELETE FROM team_messages WHERE project_id = ? AND recipient_agent_id = ?`\r\n );\r\n\r\n this.stmtMsgById = this.db.prepare(\r\n `SELECT * FROM team_messages WHERE id = ?`\r\n );\r\n }\r\n\r\n // ── Task statements ───────────────────────────────────────────────\r\n\r\n private prepareTaskStatements(): void {\r\n this.stmtTaskInsert = this.db.prepare(`\r\n INSERT INTO team_tasks\r\n (task_id, project_id, description, status, assignee_agent_id, result, metadata, created_by, created_at, updated_at, required_role, preferred_role)\r\n VALUES\r\n (@task_id, @project_id, @description, @status, @assignee_agent_id, @result, @metadata, @created_by, @created_at, @updated_at, @required_role, @preferred_role)\r\n `);\r\n\r\n // Atomic claim: WHERE guards prevent race conditions across processes\r\n this.stmtTaskClaim = this.db.prepare(`\r\n UPDATE team_tasks\r\n SET assignee_agent_id = ?, status = 'in_progress', updated_at = ?\r\n WHERE task_id = ? AND status = 'pending' AND assignee_agent_id IS NULL\r\n `);\r\n\r\n // Re-claim: same agent re-claiming its own task (idempotent)\r\n this.stmtTaskReClaim = this.db.prepare(`\r\n UPDATE team_tasks SET updated_at = ?\r\n WHERE task_id = ? AND assignee_agent_id = ? AND status = 'in_progress'\r\n `);\r\n\r\n this.stmtTaskComplete = this.db.prepare(`\r\n UPDATE team_tasks\r\n SET status = 'completed', result = ?, updated_at = ?\r\n WHERE task_id = ? AND assignee_agent_id = ? AND status = 'in_progress'\r\n `);\r\n\r\n this.stmtTaskFail = this.db.prepare(`\r\n UPDATE team_tasks\r\n SET status = 'failed', result = ?, updated_at = ?\r\n WHERE task_id = ? AND assignee_agent_id = ? AND status = 'in_progress'\r\n `);\r\n\r\n this.stmtTaskRelease = this.db.prepare(`\r\n UPDATE team_tasks\r\n SET status = 'pending', assignee_agent_id = NULL, updated_at = ?\r\n WHERE task_id = ? AND assignee_agent_id = ? AND status = 'in_progress'\r\n `);\r\n\r\n // Stale rescue: release all tasks held by a departed agent\r\n this.stmtTaskReleaseByAgent = this.db.prepare(`\r\n UPDATE team_tasks\r\n SET status = 'pending', assignee_agent_id = NULL, updated_at = ?\r\n WHERE assignee_agent_id = ? AND status = 'in_progress'\r\n `);\r\n\r\n this.stmtTaskById = this.db.prepare(\r\n `SELECT * FROM team_tasks WHERE task_id = ?`\r\n );\r\n\r\n this.stmtTaskListByProject = this.db.prepare(\r\n `SELECT * FROM team_tasks WHERE project_id = ? ORDER BY created_at DESC`\r\n );\r\n\r\n this.stmtTaskAvailable = this.db.prepare(\r\n `SELECT * FROM team_tasks WHERE project_id = ? AND status = 'pending' AND assignee_agent_id IS NULL ORDER BY created_at ASC`\r\n );\r\n\r\n this.stmtTaskDepInsert = this.db.prepare(\r\n `INSERT OR IGNORE INTO team_task_deps (task_id, dep_task_id) VALUES (?, ?)`\r\n );\r\n\r\n this.stmtTaskDepsByTask = this.db.prepare(\r\n `SELECT dep_task_id FROM team_task_deps WHERE task_id = ?`\r\n );\r\n\r\n // Count unmet dependencies for a task\r\n this.stmtTaskUnmetDeps = this.db.prepare(`\r\n SELECT COUNT(*) AS cnt FROM team_task_deps d\r\n JOIN team_tasks t ON d.dep_task_id = t.task_id\r\n WHERE d.task_id = ? AND t.status != 'completed'\r\n `);\r\n }\r\n\r\n // ── Lock statements ───────────────────────────────────────────────\r\n\r\n private prepareLockStatements(): void {\r\n this.stmtLockUpsert = this.db.prepare(`\r\n INSERT INTO team_locks (file, project_id, locked_by, locked_at, expires_at)\r\n VALUES (@file, @project_id, @locked_by, @locked_at, @expires_at)\r\n ON CONFLICT(file, project_id) DO UPDATE SET\r\n locked_by = excluded.locked_by,\r\n locked_at = excluded.locked_at,\r\n expires_at = excluded.expires_at\r\n `);\r\n\r\n this.stmtLockGet = this.db.prepare(\r\n `SELECT * FROM team_locks WHERE file = ? AND project_id = ?`\r\n );\r\n\r\n this.stmtLockDelete = this.db.prepare(\r\n `DELETE FROM team_locks WHERE file = ? AND project_id = ?`\r\n );\r\n\r\n this.stmtLockListByProject = this.db.prepare(\r\n `SELECT * FROM team_locks WHERE project_id = ? ORDER BY locked_at DESC`\r\n );\r\n\r\n this.stmtLockListByAgent = this.db.prepare(\r\n `SELECT * FROM team_locks WHERE project_id = ? AND locked_by = ? ORDER BY locked_at DESC`\r\n );\r\n\r\n this.stmtLockDeleteByAgent = this.db.prepare(\r\n `DELETE FROM team_locks WHERE locked_by = ?`\r\n );\r\n\r\n this.stmtLockDeleteExpired = this.db.prepare(\r\n `DELETE FROM team_locks WHERE project_id = ? AND expires_at <= ?`\r\n );\r\n }\r\n\r\n // ═══════════════════════════════════════════════════════════════════\r\n // Agent Operations\r\n // ═══════════════════════════════════════════════════════════════════\r\n\r\n /**\r\n * Register or reactivate an agent.\r\n * If an agent with the same (project_id, agent_type, instance_id) exists,\r\n * reactivate it (preserving agent_id). Otherwise create a new one.\r\n */\r\n registerAgent(input: {\r\n projectId: string;\r\n agentType: string;\r\n instanceId?: string;\r\n name?: string;\r\n role?: string;\r\n capabilities?: string[];\r\n }): TeamAgentRow {\r\n const instanceId = input.instanceId || randomUUID();\r\n const now = Date.now();\r\n\r\n // Check for existing agent by instance key\r\n const existing = this.stmtAgentFindByInstance.get(\r\n input.projectId, input.agentType, instanceId\r\n ) as TeamAgentRow | undefined;\r\n\r\n if (existing) {\r\n // Reactivate — preserve agent_id, update heartbeat and metadata\r\n this.stmtAgentUpsert.run({\r\n agent_id: existing.agent_id,\r\n project_id: input.projectId,\r\n agent_type: input.agentType,\r\n instance_id: instanceId,\r\n name: input.name ?? existing.name,\r\n role: input.role ?? existing.role,\r\n capabilities: input.capabilities ? JSON.stringify(input.capabilities) : existing.capabilities,\r\n status: 'active',\r\n joined_at: existing.joined_at,\r\n last_heartbeat: now,\r\n left_at: null,\r\n last_seen_obs_generation: existing.last_seen_obs_generation,\r\n });\r\n const row = this.stmtAgentFindById.get(existing.agent_id) as TeamAgentRow;\r\n this.eventBus?.emit('agent:joined', { agentId: row.agent_id, projectId: input.projectId, agentType: input.agentType });\r\n return row;\r\n }\r\n\r\n // New agent\r\n const agentId = randomUUID();\r\n this.stmtAgentUpsert.run({\r\n agent_id: agentId,\r\n project_id: input.projectId,\r\n agent_type: input.agentType,\r\n instance_id: instanceId,\r\n name: input.name || input.agentType,\r\n role: input.role ?? null,\r\n capabilities: input.capabilities ? JSON.stringify(input.capabilities) : null,\r\n status: 'active',\r\n joined_at: now,\r\n last_heartbeat: now,\r\n left_at: null,\r\n last_seen_obs_generation: 0,\r\n });\r\n const row = this.stmtAgentFindById.get(agentId) as TeamAgentRow;\r\n this.eventBus?.emit('agent:joined', { agentId: row.agent_id, projectId: input.projectId, agentType: input.agentType });\r\n return row;\r\n }\r\n\r\n getAgent(agentId: string): TeamAgentRow | undefined {\r\n return this.stmtAgentFindById.get(agentId) as TeamAgentRow | undefined;\r\n }\r\n\r\n getAgentByInstance(projectId: string, agentType: string, instanceId: string): TeamAgentRow | undefined {\r\n return this.stmtAgentFindByInstance.get(projectId, agentType, instanceId) as TeamAgentRow | undefined;\r\n }\r\n\r\n listAgents(projectId: string, filter?: { status?: 'active' | 'inactive' }): TeamAgentRow[] {\r\n const all = this.stmtAgentListByProject.all(projectId) as TeamAgentRow[];\r\n if (filter?.status) {\r\n return all.filter(a => a.status === filter.status);\r\n }\r\n return all;\r\n }\r\n\r\n /** List agents across all projects (for global scope) */\r\n listAllAgents(): TeamAgentRow[] {\r\n if (!this.db) return [];\r\n return this.db.prepare('SELECT * FROM team_agents ORDER BY last_heartbeat DESC').all() as TeamAgentRow[];\r\n }\r\n\r\n /** List locks across all projects (for global scope) */\r\n listAllLocks(): TeamLockRow[] {\r\n if (!this.db) return [];\r\n // Clean expired globally (not per-project) — bypass stmtLockDeleteExpired which scopes to project_id\r\n this.db.prepare('DELETE FROM team_locks WHERE expires_at <= ?').run(Date.now());\r\n return this.db.prepare('SELECT * FROM team_locks WHERE expires_at > ? ORDER BY locked_at DESC').all(Date.now()) as TeamLockRow[];\r\n }\r\n\r\n /** List tasks across all projects (for global scope) */\r\n listAllTasks(filter?: { available?: boolean }): TeamTaskRow[] {\r\n if (!this.db) return [];\r\n if (filter?.available) {\r\n return this.db.prepare(\r\n `SELECT t.* FROM team_tasks t WHERE t.status = 'pending' AND t.assignee_agent_id IS NULL ORDER BY t.created_at DESC`\r\n ).all() as TeamTaskRow[];\r\n }\r\n return this.db.prepare('SELECT * FROM team_tasks ORDER BY created_at DESC').all() as TeamTaskRow[];\r\n }\r\n\r\n heartbeat(agentId: string): boolean {\r\n const info = this.stmtAgentUpdateHeartbeat.run(Date.now(), agentId);\r\n return info.changes > 0;\r\n }\r\n\r\n leaveAgent(agentId: string): boolean {\r\n const agent = this.stmtAgentFindById.get(agentId) as TeamAgentRow | undefined;\r\n const info = this.stmtAgentLeave.run(Date.now(), agentId);\r\n if (info.changes > 0 && agent) {\r\n this.eventBus?.emit('agent:left', { agentId, projectId: agent.project_id });\r\n }\r\n return info.changes > 0;\r\n }\r\n\r\n updateWatermark(agentId: string, generation: number): void {\r\n this.stmtAgentUpdateWatermark.run(generation, Date.now(), agentId);\r\n }\r\n\r\n /**\r\n * Detect and mark stale agents. Returns list of stale agent IDs whose tasks/locks were released.\r\n */\r\n detectAndMarkStale(projectId: string, staleTtlMs: number): string[] {\r\n const threshold = Date.now() - staleTtlMs;\r\n const staleAgents = (this.stmtAgentListByProject.all(projectId) as TeamAgentRow[])\r\n .filter(a => a.status === 'active' && a.last_heartbeat < threshold);\r\n\r\n const staleIds: string[] = [];\r\n const now = Date.now();\r\n for (const agent of staleAgents) {\r\n this.stmtAgentLeave.run(now, agent.agent_id);\r\n // Release tasks\r\n const released = this.stmtTaskReleaseByAgent.run(now, agent.agent_id);\r\n // Release locks\r\n this.stmtLockDeleteByAgent.run(agent.agent_id);\r\n staleIds.push(agent.agent_id);\r\n // Lifecycle hook: stale agent detected (best-effort)\r\n this.eventBus?.emit('agent:stale', { agentId: agent.agent_id, projectId, releasedTasks: released.changes });\r\n }\r\n return staleIds;\r\n }\r\n\r\n getActiveCount(projectId: string): number {\r\n return this.listAgents(projectId, { status: 'active' }).length;\r\n }\r\n\r\n // ═══════════════════════════════════════════════════════════════════\r\n // Message Operations\r\n // ═══════════════════════════════════════════════════════════════════\r\n\r\n sendMessage(input: {\r\n projectId: string;\r\n senderAgentId: string;\r\n recipientAgentId?: string | null;\r\n type: string;\r\n content: string;\r\n payload?: Record<string, unknown>;\r\n taskId?: string;\r\n toRole?: string | null;\r\n handoffStatus?: string | null;\r\n }): TeamMessageRow | { error: string } {\r\n // Validate sender exists\r\n const sender = this.stmtAgentFindById.get(input.senderAgentId) as TeamAgentRow | undefined;\r\n if (!sender) {\r\n return { error: `Sender agent '${input.senderAgentId}' not found — cannot create message from unknown agent` };\r\n }\r\n\r\n // Validate direct recipient exists (broadcast with null recipient is allowed)\r\n if (input.recipientAgentId) {\r\n const recipient = this.stmtAgentFindById.get(input.recipientAgentId) as TeamAgentRow | undefined;\r\n if (!recipient) {\r\n return { error: `Recipient agent '${input.recipientAgentId}' not found — cannot send to unknown agent` };\r\n }\r\n }\r\n\r\n const id = randomUUID();\r\n const now = Date.now();\r\n const row: TeamMessageRow = {\r\n id,\r\n project_id: input.projectId,\r\n sender_agent_id: input.senderAgentId,\r\n recipient_agent_id: input.recipientAgentId ?? null,\r\n type: input.type,\r\n content: input.content,\r\n payload: input.payload ? JSON.stringify(input.payload) : null,\r\n task_id: input.taskId ?? null,\r\n read_at: null,\r\n created_at: now,\r\n to_role: input.toRole ?? null,\r\n handoff_status: input.handoffStatus ?? null,\r\n };\r\n this.stmtMsgInsert.run(row);\r\n return row;\r\n }\r\n\r\n getInbox(projectId: string, agentId: string): TeamMessageRow[] {\r\n return this.stmtMsgInbox.all(projectId, agentId) as TeamMessageRow[];\r\n }\r\n\r\n getUnreadCount(projectId: string, agentId: string): number {\r\n const row = this.stmtMsgUnreadCount.get(projectId, agentId) as { cnt: number };\r\n return row.cnt;\r\n }\r\n\r\n markMessageRead(messageId: string): boolean {\r\n const info = this.stmtMsgMarkRead.run(Date.now(), messageId);\r\n return info.changes > 0;\r\n }\r\n\r\n markAllRead(projectId: string, agentId: string): number {\r\n const info = this.stmtMsgMarkAllRead.run(Date.now(), projectId, agentId);\r\n return info.changes;\r\n }\r\n\r\n pruneReadMessages(projectId: string, olderThanMs: number): number {\r\n const threshold = Date.now() - olderThanMs;\r\n const info = this.stmtMsgPruneRead.run(projectId, threshold);\r\n return info.changes;\r\n }\r\n\r\n clearInbox(projectId: string, agentId: string): number {\r\n const info = this.stmtMsgClearInbox.run(projectId, agentId);\r\n return info.changes;\r\n }\r\n\r\n getMessageById(messageId: string): TeamMessageRow | undefined {\r\n return this.stmtMsgById.get(messageId) as TeamMessageRow | undefined;\r\n }\r\n\r\n // ═══════════════════════════════════════════════════════════════════\r\n // Task Operations (with atomic claim semantics)\r\n // ═══════════════════════════════════════════════════════════════════\r\n\r\n createTask(input: {\r\n projectId: string;\r\n description: string;\r\n deps?: string[];\r\n metadata?: Record<string, unknown>;\r\n createdBy?: string;\r\n requiredRole?: string | null;\r\n preferredRole?: string | null;\r\n }): TeamTaskRow {\r\n const taskId = randomUUID();\r\n const now = Date.now();\r\n const row: TeamTaskRow = {\r\n task_id: taskId,\r\n project_id: input.projectId,\r\n description: input.description,\r\n status: 'pending',\r\n assignee_agent_id: null,\r\n result: null,\r\n metadata: input.metadata ? JSON.stringify(input.metadata) : null,\r\n created_by: input.createdBy ?? null,\r\n created_at: now,\r\n updated_at: now,\r\n required_role: input.requiredRole ?? null,\r\n preferred_role: input.preferredRole ?? null,\r\n };\r\n this.stmtTaskInsert.run(row);\r\n\r\n // Insert dependencies\r\n if (input.deps?.length) {\r\n for (const depId of input.deps) {\r\n this.stmtTaskDepInsert.run(taskId, depId);\r\n }\r\n }\r\n\r\n // Lifecycle hook: task created (best-effort, after successful write)\r\n this.eventBus?.emit('task:created', { taskId, projectId: input.projectId, description: input.description });\r\n\r\n return row;\r\n }\r\n\r\n getTask(taskId: string): TeamTaskRow | undefined {\r\n return this.stmtTaskById.get(taskId) as TeamTaskRow | undefined;\r\n }\r\n\r\n getTaskDeps(taskId: string): string[] {\r\n const rows = this.stmtTaskDepsByTask.all(taskId) as { dep_task_id: string }[];\r\n return rows.map(r => r.dep_task_id);\r\n }\r\n\r\n /**\r\n * Atomic task claim with dependency check.\r\n * Uses BEGIN IMMEDIATE to serialize the dep check + claim atomically.\r\n * Returns { success, task, reason? }.\r\n */\r\n claimTask(taskId: string, agentId: string): { success: boolean; task?: TeamTaskRow; reason?: string; hint?: string } {\r\n const claimTx = this.db.transaction(() => {\r\n const task = this.stmtTaskById.get(taskId) as TeamTaskRow | undefined;\r\n if (!task) return { success: false, reason: 'Task not found' };\r\n\r\n // Allow same agent to re-claim\r\n if (task.assignee_agent_id === agentId && task.status === 'in_progress') {\r\n const now = Date.now();\r\n this.stmtTaskReClaim.run(now, taskId, agentId);\r\n return { success: true, task: { ...task, updated_at: now } };\r\n }\r\n\r\n // Role enforcement: required_role must match agent's role\r\n if (task.required_role) {\r\n const agent = this.stmtAgentFindById.get(agentId) as TeamAgentRow | undefined;\r\n const agentRole = agent?.role ?? '';\r\n if (agentRole !== task.required_role) {\r\n return {\r\n success: false,\r\n reason: `Role mismatch: task requires '${task.required_role}', agent has '${agentRole || 'no role'}'`,\r\n };\r\n }\r\n }\r\n\r\n // Check unmet dependencies\r\n const unmet = this.stmtTaskUnmetDeps.get(taskId) as { cnt: number };\r\n if (unmet.cnt > 0) {\r\n return { success: false, reason: `Cannot claim: ${unmet.cnt} unmet dependency(ies)` };\r\n }\r\n\r\n // Atomic claim\r\n const now = Date.now();\r\n const info = this.stmtTaskClaim.run(agentId, now, taskId);\r\n if (info.changes === 0) {\r\n // Another process claimed it or status changed\r\n const current = this.stmtTaskById.get(taskId) as TeamTaskRow;\r\n return {\r\n success: false,\r\n reason: current.assignee_agent_id\r\n ? `Task already claimed by ${current.assignee_agent_id}`\r\n : `Task status is ${current.status}, not pending`,\r\n };\r\n }\r\n\r\n // Preferred role hint (soft — claim succeeds, but inform the caller)\r\n let hint: string | undefined;\r\n if (task.preferred_role) {\r\n const agent = this.stmtAgentFindById.get(agentId) as TeamAgentRow | undefined;\r\n const agentRole = agent?.role ?? '';\r\n if (agentRole !== task.preferred_role) {\r\n hint = `Preferred role '${task.preferred_role}' not matched (agent has '${agentRole || 'no role'}') — claim still valid`;\r\n }\r\n }\r\n\r\n return { success: true, task: this.stmtTaskById.get(taskId) as TeamTaskRow, hint };\r\n });\r\n\r\n // Use immediate to acquire write lock before reading\r\n const result = claimTx.immediate();\r\n\r\n // Lifecycle hook: task claimed (best-effort, after successful write)\r\n if (result.success && result.task) {\r\n this.eventBus?.emit('task:claimed', { taskId, projectId: result.task.project_id, agentId });\r\n }\r\n\r\n return result;\r\n }\r\n\r\n completeTask(taskId: string, agentId: string, result?: string): { success: boolean; reason?: string } {\r\n const now = Date.now();\r\n const info = this.stmtTaskComplete.run(result ?? null, now, taskId, agentId);\r\n if (info.changes === 0) {\r\n return { success: false, reason: 'Not the assignee or task not in progress' };\r\n }\r\n\r\n // Lifecycle hook: task completed (best-effort)\r\n const task = this.stmtTaskById.get(taskId) as TeamTaskRow | undefined;\r\n if (task) {\r\n this.eventBus?.emit('task:completed', { taskId, projectId: task.project_id, agentId, result: result ?? undefined });\r\n }\r\n\r\n return { success: true };\r\n }\r\n\r\n failTask(taskId: string, agentId: string, result?: string): { success: boolean; reason?: string } {\r\n const now = Date.now();\r\n const info = this.stmtTaskFail.run(result ?? null, now, taskId, agentId);\r\n if (info.changes === 0) {\r\n return { success: false, reason: 'Not the assignee or task not in progress' };\r\n }\r\n\r\n // Lifecycle hook: task failed (best-effort)\r\n const task = this.stmtTaskById.get(taskId) as TeamTaskRow | undefined;\r\n if (task) {\r\n this.eventBus?.emit('task:failed', { taskId, projectId: task.project_id, agentId, result: result ?? undefined });\r\n }\r\n\r\n return { success: true };\r\n }\r\n\r\n releaseTask(taskId: string, agentId: string): { success: boolean; reason?: string } {\r\n const now = Date.now();\r\n const task = this.stmtTaskById.get(taskId) as TeamTaskRow | undefined;\r\n const info = this.stmtTaskRelease.run(now, taskId, agentId);\r\n if (info.changes === 0) {\r\n return { success: false, reason: 'Not the assignee or task not in progress' };\r\n }\r\n\r\n // Lifecycle hook: task released (best-effort)\r\n if (task) {\r\n this.eventBus?.emit('task:released', { taskId, projectId: task.project_id, agentId });\r\n }\r\n\r\n return { success: true };\r\n }\r\n\r\n releaseTasksByAgent(agentId: string): number {\r\n const now = Date.now();\r\n const info = this.stmtTaskReleaseByAgent.run(now, agentId);\r\n return info.changes;\r\n }\r\n\r\n listTasks(projectId: string, filter?: { status?: string; assignee?: string; available?: boolean }): TeamTaskRow[] {\r\n if (filter?.available) {\r\n return this.stmtTaskAvailable.all(projectId) as TeamTaskRow[];\r\n }\r\n const all = this.stmtTaskListByProject.all(projectId) as TeamTaskRow[];\r\n if (filter?.status) {\r\n return all.filter(t => t.status === filter.status);\r\n }\r\n if (filter?.assignee) {\r\n return all.filter(t => t.assignee_agent_id === filter.assignee);\r\n }\r\n return all;\r\n }\r\n\r\n /**\r\n * List available tasks for a specific agent, sorted by role affinity.\r\n * Tasks whose preferred_role matches the agent's role come first,\r\n * then tasks whose required_role matches, then role-agnostic tasks.\r\n * Tasks whose required_role does NOT match the agent's role are excluded.\r\n */\r\n listTasksForAgent(projectId: string, agentId: string): TeamTaskRow[] {\r\n const agent = this.stmtAgentFindById.get(agentId) as TeamAgentRow | undefined;\r\n if (!agent) return [];\r\n const agentRole = agent.role;\r\n\r\n const available = this.stmtTaskAvailable.all(projectId) as TeamTaskRow[];\r\n\r\n // Filter out tasks whose required_role doesn't match\r\n const eligible = available.filter(t => !t.required_role || t.required_role === agentRole);\r\n\r\n // Sort: preferred_role match → required_role match → no role constraint\r\n const score = (t: TeamTaskRow): number => {\r\n if (t.preferred_role === agentRole) return 0; // best match\r\n if (t.required_role === agentRole) return 1; // eligible but not preferred\r\n if (!t.required_role) return 2; // role-agnostic\r\n return 3; // shouldn't reach (filtered above)\r\n };\r\n\r\n eligible.sort((a, b) => score(a) - score(b));\r\n return eligible;\r\n }\r\n\r\n // ═══════════════════════════════════════════════════════════════════\r\n // Lock Operations\r\n // ═══════════════════════════════════════════════════════════════════\r\n\r\n private readonly DEFAULT_LOCK_TTL_MS = 10 * 60 * 1000; // 10 minutes\r\n\r\n acquireLock(projectId: string, file: string, agentId: string, ttlMs?: number): { success: boolean; lockedBy: string } {\r\n const ttl = ttlMs ?? this.DEFAULT_LOCK_TTL_MS;\r\n const now = Date.now();\r\n\r\n // Clean expired lock for this file first\r\n this.stmtLockDeleteExpired.run(projectId, now);\r\n\r\n const existing = this.stmtLockGet.get(file, projectId) as TeamLockRow | undefined;\r\n if (existing) {\r\n if (existing.locked_by === agentId) {\r\n // Same agent — refresh TTL\r\n this.stmtLockUpsert.run({\r\n file,\r\n project_id: projectId,\r\n locked_by: agentId,\r\n locked_at: existing.locked_at,\r\n expires_at: now + ttl,\r\n });\r\n return { success: true, lockedBy: agentId };\r\n }\r\n // Different agent holds the lock\r\n return { success: false, lockedBy: existing.locked_by };\r\n }\r\n\r\n // No lock — acquire\r\n this.stmtLockUpsert.run({\r\n file,\r\n project_id: projectId,\r\n locked_by: agentId,\r\n locked_at: now,\r\n expires_at: now + ttl,\r\n });\r\n return { success: true, lockedBy: agentId };\r\n }\r\n\r\n releaseLock(projectId: string, file: string, agentId: string): boolean {\r\n const existing = this.stmtLockGet.get(file, projectId) as TeamLockRow | undefined;\r\n if (!existing || existing.locked_by !== agentId) return false;\r\n this.stmtLockDelete.run(file, projectId);\r\n return true;\r\n }\r\n\r\n getLockStatus(projectId: string, file: string): TeamLockRow | null {\r\n // Clean expired first\r\n this.stmtLockDeleteExpired.run(projectId, Date.now());\r\n const row = this.stmtLockGet.get(file, projectId) as TeamLockRow | undefined;\r\n return row ?? null;\r\n }\r\n\r\n listLocks(projectId: string, agentId?: string): TeamLockRow[] {\r\n // Clean expired first\r\n this.stmtLockDeleteExpired.run(projectId, Date.now());\r\n if (agentId) {\r\n return this.stmtLockListByAgent.all(projectId, agentId) as TeamLockRow[];\r\n }\r\n return this.stmtLockListByProject.all(projectId) as TeamLockRow[];\r\n }\r\n\r\n releaseAllLocks(agentId: string): number {\r\n const info = this.stmtLockDeleteByAgent.run(agentId);\r\n return info.changes;\r\n }\r\n\r\n cleanExpiredLocks(projectId: string): number {\r\n const info = this.stmtLockDeleteExpired.run(projectId, Date.now());\r\n return info.changes;\r\n }\r\n\r\n // ═══════════════════════════════════════════════════════════════════\r\n // Migration from team-state.json\r\n // ═══════════════════════════════════════════════════════════════════\r\n\r\n private async migrateFromJsonIfNeeded(): Promise<void> {\r\n // Only migrate if team tables are empty AND team-state.json exists\r\n const agentCount = this.db.prepare(`SELECT COUNT(*) AS cnt FROM team_agents`).get();\r\n if (agentCount.cnt > 0) return;\r\n\r\n // Look for team-state.json in the project directory (parent of dataDir/.memorix)\r\n // team-state.json lives at projectRoot/team-state.json\r\n const candidates = [\r\n path.join(this.dataDir, 'team-state.json'),\r\n path.join(this.dataDir, '..', 'team-state.json'),\r\n ];\r\n\r\n let jsonPath: string | null = null;\r\n for (const p of candidates) {\r\n if (fs.existsSync(p)) {\r\n jsonPath = p;\r\n break;\r\n }\r\n }\r\n if (!jsonPath) return;\r\n\r\n try {\r\n const raw = fs.readFileSync(jsonPath, 'utf-8');\r\n const snap = JSON.parse(raw);\r\n if (snap.version !== 1) return;\r\n\r\n console.error(`[memorix] Migrating team-state.json to SQLite...`);\r\n let agentsMigrated = 0;\r\n let messagesMigrated = 0;\r\n let tasksMigrated = 0;\r\n let locksMigrated = 0;\r\n\r\n // Disable FK enforcement during migration — legacy data may have dangling refs\r\n this.db.pragma('foreign_keys = OFF');\r\n this.db.transaction(() => {\r\n // Migrate agents\r\n if (snap.registry?.agents) {\r\n for (const [id, raw] of Object.entries(snap.registry.agents) as [string, any][]) {\r\n this.stmtAgentUpsert.run({\r\n agent_id: id,\r\n project_id: 'migrated', // Will be updated on next session_start\r\n agent_type: 'unknown',\r\n instance_id: id, // Use agent_id as instance_id for migrated agents\r\n name: raw.name ?? '',\r\n role: raw.role ?? null,\r\n capabilities: raw.capabilities ? JSON.stringify(raw.capabilities) : null,\r\n status: raw.status ?? 'inactive',\r\n joined_at: raw.joinedAt ? new Date(raw.joinedAt).getTime() : Date.now(),\r\n last_heartbeat: raw.lastSeenAt ? new Date(raw.lastSeenAt).getTime() : Date.now(),\r\n left_at: raw.leftAt ? new Date(raw.leftAt).getTime() : null,\r\n last_seen_obs_generation: 0,\r\n });\r\n agentsMigrated++;\r\n }\r\n }\r\n\r\n // Migrate messages\r\n if (snap.messages?.inboxes) {\r\n for (const [agentId, msgs] of Object.entries(snap.messages.inboxes) as [string, any[]][]) {\r\n for (const msg of msgs) {\r\n this.stmtMsgInsert.run({\r\n id: msg.id ?? randomUUID(),\r\n project_id: 'migrated',\r\n sender_agent_id: msg.from ?? 'unknown',\r\n recipient_agent_id: msg.to === '__broadcast__' ? null : (msg.to ?? agentId),\r\n type: msg.type ?? 'direct',\r\n content: msg.content ?? '',\r\n payload: null,\r\n task_id: null,\r\n read_at: msg.read ? Date.now() : null,\r\n created_at: msg.timestamp ? new Date(msg.timestamp).getTime() : Date.now(),\r\n to_role: null,\r\n handoff_status: null,\r\n });\r\n messagesMigrated++;\r\n }\r\n }\r\n }\r\n\r\n // Migrate tasks\r\n if (snap.tasks?.tasks) {\r\n for (const [id, raw] of Object.entries(snap.tasks.tasks) as [string, any][]) {\r\n this.stmtTaskInsert.run({\r\n task_id: id,\r\n project_id: 'migrated',\r\n description: raw.description ?? '',\r\n status: raw.status ?? 'pending',\r\n assignee_agent_id: raw.assignee ?? null,\r\n result: raw.result ?? null,\r\n metadata: raw.metadata ? JSON.stringify(raw.metadata) : null,\r\n created_by: null,\r\n created_at: raw.createdAt ? new Date(raw.createdAt).getTime() : Date.now(),\r\n updated_at: raw.updatedAt ? new Date(raw.updatedAt).getTime() : Date.now(),\r\n required_role: null,\r\n preferred_role: null,\r\n });\r\n // Migrate deps\r\n if (Array.isArray(raw.deps)) {\r\n for (const dep of raw.deps) {\r\n this.stmtTaskDepInsert.run(id, dep);\r\n }\r\n }\r\n tasksMigrated++;\r\n }\r\n }\r\n\r\n // Migrate locks\r\n if (snap.locks?.locks) {\r\n for (const [file, raw] of Object.entries(snap.locks.locks) as [string, any][]) {\r\n this.stmtLockUpsert.run({\r\n file,\r\n project_id: 'migrated',\r\n locked_by: raw.lockedBy ?? 'unknown',\r\n locked_at: raw.lockedAt ? new Date(raw.lockedAt).getTime() : Date.now(),\r\n expires_at: raw.expiresAt ? new Date(raw.expiresAt).getTime() : Date.now(),\r\n });\r\n locksMigrated++;\r\n }\r\n }\r\n })();\r\n\r\n this.db.pragma('foreign_keys = ON');\r\n\r\n console.error(\r\n `[memorix] Team migration complete: ${agentsMigrated} agents, ${messagesMigrated} messages, ${tasksMigrated} tasks, ${locksMigrated} locks.`\r\n );\r\n\r\n // Rename the JSON file to mark migration done\r\n try {\r\n fs.renameSync(jsonPath, jsonPath + '.migrated');\r\n } catch { /* best-effort rename */ }\r\n\r\n } catch (err) {\r\n console.error(`[memorix] team-state.json migration failed (non-fatal): ${err}`);\r\n }\r\n }\r\n\r\n // ═══════════════════════════════════════════════════════════════════\r\n // Role Operations\r\n // ═══════════════════════════════════════════════════════════════════\r\n\r\n private prepareRoleStatements(): void {\r\n this.stmtRoleInsert = this.db.prepare(`\r\n INSERT OR IGNORE INTO team_roles\r\n (role_id, project_id, label, description, preferred_agent_types, max_concurrent, created_at)\r\n VALUES\r\n (@role_id, @project_id, @label, @description, @preferred_agent_types, @max_concurrent, @created_at)\r\n `);\r\n\r\n this.stmtRoleDelete = this.db.prepare(\r\n `DELETE FROM team_roles WHERE role_id = ? AND project_id = ?`\r\n );\r\n\r\n this.stmtRoleListByProject = this.db.prepare(\r\n `SELECT * FROM team_roles WHERE project_id = ? ORDER BY label ASC`\r\n );\r\n\r\n this.stmtRoleGetById = this.db.prepare(\r\n `SELECT * FROM team_roles WHERE role_id = ?`\r\n );\r\n\r\n this.stmtRoleCountByProject = this.db.prepare(\r\n `SELECT COUNT(*) AS cnt FROM team_roles WHERE project_id = ?`\r\n );\r\n }\r\n\r\n /**\r\n * Seed default roles for a project if none exist yet.\r\n * Uses projectId derived from the dataDir path.\r\n */\r\n private seedDefaultRoles(dataDir: string): void {\r\n // Derive project_id from dataDir (same logic as server.ts uses)\r\n const projectId = path.basename(path.resolve(dataDir, '..'));\r\n const count = (this.stmtRoleCountByProject.get(projectId) as { cnt: number }).cnt;\r\n if (count > 0) return; // Already seeded\r\n\r\n const now = Date.now();\r\n for (const def of DEFAULT_ROLES) {\r\n this.stmtRoleInsert.run({\r\n role_id: `${projectId}:${def.roleId}`,\r\n project_id: projectId,\r\n label: def.label,\r\n description: def.description,\r\n preferred_agent_types: JSON.stringify(def.preferredAgentTypes),\r\n max_concurrent: def.maxConcurrent,\r\n created_at: now,\r\n });\r\n }\r\n }\r\n\r\n addRole(projectId: string, input: { roleId: string; label: string; description?: string; preferredAgentTypes?: string[]; maxConcurrent?: number }): TeamRoleRow {\r\n const now = Date.now();\r\n const row: TeamRoleRow = {\r\n role_id: `${projectId}:${input.roleId}`,\r\n project_id: projectId,\r\n label: input.label,\r\n description: input.description ?? null,\r\n preferred_agent_types: JSON.stringify(input.preferredAgentTypes ?? []),\r\n max_concurrent: input.maxConcurrent ?? 1,\r\n created_at: now,\r\n };\r\n this.stmtRoleInsert.run(row);\r\n return row;\r\n }\r\n\r\n removeRole(projectId: string, roleId: string): boolean {\r\n const fullId = roleId.includes(':') ? roleId : `${projectId}:${roleId}`;\r\n const info = this.stmtRoleDelete.run(fullId, projectId);\r\n return info.changes > 0;\r\n }\r\n\r\n listRoles(projectId: string): TeamRoleRow[] {\r\n return this.stmtRoleListByProject.all(projectId) as TeamRoleRow[];\r\n }\r\n\r\n getRole(roleId: string): TeamRoleRow | undefined {\r\n return this.stmtRoleGetById.get(roleId) as TeamRoleRow | undefined;\r\n }\r\n\r\n /**\r\n * Get role occupancy: for each role, how many active agents currently fill it.\r\n */\r\n getRoleOccupancy(projectId: string): Array<{ role: TeamRoleRow; activeAgents: TeamAgentRow[]; vacant: number }> {\r\n const roles = this.listRoles(projectId);\r\n const activeAgents = this.listAgents(projectId, { status: 'active' });\r\n\r\n return roles.map(role => {\r\n const shortRoleId = role.role_id.split(':').pop()!;\r\n const occupants = activeAgents.filter(a => a.role === shortRoleId || a.role === role.role_id);\r\n return {\r\n role,\r\n activeAgents: occupants,\r\n vacant: Math.max(0, role.max_concurrent - occupants.length),\r\n };\r\n });\r\n }\r\n\r\n /**\r\n * Get handoff messages for a project, optionally filtered by role or status.\r\n */\r\n listHandoffs(projectId: string, filter?: { toRole?: string; status?: string }): TeamMessageRow[] {\r\n let sql = `SELECT * FROM team_messages WHERE project_id = ? AND to_role IS NOT NULL`;\r\n const params: any[] = [projectId];\r\n if (filter?.toRole) {\r\n sql += ` AND to_role = ?`;\r\n params.push(filter.toRole);\r\n }\r\n if (filter?.status) {\r\n sql += ` AND handoff_status = ?`;\r\n params.push(filter.status);\r\n }\r\n sql += ` ORDER BY created_at DESC`;\r\n return this.db.prepare(sql).all(...params) as TeamMessageRow[];\r\n }\r\n\r\n /**\r\n * Update handoff status for a message.\r\n */\r\n updateHandoffStatus(messageId: string, status: string): boolean {\r\n const info = this.db.prepare(\r\n `UPDATE team_messages SET handoff_status = ? WHERE id = ?`\r\n ).run(status, messageId);\r\n return info.changes > 0;\r\n }\r\n\r\n // ── Accessor for raw DB (used by cross-process tests) ─────────────\r\n\r\n getDb(): any {\r\n return this.db;\r\n }\r\n}\r\n\r\n// ── Singleton access ────────────────────────────────────────────────\r\n\r\nlet _teamStore: TeamStore | null = null;\r\nlet _teamStoreDataDir: string | null = null;\r\n\r\nexport function getTeamStore(): TeamStore {\r\n if (!_teamStore) {\r\n throw new Error('[memorix] TeamStore not initialized — call initTeamStore() first');\r\n }\r\n return _teamStore;\r\n}\r\n\r\nexport function isTeamStoreInitialized(): boolean {\r\n return _teamStore !== null;\r\n}\r\n\r\nexport async function initTeamStore(dataDir: string): Promise<TeamStore> {\r\n if (_teamStore && _teamStoreDataDir === dataDir) return _teamStore;\r\n\r\n _teamStore = null;\r\n _teamStoreDataDir = null;\r\n\r\n const store = new TeamStore();\r\n await store.init(dataDir);\r\n _teamStore = store;\r\n _teamStoreDataDir = dataDir;\r\n return store;\r\n}\r\n\r\nexport function resetTeamStore(): void {\r\n _teamStore = null;\r\n _teamStoreDataDir = null;\r\n}\r\n","/**\r\n * Team Poll — Situational awareness for agents.\r\n *\r\n * Phase 4b: Provides `computeWatermark` (extracted from server.ts session_start)\r\n * and `computePoll` (full situational awareness in one call).\r\n *\r\n * Architectural boundary (B3): These are cross-process consistency mechanisms.\r\n * They read from SQLite (canonical truth), never from EventBus.\r\n */\r\n\r\nimport type { TeamStore, TeamAgentRow, TeamTaskRow, TeamMessageRow } from './team-store.js';\r\n\r\n// ── Types ──────────────────────────────────────────────────────────\r\n\r\nexport interface WatermarkResult {\r\n lastSeenGeneration: number;\r\n currentGeneration: number;\r\n newObservationCount: number;\r\n}\r\n\r\nexport interface PollResult {\r\n agent: {\r\n agentId: string;\r\n status: string;\r\n lastHeartbeat: number;\r\n } | null;\r\n watermark: WatermarkResult;\r\n inbox: {\r\n unreadCount: number;\r\n messages: TeamMessageRow[];\r\n };\r\n tasks: {\r\n myInProgress: TeamTaskRow[];\r\n availableToClaim: TeamTaskRow[];\r\n recentlyCompleted: TeamTaskRow[];\r\n recentlyFailed: TeamTaskRow[];\r\n };\r\n team: {\r\n activeAgents: TeamAgentRow[];\r\n totalAgents: number;\r\n };\r\n}\r\n\r\n// ── computeWatermark ───────────────────────────────────────────────\r\n\r\n/**\r\n * Compute the watermark for an agent: how many new observations\r\n * have appeared in this project since the agent's last session.\r\n *\r\n * Extracted from server.ts session_start to be shared by poll and session_start.\r\n *\r\n * @param lastSeenGeneration - Agent's last_seen_obs_generation from TeamStore\r\n * @param currentGeneration - Current global generation from observation store\r\n * @param projectObservations - Pre-filtered observations for this project\r\n * with writeGeneration > lastSeenGeneration\r\n */\r\nexport function computeWatermark(\r\n lastSeenGeneration: number,\r\n currentGeneration: number,\r\n newObservationCount: number,\r\n): WatermarkResult {\r\n return {\r\n lastSeenGeneration,\r\n currentGeneration,\r\n newObservationCount,\r\n };\r\n}\r\n\r\n// ── computePoll ────────────────────────────────────────────────────\r\n\r\n/**\r\n * Compute full situational awareness for an agent in one call.\r\n * Reads only from SQLite (TeamStore) — never from EventBus.\r\n *\r\n * @param teamStore - The TeamStore instance\r\n * @param projectId - Current project ID\r\n * @param agentId - The requesting agent's ID (null if no agent registered)\r\n * @param watermark - Pre-computed watermark result\r\n */\r\nexport function computePoll(\r\n teamStore: TeamStore,\r\n projectId: string,\r\n agentId: string | null,\r\n watermark: WatermarkResult,\r\n): PollResult {\r\n // Agent info\r\n let agent: PollResult['agent'] = null;\r\n if (agentId) {\r\n const row = teamStore.getAgent(agentId);\r\n if (row) {\r\n agent = {\r\n agentId: row.agent_id,\r\n status: row.status,\r\n lastHeartbeat: row.last_heartbeat,\r\n };\r\n }\r\n }\r\n\r\n // Inbox\r\n const unreadCount = agentId ? teamStore.getUnreadCount(projectId, agentId) : 0;\r\n const messages = agentId ? teamStore.getInbox(projectId, agentId) : [];\r\n\r\n // Tasks\r\n const allTasks = teamStore.listTasks(projectId);\r\n const myInProgress = agentId\r\n ? allTasks.filter(t => t.assignee_agent_id === agentId && t.status === 'in_progress')\r\n : [];\r\n\r\n // Available to claim: pending, no assignee, all deps met\r\n const pendingTasks = allTasks.filter(t => t.status === 'pending' && !t.assignee_agent_id);\r\n const availableToClaim = pendingTasks.filter(t => {\r\n const unmet = teamStore.getTaskDeps(t.task_id)\r\n .map(depId => teamStore.getTask(depId))\r\n .filter(dep => dep && dep.status !== 'completed');\r\n return unmet.length === 0;\r\n });\r\n\r\n const recentlyCompleted = allTasks.filter(t => t.status === 'completed');\r\n const recentlyFailed = allTasks.filter(t => t.status === 'failed');\r\n\r\n // Team\r\n const allAgents = teamStore.listAgents(projectId);\r\n const activeAgents = allAgents.filter(a => a.status === 'active');\r\n\r\n return {\r\n agent,\r\n watermark,\r\n inbox: { unreadCount, messages },\r\n tasks: { myInProgress, availableToClaim, recentlyCompleted, recentlyFailed },\r\n team: { activeAgents, totalAgents: allAgents.length },\r\n };\r\n}\r\n","/**\r\n * Export/Import Engine\r\n *\r\n * Enables Agent Team continuity by exporting and importing Memorix data.\n *\r\n * Export formats:\r\n * - JSON: Full fidelity, machine-readable\r\n * - Markdown: Human-readable, great for sharing in PRs/docs\r\n *\r\n * Import: JSON format only (full fidelity restore)\r\n */\r\n\r\nimport type { Observation } from '../types.js';\r\nimport type { Session } from '../types.js';\r\nimport { getObservationStore } from '../store/obs-store.js';\r\nimport { getSessionStore } from '../store/session-store.js';\r\n\r\n/** Export package structure */\r\nexport interface MemorixExport {\r\n version: string;\r\n exportedAt: string;\r\n projectId: string;\r\n observations: Observation[];\r\n sessions: Session[];\r\n stats: {\r\n observationCount: number;\r\n sessionCount: number;\r\n typeBreakdown: Record<string, number>;\r\n };\r\n}\r\n\r\nconst OBSERVATION_ICONS: Record<string, string> = {\r\n 'session-request': '[SESSION]', 'gotcha': '[GOTCHA]', 'problem-solution': '[FIX]',\r\n 'how-it-works': '[INFO]', 'what-changed': '[CHANGE]', 'discovery': '[DISCOVERY]',\r\n 'why-it-exists': '[WHY]', 'decision': '[DECISION]', 'trade-off': '[TRADEOFF]',\r\n};\r\n\r\n/**\r\n * Export project data as JSON.\r\n */\r\nexport async function exportAsJson(\r\n projectDir: string,\r\n projectId: string,\r\n): Promise<MemorixExport> {\r\n const store = getObservationStore();\r\n const allObs = await store.loadAll();\r\n const allSessions = await getSessionStore().loadAll();\r\n\r\n const projectObs = allObs.filter(o => o.projectId === projectId);\r\n const projectSessions = allSessions.filter(s => s.projectId === projectId);\r\n\r\n // Type breakdown\r\n const typeBreakdown: Record<string, number> = {};\r\n for (const obs of projectObs) {\r\n typeBreakdown[obs.type] = (typeBreakdown[obs.type] ?? 0) + 1;\r\n }\r\n\r\n return {\r\n version: '0.9.0',\r\n exportedAt: new Date().toISOString(),\r\n projectId,\r\n observations: projectObs,\r\n sessions: projectSessions,\r\n stats: {\r\n observationCount: projectObs.length,\r\n sessionCount: projectSessions.length,\r\n typeBreakdown,\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * Export project data as human-readable Markdown.\r\n */\r\nexport async function exportAsMarkdown(\r\n projectDir: string,\r\n projectId: string,\r\n): Promise<string> {\r\n const data = await exportAsJson(projectDir, projectId);\r\n const lines: string[] = [];\r\n\r\n lines.push(`# Memorix Export: ${projectId}`);\r\n lines.push(`Exported: ${data.exportedAt}`);\r\n lines.push(`Observations: ${data.stats.observationCount} | Sessions: ${data.stats.sessionCount}`);\r\n lines.push('');\r\n\r\n // Type breakdown\r\n if (Object.keys(data.stats.typeBreakdown).length > 0) {\r\n lines.push('## Type Distribution');\r\n for (const [type, count] of Object.entries(data.stats.typeBreakdown).sort((a, b) => b[1] - a[1])) {\r\n const icon = OBSERVATION_ICONS[type] ?? '[UNKNOWN]';\r\n lines.push(`- ${icon} ${type}: ${count}`);\r\n }\r\n lines.push('');\r\n }\r\n\r\n // Sessions\r\n if (data.sessions.length > 0) {\r\n lines.push('## Sessions');\r\n for (const s of data.sessions) {\r\n const status = s.status === 'active' ? '[CHANGE]' : '[OK]';\r\n const agent = s.agent ? ` [${s.agent}]` : '';\r\n lines.push(`### ${status} ${s.id}${agent}`);\r\n lines.push(`Started: ${s.startedAt}${s.endedAt ? ` | Ended: ${s.endedAt}` : ''}`);\r\n if (s.summary) {\r\n lines.push('');\r\n lines.push(s.summary);\r\n }\r\n lines.push('');\r\n }\r\n }\r\n\r\n // Observations grouped by entity\r\n const byEntity = new Map<string, Observation[]>();\r\n for (const obs of data.observations) {\r\n if (!byEntity.has(obs.entityName)) byEntity.set(obs.entityName, []);\r\n byEntity.get(obs.entityName)!.push(obs);\r\n }\r\n\r\n lines.push('## Observations');\r\n for (const [entity, observations] of byEntity) {\r\n lines.push(`### ${entity}`);\r\n for (const obs of observations) {\r\n const icon = OBSERVATION_ICONS[obs.type] ?? '[UNKNOWN]';\r\n lines.push(`#### ${icon} #${obs.id} ${obs.title}`);\r\n lines.push(`Type: ${obs.type} | Created: ${obs.createdAt}${obs.topicKey ? ` | Topic: ${obs.topicKey}` : ''}${obs.revisionCount && obs.revisionCount > 1 ? ` | Rev: ${obs.revisionCount}` : ''}`);\r\n lines.push('');\r\n lines.push(obs.narrative);\r\n if (obs.facts.length > 0) {\r\n lines.push('');\r\n lines.push('**Facts:**');\r\n for (const f of obs.facts) lines.push(`- ${f}`);\r\n }\r\n if (obs.filesModified.length > 0) {\r\n lines.push('');\r\n lines.push(`**Files:** ${obs.filesModified.join(', ')}`);\r\n }\r\n lines.push('');\r\n }\r\n }\r\n\r\n return lines.join('\\n');\r\n}\r\n\r\n/**\r\n * Import observations and sessions from a JSON export.\r\n * Re-assigns IDs to avoid conflicts with existing data.\r\n */\r\nexport async function importFromJson(\r\n projectDir: string,\r\n data: MemorixExport,\r\n): Promise<{ observationsImported: number; sessionsImported: number; skipped: number }> {\r\n let imported = 0;\r\n let sessionsImported = 0;\r\n let skipped = 0;\r\n\r\n const store = getObservationStore();\r\n await store.atomic(async (tx) => {\r\n const existingObs = await tx.loadAll();\r\n const sessionStore = getSessionStore();\r\n const existingSessions = await sessionStore.loadAll();\r\n let nextId = await tx.loadIdCounter();\r\n\r\n // Build set of existing topicKey+projectId for dedup\r\n const existingTopicKeys = new Set(\r\n existingObs\r\n .filter(o => o.topicKey)\r\n .map(o => `${o.projectId}::${o.topicKey}`),\r\n );\r\n\r\n // Import observations\r\n for (const obs of data.observations) {\r\n // Skip if topicKey already exists (dedup)\r\n if (obs.topicKey && existingTopicKeys.has(`${obs.projectId}::${obs.topicKey}`)) {\r\n skipped++;\r\n continue;\r\n }\r\n\r\n const newObs = { ...obs, id: nextId++ };\r\n existingObs.push(newObs);\r\n imported++;\r\n }\r\n\r\n // Import sessions (skip duplicates by ID)\r\n const existingSessionIds = new Set(existingSessions.map(s => s.id));\r\n for (const session of data.sessions) {\r\n if (!existingSessionIds.has(session.id)) {\r\n existingSessions.push(session);\r\n sessionsImported++;\r\n }\r\n }\r\n\r\n await tx.saveAll(existingObs);\r\n await tx.saveIdCounter(nextId);\r\n // Persist imported sessions via store\r\n for (const session of data.sessions) {\r\n if (!existingSessionIds.has(session.id)) {\r\n await sessionStore.insert(session);\r\n }\r\n }\r\n });\r\n\r\n return { observationsImported: imported, sessionsImported, skipped };\r\n}\r\n","/**\r\n * Project classification helpers — shared by /api/projects and /api/identity.\r\n *\r\n * Three kinds:\r\n * - 'real': genuine user projects (e.g. AVIDS2/memorix, github.com/org/repo)\r\n * - 'temporary': test/demo/smoke/e2e scratch projects (local/task-*, local/smoke-*, etc.)\r\n * - 'placeholder': unresolved / obviously broken IDs (placeholder/*, __unresolved__, System32)\r\n *\r\n * A 'dirty' project is one with a clearly broken canonical ID (System32 etc.).\r\n * 'dirty' and 'temporary' are orthogonal axes:\r\n * - local/task-abc → temporary, NOT dirty\r\n * - placeholder/xxx → placeholder, dirty\r\n * - System32\\something → real-looking location but dirty (broken ID)\r\n */\r\n\r\nexport type ProjectKind = 'real' | 'temporary' | 'placeholder';\r\n\r\n/** Regex list — anything matching is temporary (scratch projects) */\r\nconst TEMPORARY_PATTERNS: RegExp[] = [\r\n /^local\\/task-/i,\r\n /^local\\/smoke-/i,\r\n /^local\\/release-smoke-/i,\r\n /^local\\/memorix-e2e-/i,\r\n /^local\\/orchestrate-/i,\r\n /^local\\/scratch-/i,\r\n /^local\\/tmp-/i,\r\n];\r\n\r\n/** Regex list — anything matching is placeholder/unresolved */\r\nconst PLACEHOLDER_PATTERNS: RegExp[] = [\r\n /^__unresolved__$/,\r\n /^placeholder\\//i,\r\n];\r\n\r\n/** Regex list — IDs that indicate a broken canonical ID (dirty). */\r\nconst DIRTY_PATTERNS: RegExp[] = [\r\n /^placeholder\\//i,\r\n /System32/i,\r\n /Microsoft VS Code/i,\r\n /node_modules/i,\r\n /\\.vscode/i,\r\n /^local\\/[A-Z]:\\\\/i,\r\n];\r\n\r\nexport function classifyProjectId(id: string): ProjectKind {\r\n if (!id) return 'placeholder';\r\n if (PLACEHOLDER_PATTERNS.some(p => p.test(id))) return 'placeholder';\r\n if (TEMPORARY_PATTERNS.some(p => p.test(id))) return 'temporary';\r\n return 'real';\r\n}\r\n\r\nexport function isDirtyProjectId(id: string): boolean {\r\n if (!id) return false;\r\n return DIRTY_PATTERNS.some(p => p.test(id));\r\n}\r\n\r\n/** Friendly label for UI badges */\r\nexport function projectKindLabel(kind: ProjectKind): string {\r\n switch (kind) {\r\n case 'real': return 'real';\r\n case 'temporary': return 'temporary';\r\n case 'placeholder': return 'placeholder';\r\n }\r\n}\r\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 { getBaseDataDir } from '../store/persistence.js';\nimport { getObservationStore, initObservationStore } from '../store/obs-store.js';\nimport { getSessionStore, initSessionStore } from '../store/session-store.js';\nimport { initGraphStore, getGraphStore } from '../store/graph-store.js';\nimport type { TeamStore } from '../team/team-store.js';\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\nfunction isActiveStatus(status?: string): boolean {\r\n return (status ?? 'active') === 'active';\r\n}\r\n\r\nfunction filterActiveByProject<T extends { projectId?: string; status?: string }>(items: T[], projectId: string): T[] {\r\n return items.filter(item => item.projectId === projectId && isActiveStatus(item.status));\r\n}\r\n\r\n/**\r\n * Compute project-scoped graph counts from observations.\r\n * Only entities referenced by this project's active observations are counted.\r\n */\r\nfunction computeProjectGraphCounts(\r\n allEntities: Array<{ name: string }>,\r\n allRelations: Array<{ from: string; to: string }>,\r\n projectObs: Array<{ entityName?: string; status?: string }>,\r\n): { entities: number; relations: number; entityNames: Set<string> } {\r\n const entityNames = new Set(\r\n projectObs\r\n .filter(o => (o.status ?? 'active') === 'active' && o.entityName)\r\n .map(o => o.entityName!),\r\n );\r\n const entities = allEntities.filter(e => entityNames.has(e.name));\r\n const entityNameSet = new Set(entities.map(e => e.name));\r\n const relations = allRelations.filter(r => entityNameSet.has(r.from) && entityNameSet.has(r.to));\r\n return { entities: entities.length, relations: relations.length, entityNames };\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 projectRoot: string | null,\r\n projectResolved: boolean,\r\n mode: 'standalone' | 'control-plane' = 'standalone',\r\n port: number = 3210,\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 let effectiveProjectRoot = projectRoot;\r\n let effectiveProjectResolved = projectResolved;\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 // Switched project is considered resolved (user selected it from known projects)\r\n effectiveProjectResolved = true;\r\n effectiveProjectRoot = null; // root unknown for switched project\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 getObservationStore().loadAll() as Array<{ projectId?: string; status?: string }>;\r\n const projectSet = new Map<string, number>();\r\n for (const obs of allObs) {\r\n if (!isActiveStatus(obs.status)) continue;\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 // Classify projects as real/temporary/placeholder + dirty flag\r\n const { classifyProjectId, isDirtyProjectId } = await import('./project-classification.js');\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 kind: classifyProjectId(id),\r\n dirty: isDirtyProjectId(id),\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, {\r\n id: effectiveProjectId,\r\n name: effectiveProjectName,\r\n resolved: effectiveProjectResolved,\r\n rootPath: effectiveProjectRoot,\r\n mode,\r\n port,\r\n mcpEndpoint: mode === 'control-plane' ? `http://127.0.0.1:${port}/mcp` : null,\r\n });\r\n break;\r\n }\r\n\r\n case '/graph': {\r\n await initGraphStore(effectiveDataDir);\r\n const gStore = getGraphStore();\r\n const graph = { entities: gStore.loadEntities(), relations: gStore.loadRelations() };\r\n // Project-scope the graph: only include entities that have observations in this project\r\n const graphObs = await getObservationStore().loadAll() as Array<{ projectId?: string; entityName?: string; status?: string }>;\r\n const projectEntityNames = new Set(\r\n graphObs\r\n .filter(o => o.projectId === effectiveProjectId && (o.status ?? 'active') === 'active' && o.entityName)\r\n .map(o => o.entityName!),\r\n );\r\n const entities = graph.entities.filter((e: any) => projectEntityNames.has(e.name));\r\n const entityNameSet = new Set(entities.map((e: any) => e.name));\r\n const relations = graph.relations.filter((r: any) => entityNameSet.has(r.from) && entityNameSet.has(r.to));\r\n sendJson(res, { entities, relations });\r\n break;\r\n }\r\n\r\n case '/observations': {\r\n const allObs = await getObservationStore().loadAll();\r\n const observations = filterActiveByProject(allObs as Array<{ projectId?: string; status?: string }>, effectiveProjectId);\r\n sendJson(res, observations);\r\n break;\r\n }\r\n\r\n case '/sessions': {\r\n const allSessions = await getSessionStore().loadAll();\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 await initGraphStore(effectiveDataDir);\r\n const graph = { entities: getGraphStore().loadEntities(), relations: getGraphStore().loadRelations() };\r\n const allObs = await getObservationStore().loadAll();\r\n const observations = filterActiveByProject(\r\n allObs as Array<{ projectId?: string; status?: string; type?: string; id?: number; createdAt?: string; title?: string; entityName?: string }>,\r\n effectiveProjectId,\r\n );\r\n const nextId = await getObservationStore().loadIdCounter();\r\n\r\n // Project-scoped graph counts (must match /api/graph and /api/export)\r\n const projectGraphCounts = computeProjectGraphCounts(graph.entities, graph.relations, observations as Array<{ entityName?: string; status?: string }>);\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 // Source breakdown (git / agent / manual)\r\n const sourceCounts: Record<string, number> = { git: 0, agent: 0, manual: 0 };\r\n const gitMemories: Array<any> = [];\r\n const now = Date.now();\r\n const sevenDaysAgo = now - 7 * 24 * 60 * 60 * 1000;\r\n let recentGitCount = 0;\r\n\r\n for (const obs of observations) {\r\n const src = (obs as any).source || 'agent';\r\n sourceCounts[src] = (sourceCounts[src] || 0) + 1;\r\n if (src === 'git') {\r\n gitMemories.push(obs);\r\n if (obs.createdAt && new Date(obs.createdAt).getTime() > sevenDaysAgo) {\r\n recentGitCount++;\r\n }\r\n }\r\n }\r\n\r\n // Git memory summary\r\n const gitSorted = [...gitMemories].sort((a, b) => (b.id || 0) - (a.id || 0));\r\n const recentGitMemories = gitSorted.slice(0, 8).map(o => ({\r\n id: o.id, title: o.title, type: o.type,\r\n commitHash: (o as any).commitHash,\r\n entityName: o.entityName, createdAt: o.createdAt,\r\n filesModified: (o as any).filesModified,\r\n }));\r\n\r\n // Retention summary\r\n let retentionSummary = { active: 0, stale: 0, archive: 0, immune: 0 };\r\n for (const obs of observations) {\r\n const age = now - new Date((obs as any).createdAt || now).getTime();\r\n const ageHours = age / (1000 * 60 * 60);\r\n const importance = (obs as any).importance ?? 5;\r\n const accessCount = (obs as any).accessCount ?? 0;\r\n const lambda = 0.01;\r\n const score = Math.min(importance * Math.exp(-lambda * ageHours) + Math.min(accessCount * 0.5, 3), 10);\r\n const isImmune = importance >= 8 || obs.type === 'gotcha' || obs.type === 'decision';\r\n if (isImmune) retentionSummary.immune++;\r\n if (score >= 3) retentionSummary.active++;\r\n else if (score >= 1) retentionSummary.stale++;\r\n else retentionSummary.archive++;\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 // Storage backend info\r\n const store = getObservationStore();\r\n const storageInfo = {\r\n backend: store.getBackendName(),\r\n generation: store.getGeneration(),\r\n };\r\n\r\n sendJson(res, {\r\n entities: projectGraphCounts.entities,\r\n relations: projectGraphCounts.relations,\r\n observations: observations.length,\r\n nextId,\r\n typeCounts,\r\n sourceCounts,\r\n recentObservations: sorted,\r\n embedding: embeddingStatus,\r\n storage: storageInfo,\r\n gitSummary: {\r\n total: gitMemories.length,\r\n recentWeek: recentGitCount,\r\n recentMemories: recentGitMemories,\r\n },\r\n retentionSummary,\r\n });\r\n break;\r\n }\r\n\r\n case '/retention': {\r\n const allObs = await getObservationStore().loadAll() 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 status?: string;\r\n }>;\r\n const observations = filterActiveByProject(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 case '/config': {\r\n // Config provenance — shows where each config value comes from\r\n const os = await import('node:os');\r\n const { existsSync } = await import('node:fs');\r\n const { join } = await import('node:path');\r\n\r\n let yml: any = {};\r\n // Use the real project root from dashboard state, not process.cwd()\r\n const configProjectRoot = effectiveProjectRoot;\r\n try {\r\n const { loadYamlConfig } = await import('../config/yaml-loader.js');\r\n yml = loadYamlConfig();\r\n } catch { /* best effort */ }\r\n\r\n // Load .env files so process.env reflects actual config (fixes #74, #62)\r\n if (configProjectRoot) {\r\n try {\r\n const { loadDotenv } = await import('../config/dotenv-loader.js');\r\n loadDotenv(configProjectRoot);\r\n } catch { /* best effort */ }\r\n }\r\n\r\n // Check which config files exist\r\n const files: Record<string, { exists: boolean; path: string; unavailable?: boolean }> = {\r\n 'project memorix.yml': { exists: false, path: '', unavailable: !configProjectRoot },\r\n 'user memorix.yml': { exists: false, path: '' },\r\n 'project .env': { exists: false, path: '', unavailable: !configProjectRoot },\r\n 'user .env': { exists: false, path: '' },\r\n 'legacy config.json': { exists: false, path: '' },\r\n };\r\n try {\r\n const home = os.homedir();\r\n const paths: Record<string, string | null> = {\r\n 'project memorix.yml': configProjectRoot ? join(configProjectRoot, 'memorix.yml') : null,\r\n 'user memorix.yml': join(home, '.memorix', 'memorix.yml'),\r\n 'project .env': configProjectRoot ? join(configProjectRoot, '.env') : null,\r\n 'user .env': join(home, '.memorix', '.env'),\r\n 'legacy config.json': join(home, '.memorix', 'config.json'),\r\n };\r\n for (const [key, fpath] of Object.entries(paths)) {\r\n if (fpath === null) {\r\n files[key] = { exists: false, path: 'unavailable', unavailable: true };\r\n } else {\r\n files[key] = { exists: existsSync(fpath), path: fpath };\r\n }\r\n }\r\n } catch { /* best effort */ }\r\n\r\n // Config values with provenance\r\n const values: Array<{ key: string; value: string; source: string; sensitive?: boolean }> = [];\r\n\r\n // LLM\r\n // Helper: determine source label (distinguishes .env file vs system env)\r\n const getEnvSource = async (envKey: string, ymlSource?: string): Promise<string> => {\r\n if (process.env[envKey]) {\r\n // Check if this key was injected by dotenv-loader (from .env file)\r\n try {\r\n const { getLoadedEnvFiles } = await import('../config/dotenv-loader.js');\r\n const envFiles = getLoadedEnvFiles();\r\n if (envFiles.length > 0) return `.env (${envKey})`;\r\n } catch { /* ignore */ }\r\n return `env:${envKey}`;\r\n }\r\n return ymlSource ?? 'default';\r\n };\r\n\r\n const llmProvider = process.env.MEMORIX_LLM_PROVIDER || yml.llm?.provider;\r\n if (llmProvider) values.push({ key: 'llm.provider', value: llmProvider, source: await getEnvSource('MEMORIX_LLM_PROVIDER', yml.llm?.provider ? 'memorix.yml' : undefined) });\r\n\r\n const llmModel = process.env.MEMORIX_LLM_MODEL || yml.llm?.model;\r\n if (llmModel) values.push({ key: 'llm.model', value: llmModel, source: await getEnvSource('MEMORIX_LLM_MODEL', yml.llm?.model ? 'memorix.yml' : undefined) });\r\n\r\n const llmKey = process.env.MEMORIX_LLM_API_KEY || process.env.MEMORIX_API_KEY || yml.llm?.apiKey || process.env.OPENAI_API_KEY;\r\n if (llmKey) {\r\n let src = 'unknown';\r\n if (process.env.MEMORIX_LLM_API_KEY) src = await getEnvSource('MEMORIX_LLM_API_KEY');\r\n else if (process.env.MEMORIX_API_KEY) src = await getEnvSource('MEMORIX_API_KEY');\r\n else if (yml.llm?.apiKey) src = 'memorix.yml (move to .env!)';\r\n else if (process.env.OPENAI_API_KEY) src = await getEnvSource('OPENAI_API_KEY');\r\n values.push({ key: 'llm.apiKey', value: '****' + llmKey.slice(-4), source: src, sensitive: true });\r\n } else {\r\n values.push({ key: 'llm.apiKey', value: 'not set', source: 'none' });\r\n }\r\n\r\n // Embedding\r\n const embProvider = process.env.MEMORIX_EMBEDDING || yml.embedding?.provider || 'off';\r\n values.push({ key: 'embedding.provider', value: embProvider, source: await getEnvSource('MEMORIX_EMBEDDING', yml.embedding?.provider ? 'memorix.yml' : undefined) });\r\n\r\n // Git\r\n values.push({ key: 'git.autoHook', value: String(yml.git?.autoHook ?? false), source: yml.git?.autoHook !== undefined ? 'memorix.yml' : 'default' });\r\n values.push({ key: 'git.skipMergeCommits', value: String(yml.git?.skipMergeCommits ?? true), source: yml.git?.skipMergeCommits !== undefined ? 'memorix.yml' : 'default' });\r\n\r\n // Behavior\r\n if (yml.behavior?.formationMode) values.push({ key: 'behavior.formationMode', value: yml.behavior.formationMode, source: 'memorix.yml' });\r\n if (yml.behavior?.sessionInject) values.push({ key: 'behavior.sessionInject', value: yml.behavior.sessionInject, source: 'memorix.yml' });\r\n\r\n // Server\r\n values.push({ key: 'server.transport', value: yml.server?.transport || 'stdio', source: yml.server?.transport ? 'memorix.yml' : 'default' });\r\n values.push({ key: 'server.dashboard', value: String(yml.server?.dashboard ?? true), source: yml.server?.dashboard !== undefined ? 'memorix.yml' : 'default' });\r\n\r\n sendJson(res, { files, values });\r\n break;\r\n }\r\n\r\n case '/identity': {\r\n // Project identity health — with classification layering (matches control-plane contract)\r\n const allObs = await getObservationStore().loadAll() as Array<{ projectId?: string }>;\r\n const allProjectIds = [...new Set(allObs.map(o => o.projectId).filter(Boolean))] as string[];\r\n\r\n // Classify every known ID (real / temporary / placeholder) + dirty axis\r\n let classifyProjectId: (id: string) => string = () => 'real';\r\n let isDirtyProjectId: (id: string) => boolean = () => false;\r\n try {\r\n const cls = await import('../dashboard/project-classification.js');\r\n classifyProjectId = cls.classifyProjectId;\r\n isDirtyProjectId = cls.isDirtyProjectId;\r\n } catch { /* classification module not available */ }\r\n\r\n const classified = allProjectIds.map(id => ({\r\n id,\r\n kind: classifyProjectId(id),\r\n dirty: isDirtyProjectId(id),\r\n isCurrent: id === effectiveProjectId,\r\n }));\r\n\r\n const realIds = classified.filter(c => c.kind === 'real').map(c => c.id);\r\n const temporaryIds = classified.filter(c => c.kind === 'temporary').map(c => c.id);\r\n const placeholderIds = classified.filter(c => c.kind === 'placeholder').map(c => c.id);\r\n const dirtyIds = classified.filter(c => c.dirty).map(c => c.id);\r\n\r\n // Get alias info\r\n let aliasGroups: any[] = [];\r\n let canonicalId = effectiveProjectId;\r\n try {\r\n const aliasModule = await import('../project/aliases.js');\r\n canonicalId = await aliasModule.getCanonicalId(effectiveProjectId);\r\n\r\n // Load full registry to get all groups\r\n const { promises: fsP } = await import('node:fs');\r\n const registryPath = path.join(baseDir, '.project-aliases.json');\r\n const raw = await fsP.readFile(registryPath, 'utf-8');\r\n const registry = JSON.parse(raw);\r\n aliasGroups = registry.groups || [];\r\n } catch { /* alias module may not be available */ }\r\n\r\n const currentGroup = aliasGroups.find((g: any) => g.aliases?.includes(effectiveProjectId) || g.canonical === effectiveProjectId);\r\n const aliases = currentGroup?.aliases || [effectiveProjectId];\r\n\r\n // Alias groups intersecting real (non-temporary, non-placeholder) IDs\r\n const realIdSet = new Set(realIds);\r\n const aliasGroupsReal = aliasGroups.filter((g: any) => {\r\n const members = [g.canonical, ...(g.aliases || [])].filter(Boolean);\r\n return members.some((m: string) => realIdSet.has(m));\r\n }).length;\r\n\r\n // Current project dirty flag\r\n const currentDirty = isDirtyProjectId(effectiveProjectId);\r\n // Unmerged real fragments = real IDs not covered by any alias group\r\n const aliasCoveredReal = new Set<string>();\r\n for (const g of aliasGroups) {\r\n for (const m of [g.canonical, ...(g.aliases || [])]) {\r\n if (m && realIdSet.has(m)) aliasCoveredReal.add(m);\r\n }\r\n }\r\n const unmergedRealFragments = realIds.filter(id => !aliasCoveredReal.has(id));\r\n const hasMultipleUnmerged = unmergedRealFragments.length > 1;\r\n const isHealthy = !currentDirty && !hasMultipleUnmerged;\r\n\r\n sendJson(res, {\r\n currentProjectId: effectiveProjectId,\r\n canonicalId,\r\n aliases,\r\n currentKind: classifyProjectId(effectiveProjectId),\r\n currentDirty,\r\n // Primary counts — the ones UI should headline\r\n realKnownIds: realIds,\r\n // De-emphasized / historical\r\n temporaryKnownIds: temporaryIds,\r\n placeholderKnownIds: placeholderIds,\r\n // Back-compat: full list for legacy consumers\r\n allProjectIds,\r\n dirtyIds,\r\n // Alias registry: both raw count and real-scoped count\r\n aliasGroups: aliasGroups.length,\r\n aliasGroupsReal,\r\n unmergedRealFragments,\r\n isHealthy,\r\n healthIssues: [\r\n ...(currentDirty ? ['Current project ID is dirty (broken canonical)'] : []),\r\n ...(hasMultipleUnmerged ? [`${unmergedRealFragments.length} unmerged real project fragments detected`] : []),\r\n ],\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 const obsStore = getObservationStore();\r\n const allObs = await obsStore.loadAll();\r\n const matchObs = allObs.find(o => o.id === obsId);\r\n if (!matchObs) {\r\n sendError(res, 'Observation not found', 404);\r\n } else if (matchObs.projectId !== effectiveProjectId) {\r\n // Cross-project deletion guard: reject if obs belongs to a different project\r\n sendError(res, `Observation #${obsId} belongs to project \"${matchObs.projectId}\", not \"${effectiveProjectId}\"`, 403);\r\n } else {\r\n await obsStore.remove(obsId);\r\n\r\n // Sync: clean up graph entity references for this observation\r\n try {\r\n await initGraphStore(effectiveDataDir);\r\n const gStore = getGraphStore();\r\n const prefix = `[#${obsId}] `;\r\n const deletions: { entityName: string; observations: string[] }[] = [];\r\n for (const entity of gStore.loadEntities()) {\r\n const toRemove = entity.observations.filter((o: string) => o.startsWith(prefix));\r\n if (toRemove.length > 0) deletions.push({ entityName: entity.name, observations: toRemove });\r\n }\r\n if (deletions.length > 0) gStore.deleteObservations(deletions);\r\n } catch { /* graph sync is best-effort */ }\r\n\r\n sendJson(res, { ok: true, deleted: obsId });\r\n }\r\n break;\r\n }\r\n\r\n if (apiPath === '/export') {\r\n await initGraphStore(effectiveDataDir);\r\n const fullGraph = { entities: getGraphStore().loadEntities(), relations: getGraphStore().loadRelations() };\r\n const allObs = await getObservationStore().loadAll();\r\n const observations = filterActiveByProject(allObs as Array<{ projectId?: string; entityName?: string; status?: string }>, effectiveProjectId);\r\n const nextId = await getObservationStore().loadIdCounter();\r\n // Project-scope the graph: only entities referenced by this project's observations\r\n const exportEntityNames = new Set(\r\n observations\r\n .filter(o => (o.status ?? 'active') === 'active' && o.entityName)\r\n .map(o => o.entityName!),\r\n );\r\n const exportEntities = fullGraph.entities.filter((e: any) => exportEntityNames.has(e.name));\r\n const exportEntitySet = new Set(exportEntities.map((e: any) => e.name));\r\n const exportRelations = fullGraph.relations.filter((r: any) => exportEntitySet.has(r.from) && exportEntitySet.has(r.to));\r\n const exportData = {\r\n project: { id: effectiveProjectId, name: effectiveProjectName },\r\n exportedAt: new Date().toISOString(),\r\n graph: { entities: exportEntities, relations: exportRelations },\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 projectRoot: string | null;\r\n projectResolved: boolean;\r\n mode: 'standalone' | 'control-plane';\r\n port: number;\r\n}\r\n\r\n/** Optional Agent Team instances passed from MCP server */\nexport interface TeamInstances {\n registry: { listAgents: (filter?: any) => any[]; getActiveCount: () => number; getAgent: (id: string) => any };\n fileLocks: { listLocks: (agentId?: string) => any[]; cleanExpired: () => void };\n taskManager: { list: (filter?: any) => any[]; getAvailable: () => any[] };\n messageBus: { getUnreadCount: (agentId: string) => number };\n}\n\nfunction parseJsonField(value: unknown, fallback: unknown): unknown {\n if (typeof value !== 'string') return value ?? fallback;\n try {\n return JSON.parse(value || JSON.stringify(fallback));\n } catch {\n return fallback;\n }\n}\n\nfunction normalizeDashboardAgent(teamStore: TeamStore, projectId: string, agent: any) {\n const id = agent.agent_id ?? agent.id ?? '';\n const agentProjectId = agent.project_id ?? agent.projectId ?? projectId;\n return {\n id,\n projectId: agentProjectId,\n instanceId: agent.instance_id ?? agent.instanceId,\n agentType: agent.agent_type ?? agent.agentType,\n name: agent.name,\n role: agent.role,\n capabilities: parseJsonField(agent.capabilities, []),\n status: agent.status,\n joinedAt: agent.joined_at ?? agent.joinedAt,\n lastSeenAt: agent.last_heartbeat ?? agent.last_seen_at ?? agent.lastSeenAt,\n leftAt: agent.left_at ?? agent.leftAt,\n unread: id ? teamStore.getUnreadCount(agentProjectId, id) : 0,\n source: agent.source || 'sqlite',\n };\n}\n\nfunction normalizeDashboardLock(lock: any) {\n return {\n file: lock.file,\n projectId: lock.project_id ?? lock.projectId,\n lockedBy: lock.locked_by ?? lock.lockedBy,\n lockedAt: lock.locked_at ?? lock.lockedAt,\n expiresAt: lock.expires_at ?? lock.expiresAt,\n };\n}\n\nfunction normalizeDashboardTask(task: any) {\n return {\n id: task.task_id ?? task.id,\n projectId: task.project_id ?? task.projectId,\n description: task.description,\n status: task.status,\n assignee: task.assignee_agent_id ?? task.assignee,\n result: task.result,\n metadata: parseJsonField(task.metadata, null),\n createdBy: task.created_by ?? task.createdBy,\n createdAt: task.created_at ?? task.createdAt,\n updatedAt: task.updated_at ?? task.updatedAt,\n deps: task.deps || [],\n requiredRole: task.required_role ?? task.requiredRole ?? null,\n preferredRole: task.preferred_role ?? task.preferredRole ?? null,\n };\n}\n\nasync function buildTeamSnapshot(dataDir: string, projectId: string, scope: string, mode: DashboardState['mode']) {\n try {\n const { initTeamStore } = await import('../team/team-store.js');\n const teamStore = await initTeamStore(dataDir);\n const effectiveProjectId = scope === 'global' ? undefined : projectId;\n const rawAgents = effectiveProjectId ? teamStore.listAgents(effectiveProjectId) : teamStore.listAllAgents();\n const rawLocks = effectiveProjectId ? teamStore.listLocks(effectiveProjectId) : teamStore.listAllLocks();\n const rawTasks = effectiveProjectId ? teamStore.listTasks(effectiveProjectId) : teamStore.listAllTasks();\n const available = effectiveProjectId ? teamStore.listTasks(effectiveProjectId, { available: true }) : teamStore.listAllTasks({ available: true });\n const agents = rawAgents.map((agent: any) => normalizeDashboardAgent(teamStore, projectId, agent));\n const locks = rawLocks.map(normalizeDashboardLock);\n const tasks = rawTasks.map(normalizeDashboardTask);\n const recentWindowMs = 7 * 24 * 60 * 60 * 1000;\n const now = Date.now();\n const withTier = agents.map((agent: any) => {\n if (agent.status === 'active') return { ...agent, activityTier: 'active' };\n const seen = Date.parse(agent.lastSeenAt ?? '') || 0;\n return { ...agent, activityTier: now - seen <= recentWindowMs ? 'recent' : 'historical' };\n });\n const activeCount = withTier.filter((agent: any) => agent.activityTier === 'active').length;\n const recentCount = withTier.filter((agent: any) => agent.activityTier === 'recent').length;\n const historicalCount = withTier.filter((agent: any) => agent.activityTier === 'historical').length;\n const roles = effectiveProjectId ? teamStore.listRoles(effectiveProjectId) : [];\n const roleOccupancy = effectiveProjectId ? teamStore.getRoleOccupancy(effectiveProjectId) : [];\n const handoffs = effectiveProjectId ? teamStore.listHandoffs(effectiveProjectId) : [];\n return {\n mode,\n readOnly: mode === 'standalone',\n scope,\n agents: withTier,\n activeCount,\n recentCount,\n historicalCount,\n totalAgents: withTier.length,\n recentWindowDays: 7,\n locks,\n tasks,\n availableTasks: available.length,\n sessions: 0,\n roles,\n roleOccupancy,\n handoffs,\n openTasks: tasks.filter((task: any) => task.status === 'pending' || task.status === 'in_progress').length,\n openHandoffs: handoffs.filter((handoff: any) => handoff.handoff_status === 'open' || handoff.handoffStatus === 'open').length,\n totalUnread: withTier.reduce((sum: number, agent: any) => sum + (agent.unread || 0), 0),\n activeSessions: activeCount,\n };\n } catch {\n return {\n mode,\n readOnly: mode === 'standalone',\n scope,\n agents: [],\n activeCount: 0,\n recentCount: 0,\n historicalCount: 0,\n totalAgents: 0,\n recentWindowDays: 7,\n locks: [],\n tasks: [],\n availableTasks: 0,\n sessions: 0,\n roles: [],\n roleOccupancy: [],\n handoffs: [],\n openTasks: 0,\n openHandoffs: 0,\n totalUnread: 0,\n activeSessions: 0,\n };\n }\n}\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 projectRoot: string | null = null,\r\n projectResolved = true,\r\n): Promise<void> {\r\n await initObservationStore(dataDir);\r\n await initSessionStore(dataDir);\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 isControlPlane = !!teamInstances;\r\n const state: DashboardState = { projectId, projectName, dataDir, projectRoot, projectResolved, mode: isControlPlane ? 'control-plane' : 'standalone', port };\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 state.projectRoot = body.projectRoot || null;\r\n state.projectResolved = body.projectResolved ?? (body.projectId !== '__unresolved__');\r\n console.error(`[dashboard] Switched current project to: ${state.projectId} (resolved: ${state.projectResolved})`);\r\n sendJson(res, { ok: true, projectId: state.projectId, projectName: state.projectName, resolved: state.projectResolved });\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 }\n\n if (url.startsWith('/api/team')) {\n if (!teamInstances) {\n const parsedUrl = new URL(url, `http://127.0.0.1:${port}`);\n const scope = parsedUrl.searchParams.get('scope') || 'project';\n sendJson(res, await buildTeamSnapshot(state.dataDir, state.projectId, scope, state.mode));\n return;\n }\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\r\n // Role occupancy and handoffs from TeamStore (if available)\r\n let roles: any[] = [];\r\n let roleOccupancy: any[] = [];\r\n let handoffs: any[] = [];\r\n try {\r\n const { getTeamStore, isTeamStoreInitialized } = await import('../team/team-store.js');\r\n if (isTeamStoreInitialized()) {\r\n const teamStore = getTeamStore();\r\n const projectId = state.projectId;\r\n roles = teamStore.listRoles(projectId);\r\n roleOccupancy = teamStore.getRoleOccupancy(projectId);\r\n handoffs = teamStore.listHandoffs(projectId);\r\n }\r\n } catch { /* team store not available in standalone mode */ }\r\n\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 roles,\r\n roleOccupancy,\r\n handoffs,\r\n // Resume data for \"Continue this project\" area\r\n openTasks: tasks.filter((t: any) => t.status === 'pending' || t.status === 'in_progress').length,\r\n openHandoffs: handoffs.filter((h: any) => h.handoff_status === 'open' || h.handoffStatus === 'open').length,\r\n totalUnread: agents.reduce((sum: number, a: any) => sum + teamInstances!.messageBus.getUnreadCount(a.id), 0),\r\n activeSessions: agents.filter((a: any) => a.status === 'active').length,\r\n });\r\n } catch {\r\n sendJson(res, { agents: [], activeCount: 0, locks: [], tasks: [], availableTasks: 0, roles: [], roleOccupancy: [], handoffs: [] });\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, state.projectRoot, state.projectResolved, state.mode, state.port);\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, '127.0.0.1', () => {\r\n const url = `http://127.0.0.1:${port}`;\r\n const resolvedLabel = projectResolved ? 'resolved' : 'unresolved';\r\n const modeLabel = isControlPlane ? 'Control Plane' : 'Standalone';\r\n console.error(` Memorix Dashboard [${modeLabel}]`);\r\n console.error(` ───────────────────────`);\r\n console.error(` Mode: ${modeLabel}`);\r\n console.error(` Project: ${projectName} (${projectId}) [${resolvedLabel}]`);\r\n console.error(` Local: ${url}`);\r\n if (isControlPlane) console.error(` MCP: ${url}/mcp`);\r\n console.error(` Data dir: ${dataDir}`);\r\n console.error(`\\n Press Ctrl+C to stop\\n`);\r\n if (autoOpen) openBrowser(url);\r\n resolve();\r\n });\r\n });\r\n}\r\n","/**\r\n * TeamEventBus — Process-local typed event emitter for team coordination.\r\n *\r\n * Phase 4b: Provides push-based acceleration within a single process.\r\n * NOT a cross-process mechanism — the orchestrator uses SQLite polling.\r\n *\r\n * Architectural boundary (B1): This is process-local fanout only.\r\n * No persistence, no cross-process delivery, no durability guarantees.\r\n * If no listeners are registered, events are silently dropped.\r\n */\r\n\r\nimport { EventEmitter } from 'node:events';\r\n\r\n// ── Event type map ─────────────────────────────────────────────────\r\n\r\nexport interface TeamEventMap {\r\n 'task:created': { taskId: string; projectId: string; description: string };\r\n 'task:claimed': { taskId: string; projectId: string; agentId: string };\r\n 'task:completed': { taskId: string; projectId: string; agentId: string; result?: string };\r\n 'task:failed': { taskId: string; projectId: string; agentId: string; result?: string };\r\n 'task:released': { taskId: string; projectId: string; agentId: string };\r\n 'agent:joined': { agentId: string; projectId: string; agentType: string };\r\n 'agent:left': { agentId: string; projectId: string };\r\n 'agent:stale': { agentId: string; projectId: string; releasedTasks: number };\r\n 'handoff:created':{ observationId: number; projectId: string; fromAgent: string; toAgent?: string; taskId?: string };\r\n}\r\n\r\nexport type TeamEventName = keyof TeamEventMap;\r\n\r\n// ── TeamEventBus ───────────────────────────────────────────────────\r\n\r\nexport class TeamEventBus {\r\n private emitter = new EventEmitter();\r\n\r\n constructor() {\r\n // Prevent memory leak warnings for legitimate multi-listener scenarios\r\n this.emitter.setMaxListeners(50);\r\n }\r\n\r\n /**\r\n * Emit a typed event. Non-blocking, best-effort.\r\n * If no listeners are registered, the event is silently dropped.\r\n */\r\n emit<K extends TeamEventName>(event: K, data: TeamEventMap[K]): void {\r\n try {\r\n this.emitter.emit(event, data);\r\n } catch {\r\n // Best-effort: listener errors never propagate to caller\r\n }\r\n }\r\n\r\n /** Subscribe to a typed event. Returns unsubscribe function. */\r\n on<K extends TeamEventName>(event: K, listener: (data: TeamEventMap[K]) => void): () => void {\r\n this.emitter.on(event, listener);\r\n return () => { this.emitter.off(event, listener); };\r\n }\r\n\r\n /** Subscribe to a typed event, fire only once. */\r\n once<K extends TeamEventName>(event: K, listener: (data: TeamEventMap[K]) => void): void {\r\n this.emitter.once(event, listener);\r\n }\r\n\r\n /** Remove all listeners for a specific event, or all events if none specified. */\r\n removeAllListeners(event?: TeamEventName): void {\r\n if (event) {\r\n this.emitter.removeAllListeners(event);\r\n } else {\r\n this.emitter.removeAllListeners();\r\n }\r\n }\r\n\r\n /** Current listener count for a specific event. */\r\n listenerCount(event: TeamEventName): number {\r\n return this.emitter.listenerCount(event);\r\n }\r\n}\r\n","/**\r\n * Task Graph — Phase 6b: Structured task plan schema + DAG utilities.\r\n *\r\n * Defines the Zod schema for planner output, validates structure and\r\n * semantics, and provides DAG operations (topological sort, cycle\r\n * detection, parallel group discovery).\r\n *\r\n * The planner returns a TaskGraph; the coordinator materializes it\r\n * into TeamStore tasks with system-injected pipelineId.\r\n */\r\n\r\nimport { z } from 'zod';\r\n\r\n// ── Zod Schema ─────────────────────────────────────────────────────\r\n\r\nexport const TaskNodeSchema = z.object({\r\n tempId: z.string().min(1).describe('Temporary ID like \"t1\", \"t2\"'),\r\n role: z.enum(['pm', 'engineer', 'qa', 'reviewer']),\r\n description: z.string().min(30).describe('Self-contained task description with all context'),\r\n deps: z.array(z.string()).describe('tempIds of prerequisite tasks'),\r\n files: z.array(z.string()).optional().describe('Files this task will create or modify'),\r\n /** Phase 7: Natural-language acceptance criteria (Goal-First Testing) */\r\n goals: z.array(z.string()).optional().describe('Acceptance criteria for task verification'),\r\n});\r\n\r\nexport type TaskNode = z.infer<typeof TaskNodeSchema>;\r\n\r\nexport const TaskGraphSchema = z.object({\r\n summary: z.string().min(10).describe('One-paragraph plan summary'),\r\n tasks: z.array(TaskNodeSchema).min(2).max(30),\r\n}).superRefine((data, ctx) => {\r\n const ids = new Set(data.tasks.map(t => t.tempId));\r\n\r\n // Validate: all dep references exist\r\n for (const task of data.tasks) {\r\n for (const dep of task.deps) {\r\n if (!ids.has(dep)) {\r\n ctx.addIssue({\r\n code: z.ZodIssueCode.custom,\r\n message: `Task \"${task.tempId}\" references unknown dependency \"${dep}\"`,\r\n path: ['tasks'],\r\n });\r\n }\r\n }\r\n // Self-reference check\r\n if (task.deps.includes(task.tempId)) {\r\n ctx.addIssue({\r\n code: z.ZodIssueCode.custom,\r\n message: `Task \"${task.tempId}\" depends on itself`,\r\n path: ['tasks'],\r\n });\r\n }\r\n }\r\n\r\n // Validate: last task must be a reviewer\r\n if (data.tasks.length > 0 && data.tasks[data.tasks.length - 1].role !== 'reviewer') {\r\n ctx.addIssue({\r\n code: z.ZodIssueCode.custom,\r\n message: 'Last task must have role \"reviewer\"',\r\n path: ['tasks'],\r\n });\r\n }\r\n\r\n // Validate: no cycles\r\n if (hasCycle(data.tasks)) {\r\n ctx.addIssue({\r\n code: z.ZodIssueCode.custom,\r\n message: 'Task graph contains a cycle',\r\n path: ['tasks'],\r\n });\r\n }\r\n\r\n // Validate: unique tempIds\r\n if (ids.size !== data.tasks.length) {\r\n ctx.addIssue({\r\n code: z.ZodIssueCode.custom,\r\n message: 'Duplicate tempId values detected',\r\n path: ['tasks'],\r\n });\r\n }\r\n});\r\n\r\nexport type TaskGraph = z.infer<typeof TaskGraphSchema>;\r\n\r\n// ── Parsing ────────────────────────────────────────────────────────\r\n\r\n/**\r\n * Parse and validate a JSON string into a TaskGraph.\r\n * Returns { success, data, error }.\r\n */\r\nexport function parseTaskGraph(raw: string): {\r\n success: true; data: TaskGraph; warnings: string[];\r\n} | {\r\n success: false; error: string;\r\n} {\r\n // Try to extract JSON from fenced code blocks or raw text\r\n const json = extractJson(raw);\r\n if (!json) {\r\n return { success: false, error: 'No valid JSON found in planner output' };\r\n }\r\n\r\n let parsed: unknown;\r\n try {\r\n parsed = JSON.parse(json);\r\n } catch (e) {\r\n return { success: false, error: `JSON parse error: ${(e as Error).message}` };\r\n }\r\n\r\n const result = TaskGraphSchema.safeParse(parsed);\r\n if (!result.success) {\r\n const issues = result.error.issues.map(i => `${i.path.join('.')}: ${i.message}`);\r\n return { success: false, error: `Validation failed:\\n${issues.join('\\n')}` };\r\n }\r\n\r\n const warnings = validateSemantics(result.data);\r\n return { success: true, data: result.data, warnings };\r\n}\r\n\r\n// ── DAG Utilities ──────────────────────────────────────────────────\r\n\r\n/**\r\n * Detect cycles in the task graph using DFS.\r\n */\r\nexport function hasCycle(tasks: Pick<TaskNode, 'tempId' | 'deps'>[]): boolean {\r\n const WHITE = 0, GRAY = 1, BLACK = 2;\r\n const color = new Map<string, number>();\r\n for (const t of tasks) color.set(t.tempId, WHITE);\r\n\r\n const adj = new Map<string, string[]>();\r\n for (const t of tasks) adj.set(t.tempId, t.deps);\r\n\r\n function dfs(node: string): boolean {\r\n color.set(node, GRAY);\r\n for (const dep of adj.get(node) ?? []) {\r\n const c = color.get(dep);\r\n if (c === GRAY) return true; // back edge → cycle\r\n if (c === WHITE && dfs(dep)) return true;\r\n }\r\n color.set(node, BLACK);\r\n return false;\r\n }\r\n\r\n for (const t of tasks) {\r\n if (color.get(t.tempId) === WHITE && dfs(t.tempId)) return true;\r\n }\r\n return false;\r\n}\r\n\r\n/**\r\n * Topological sort (Kahn's algorithm). Returns tasks in execution order.\r\n * Throws if graph has a cycle.\r\n */\r\nexport function topologicalSort(tasks: TaskNode[]): TaskNode[] {\r\n const inDegree = new Map<string, number>();\r\n const taskMap = new Map<string, TaskNode>();\r\n const adj = new Map<string, string[]>(); // dep → dependents\r\n\r\n for (const t of tasks) {\r\n taskMap.set(t.tempId, t);\r\n inDegree.set(t.tempId, t.deps.length);\r\n if (!adj.has(t.tempId)) adj.set(t.tempId, []);\r\n for (const dep of t.deps) {\r\n if (!adj.has(dep)) adj.set(dep, []);\r\n adj.get(dep)!.push(t.tempId);\r\n }\r\n }\r\n\r\n const queue: string[] = [];\r\n for (const [id, deg] of inDegree) {\r\n if (deg === 0) queue.push(id);\r\n }\r\n\r\n const sorted: TaskNode[] = [];\r\n while (queue.length > 0) {\r\n const id = queue.shift()!;\r\n sorted.push(taskMap.get(id)!);\r\n for (const dependent of adj.get(id) ?? []) {\r\n const newDeg = (inDegree.get(dependent) ?? 1) - 1;\r\n inDegree.set(dependent, newDeg);\r\n if (newDeg === 0) queue.push(dependent);\r\n }\r\n }\r\n\r\n if (sorted.length !== tasks.length) {\r\n throw new Error('Task graph contains a cycle — topological sort failed');\r\n }\r\n return sorted;\r\n}\r\n\r\n/**\r\n * Find groups of tasks that can execute in parallel.\r\n * Tasks in the same group have no mutual dependencies and all their\r\n * deps are satisfied at the same \"level\".\r\n */\r\nexport function findParallelGroups(tasks: TaskNode[]): string[][] {\r\n const inDegree = new Map<string, number>();\r\n const adj = new Map<string, string[]>();\r\n\r\n for (const t of tasks) {\r\n inDegree.set(t.tempId, t.deps.length);\r\n if (!adj.has(t.tempId)) adj.set(t.tempId, []);\r\n for (const dep of t.deps) {\r\n if (!adj.has(dep)) adj.set(dep, []);\r\n adj.get(dep)!.push(t.tempId);\r\n }\r\n }\r\n\r\n const groups: string[][] = [];\r\n const remaining = new Set(tasks.map(t => t.tempId));\r\n\r\n while (remaining.size > 0) {\r\n const ready: string[] = [];\r\n for (const id of remaining) {\r\n if ((inDegree.get(id) ?? 0) === 0) ready.push(id);\r\n }\r\n if (ready.length === 0) break; // cycle guard\r\n groups.push(ready);\r\n for (const id of ready) {\r\n remaining.delete(id);\r\n for (const dep of adj.get(id) ?? []) {\r\n inDegree.set(dep, (inDegree.get(dep) ?? 1) - 1);\r\n }\r\n }\r\n }\r\n\r\n return groups;\r\n}\r\n\r\n/**\r\n * Length of the longest dependency chain.\r\n */\r\nexport function longestChain(tasks: Pick<TaskNode, 'tempId' | 'deps'>[]): number {\r\n const memo = new Map<string, number>();\r\n const taskMap = new Map(tasks.map(t => [t.tempId, t]));\r\n\r\n function depth(id: string): number {\r\n if (memo.has(id)) return memo.get(id)!;\r\n const t = taskMap.get(id);\r\n if (!t || t.deps.length === 0) { memo.set(id, 1); return 1; }\r\n const maxDep = Math.max(...t.deps.map(d => depth(d)));\r\n const d = maxDep + 1;\r\n memo.set(id, d);\r\n return d;\r\n }\r\n\r\n let max = 0;\r\n for (const t of tasks) max = Math.max(max, depth(t.tempId));\r\n return max;\r\n}\r\n\r\n// ── Semantic Validation (warnings, not errors) ─────────────────────\r\n\r\nfunction validateSemantics(graph: TaskGraph): string[] {\r\n const warnings: string[] = [];\r\n\r\n // Check for duplicate descriptions\r\n const descs = graph.tasks.map(t => t.description.slice(0, 80));\r\n if (new Set(descs).size < descs.length) {\r\n warnings.push('Some tasks have very similar descriptions — consider making them more distinct');\r\n }\r\n\r\n // Check for overly linear graph (missed parallelism)\r\n const chain = longestChain(graph.tasks);\r\n if (chain > graph.tasks.length * 0.8 && graph.tasks.length > 3) {\r\n warnings.push(`Task graph is nearly linear (chain=${chain}/${graph.tasks.length}) — independent tasks could run in parallel`);\r\n }\r\n\r\n // Check for very short descriptions\r\n for (const t of graph.tasks) {\r\n if (t.description.length < 80) {\r\n warnings.push(`Task \"${t.tempId}\" has a short description (${t.description.length} chars) — agents may lack context`);\r\n }\r\n }\r\n\r\n return warnings;\r\n}\r\n\r\n// ── Helpers ─────────────────────────────────────────────────────────\r\n\r\n/**\r\n * Extract JSON from raw LLM output — handles fenced code blocks,\r\n * bare JSON objects, and markdown-wrapped output.\r\n */\r\nfunction extractJson(raw: string): string | null {\r\n // Handle Claude CLI output formats:\r\n // 1. --output-format json: single {\"type\":\"result\",\"result\":\"...text...\"}\r\n // 2. --output-format stream-json: multiple lines, plan is in assistant text blocks\r\n // 3. Plain text with fenced code blocks or bare JSON\r\n let text = raw;\r\n\r\n // Try single JSON envelope first\r\n try {\r\n const envelope = JSON.parse(raw.trim());\r\n if (envelope && typeof envelope.result === 'string' && envelope.type === 'result') {\r\n text = envelope.result;\r\n }\r\n } catch { /* not a single JSON envelope */ }\r\n\r\n // Handle stream-json: extract text content from assistant messages\r\n // Each line is a separate JSON object — collect all text blocks\r\n if (text === raw && raw.includes('\"type\"')) {\r\n const textBlocks: string[] = [];\r\n for (const line of raw.split('\\n')) {\r\n const trimmed = line.trim();\r\n if (!trimmed.startsWith('{')) continue;\r\n try {\r\n const obj = JSON.parse(trimmed);\r\n // Claude stream-json assistant message with text content\r\n if (obj.type === 'assistant' && Array.isArray(obj.message?.content)) {\r\n for (const block of obj.message.content) {\r\n if (block.type === 'text' && typeof block.text === 'string') {\r\n textBlocks.push(block.text);\r\n }\r\n }\r\n }\r\n // Also check content_block_delta (streaming text chunks)\r\n if (obj.type === 'content_block_delta' && obj.delta?.type === 'text_delta') {\r\n textBlocks.push(obj.delta.text);\r\n }\r\n // Result message with subtype text\r\n if (obj.type === 'result' && typeof obj.result === 'string') {\r\n textBlocks.push(obj.result);\r\n }\r\n } catch { /* skip unparseable lines */ }\r\n }\r\n if (textBlocks.length > 0) {\r\n text = textBlocks.join('');\r\n }\r\n }\r\n\r\n // Try fenced code block first: ```json ... ``` or ``` ... ```\r\n const fenced = text.match(/```(?:json)?\\s*\\n?([\\s\\S]*?)```/);\r\n if (fenced) {\r\n const candidate = fenced[1].trim();\r\n if (candidate.startsWith('{')) return candidate;\r\n }\r\n\r\n // Try bare JSON object — use brace-counting to find matching closing brace\r\n // This handles trailing text after the JSON (common with Gemini and other LLMs)\r\n const braceStart = text.indexOf('{');\r\n if (braceStart !== -1) {\r\n const extracted = extractBalancedJson(text, braceStart);\r\n if (extracted) return extracted;\r\n }\r\n\r\n return null;\r\n}\r\n\r\n/**\r\n * Extract a balanced JSON object starting at `startIdx` using brace-counting.\r\n * Respects string literals (skips braces inside quotes) and escape sequences.\r\n * Returns the substring if a balanced object is found, else null.\r\n */\r\nfunction extractBalancedJson(text: string, startIdx: number): string | null {\r\n let depth = 0;\r\n let inString = false;\r\n let escape = false;\r\n\r\n for (let i = startIdx; i < text.length; i++) {\r\n const ch = text[i];\r\n\r\n if (escape) {\r\n escape = false;\r\n continue;\r\n }\r\n\r\n if (ch === '\\\\' && inString) {\r\n escape = true;\r\n continue;\r\n }\r\n\r\n if (ch === '\"') {\r\n inString = !inString;\r\n continue;\r\n }\r\n\r\n if (inString) continue;\r\n\r\n if (ch === '{') depth++;\r\n else if (ch === '}') {\r\n depth--;\r\n if (depth === 0) {\r\n return text.slice(startIdx, i + 1);\r\n }\r\n }\r\n }\r\n\r\n return null; // unbalanced\r\n}\r\n","/**\r\n * Context Collector — Phase 6a: Gather project context for the planner.\r\n *\r\n * Collects file tree, dependencies, git history, and team capabilities\r\n * so the planner can make informed task decomposition decisions.\r\n * Pure side-effect-free reads — no LLM calls.\r\n */\r\n\r\nimport { execSync } from 'node:child_process';\r\nimport { readFileSync, existsSync } from 'node:fs';\r\nimport { join } from 'node:path';\r\n\r\n// ── Types ──────────────────────────────────────────────────────────\r\n\r\nexport interface PlanningContext {\r\n /** Truncated file tree (gitignored files excluded) */\r\n fileTree: string;\r\n /** package.json dependencies summary (or empty string) */\r\n dependencies: string;\r\n /** Recent git log (last 10 commits, one-line) */\r\n gitLog: string;\r\n /** Available agent names */\r\n agents: string[];\r\n}\r\n\r\nexport interface ContextCollectorOpts {\r\n projectDir: string;\r\n agents: string[];\r\n /** Max entries in file tree (default: 80) */\r\n maxFileTreeEntries?: number;\r\n /** Max git log entries (default: 10) */\r\n maxGitLogEntries?: number;\r\n}\r\n\r\n// ── Implementation ─────────────────────────────────────────────────\r\n\r\n/**\r\n * Collect project context. All operations are best-effort —\r\n * failures produce empty strings rather than throwing.\r\n */\r\nexport function collectPlanningContext(opts: ContextCollectorOpts): PlanningContext {\r\n const {\r\n projectDir,\r\n agents,\r\n maxFileTreeEntries = 80,\r\n maxGitLogEntries = 10,\r\n } = opts;\r\n\r\n return {\r\n fileTree: collectFileTree(projectDir, maxFileTreeEntries),\r\n dependencies: collectDependencies(projectDir),\r\n gitLog: collectGitLog(projectDir, maxGitLogEntries),\r\n agents,\r\n };\r\n}\r\n\r\n/**\r\n * Serialize context into a prompt-ready string.\r\n */\r\nexport function contextToPromptSection(ctx: PlanningContext): string {\r\n const sections: string[] = [];\r\n\r\n if (ctx.fileTree) {\r\n sections.push(`## Project Structure\\n\\`\\`\\`\\n${ctx.fileTree}\\n\\`\\`\\``);\r\n }\r\n if (ctx.dependencies) {\r\n sections.push(`## Dependencies\\n\\`\\`\\`\\n${ctx.dependencies}\\n\\`\\`\\``);\r\n }\r\n if (ctx.gitLog) {\r\n sections.push(`## Recent Git History\\n\\`\\`\\`\\n${ctx.gitLog}\\n\\`\\`\\``);\r\n }\r\n if (ctx.agents.length > 0) {\r\n sections.push(`## Available Agents\\n${ctx.agents.join(', ')}`);\r\n }\r\n\r\n return sections.length > 0\r\n ? `# Project Context\\n\\n${sections.join('\\n\\n')}`\r\n : '';\r\n}\r\n\r\n// ── Internals ──────────────────────────────────────────────────────\r\n\r\nfunction collectFileTree(projectDir: string, maxEntries: number): string {\r\n try {\r\n // Use git ls-files to respect .gitignore\r\n const raw = execSync('git ls-files --cached --others --exclude-standard', {\r\n cwd: projectDir,\r\n encoding: 'utf-8',\r\n timeout: 5_000,\r\n maxBuffer: 512 * 1024,\r\n }).trim();\r\n\r\n if (!raw) return '';\r\n const lines = raw.split('\\n');\r\n const truncated = lines.slice(0, maxEntries);\r\n const suffix = lines.length > maxEntries\r\n ? `\\n... (${lines.length - maxEntries} more files)`\r\n : '';\r\n return truncated.join('\\n') + suffix;\r\n } catch {\r\n return '';\r\n }\r\n}\r\n\r\nfunction collectDependencies(projectDir: string): string {\r\n try {\r\n const pkgPath = join(projectDir, 'package.json');\r\n if (!existsSync(pkgPath)) return '';\r\n const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));\r\n const parts: string[] = [];\r\n if (pkg.dependencies && Object.keys(pkg.dependencies).length > 0) {\r\n parts.push(`dependencies: ${Object.keys(pkg.dependencies).join(', ')}`);\r\n }\r\n if (pkg.devDependencies && Object.keys(pkg.devDependencies).length > 0) {\r\n parts.push(`devDependencies: ${Object.keys(pkg.devDependencies).join(', ')}`);\r\n }\r\n return parts.join('\\n');\r\n } catch {\r\n return '';\r\n }\r\n}\r\n\r\nfunction collectGitLog(projectDir: string, maxEntries: number): string {\r\n try {\r\n return execSync(`git log --oneline -${maxEntries}`, {\r\n cwd: projectDir,\r\n encoding: 'utf-8',\r\n timeout: 5_000,\r\n }).trim();\r\n } catch {\r\n return '';\r\n }\r\n}\r\n","/**\r\n * Planner — Phase 6c: Structured goal→tasks decomposition.\r\n *\r\n * Seeds a \"planning\" meta-task. The planner agent returns a structured\r\n * JSON TaskGraph (validated by Zod). The coordinator then calls\r\n * materializeTaskGraph() to create real tasks with system-injected\r\n * pipelineId (eliminating D1 debt: no more prompt-compliance dependency).\r\n *\r\n * Review tasks include a quality-gate: the reviewer checks completed work\r\n * and may spawn fix tasks + a follow-up review, up to maxIterations.\r\n */\r\n\r\nimport { randomUUID } from 'node:crypto';\r\nimport type { TeamStore } from '../team/team-store.js';\r\nimport { parseTaskGraph, topologicalSort, type TaskGraph } from './task-graph.js';\r\nimport { collectPlanningContext, contextToPromptSection } from './context-collector.js';\r\n\r\n// ── Types ──────────────────────────────────────────────────────────\r\n\r\nexport interface PlannerConfig {\r\n goal: string;\r\n /** Max review→fix cycles (default 3) */\r\n maxIterations?: number;\r\n /** Max total tasks the pipeline may create (default 15) */\r\n taskBudget?: number;\r\n}\r\n\r\nexport interface PlannerMeta {\r\n plannerType: 'plan' | 'review';\r\n pipelineId: string;\r\n goal: string;\r\n iteration: number;\r\n maxIterations: number;\r\n taskBudget: number;\r\n}\r\n\r\n// ── Helpers ────────────────────────────────────────────────────────\r\n\r\n/**\r\n * Parse task metadata to determine if a task is a planner/review task.\r\n * Returns null for regular worker tasks.\r\n */\r\nexport function isPlannerTask(metadata?: string | null): PlannerMeta | null {\r\n if (!metadata) return null;\r\n try {\r\n const parsed = JSON.parse(metadata);\r\n if (parsed?.plannerType === 'plan' || parsed?.plannerType === 'review') {\r\n return parsed as PlannerMeta;\r\n }\r\n } catch { /* not planner metadata */ }\r\n return null;\r\n}\r\n\r\n/**\r\n * Extract pipelineId from any task's metadata (planner, review, or worker).\r\n * Returns null if the task is not part of an autonomous pipeline.\r\n */\r\nexport function extractPipelineId(metadata?: string | null): string | null {\r\n if (!metadata) return null;\r\n try {\r\n const parsed = JSON.parse(metadata);\r\n return typeof parsed?.pipelineId === 'string' ? parsed.pipelineId : null;\r\n } catch { return null; }\r\n}\r\n\r\n// ── Guards (server-enforced hard limits) ───────────────────────────\r\n\r\nexport interface GuardInput {\r\n /** All existing tasks in the project */\r\n existingTasks: Array<{ metadata?: string | null }>;\r\n /** Metadata of the task being created (parsed), if any */\r\n newTaskMeta?: Record<string, unknown> | null;\r\n}\r\n\r\nexport type GuardResult =\r\n | { allowed: true }\r\n | { allowed: false; reason: string };\r\n\r\n/**\r\n * Enforce autonomous-pipeline limits at the system level.\r\n *\r\n * Pipeline-scoped: only counts tasks belonging to the SAME pipelineId.\r\n * Called by the team_task create handler in server.ts.\r\n * Tasks without a pipelineId (manual tasks, other pipelines) are never affected.\r\n */\r\nexport function checkPipelineGuards(input: GuardInput): GuardResult {\r\n // Extract pipelineId from the task being created\r\n const newPipelineId = typeof input.newTaskMeta?.pipelineId === 'string'\r\n ? input.newTaskMeta.pipelineId : null;\r\n\r\n // No pipelineId on new task → not part of any autonomous pipeline → allow\r\n if (!newPipelineId) return { allowed: true };\r\n\r\n // Scan existing tasks: find plan meta + count pipeline members\r\n let planMeta: PlannerMeta | null = null;\r\n let pipelineTaskCount = 0;\r\n\r\n for (const t of input.existingTasks) {\r\n const pid = extractPipelineId(t.metadata);\r\n if (pid === newPipelineId) {\r\n pipelineTaskCount++;\r\n if (!planMeta) {\r\n const parsed = isPlannerTask(t.metadata);\r\n if (parsed?.plannerType === 'plan') planMeta = parsed;\r\n }\r\n }\r\n }\r\n\r\n // No planning task found for this pipeline → allow (orphan pipelineId)\r\n if (!planMeta) return { allowed: true };\r\n\r\n // Guard 1: task budget (pipeline-scoped)\r\n if (pipelineTaskCount + 1 > planMeta.taskBudget) {\r\n return {\r\n allowed: false,\r\n reason: `Task budget exhausted (${pipelineTaskCount}/${planMeta.taskBudget}). Cannot create more tasks.`,\r\n };\r\n }\r\n\r\n // Guard 2: review iteration limit (pipeline-scoped)\r\n if (input.newTaskMeta?.plannerType === 'review') {\r\n const iter = typeof input.newTaskMeta.iteration === 'number'\r\n ? input.newTaskMeta.iteration : 0;\r\n if (iter > planMeta.maxIterations) {\r\n return {\r\n allowed: false,\r\n reason: `Max review iterations exceeded (${iter}/${planMeta.maxIterations}). Cannot create more review tasks.`,\r\n };\r\n }\r\n }\r\n\r\n return { allowed: true };\r\n}\r\n\r\n// ── Seed ───────────────────────────────────────────────────────────\r\n\r\nexport interface SeedOptions {\r\n /** Collect project context before planning (default: true) */\r\n collectContext?: boolean;\r\n /** Use structured JSON output (default: true). Set false for P5 legacy mode. */\r\n structuredPlan?: boolean;\r\n}\r\n\r\n/**\r\n * Create the initial planning task. The agent that executes it will\r\n * return a structured JSON TaskGraph (or call team_task in legacy mode).\r\n */\r\nexport function seedAutonomousPipeline(\r\n teamStore: TeamStore,\r\n projectId: string,\r\n config: PlannerConfig,\r\n opts?: SeedOptions & { projectDir?: string; agents?: string[] },\r\n): { planningTaskId: string; pipelineId: string } {\r\n const maxIterations = config.maxIterations ?? 3;\r\n const taskBudget = config.taskBudget ?? 15;\r\n const structuredPlan = opts?.structuredPlan ?? true;\r\n\r\n const pipelineId = randomUUID();\r\n\r\n const meta: PlannerMeta = {\r\n plannerType: 'plan',\r\n pipelineId,\r\n goal: config.goal,\r\n iteration: 0,\r\n maxIterations,\r\n taskBudget,\r\n };\r\n\r\n // Collect project context (best-effort)\r\n let contextSection = '';\r\n if (opts?.collectContext !== false && opts?.projectDir) {\r\n try {\r\n const ctx = collectPlanningContext({\r\n projectDir: opts.projectDir,\r\n agents: opts.agents ?? [],\r\n });\r\n contextSection = contextToPromptSection(ctx);\r\n } catch { /* best-effort */ }\r\n }\r\n\r\n const prompt = structuredPlan\r\n ? buildStructuredPlanningPrompt(config.goal, maxIterations, taskBudget, pipelineId, contextSection)\r\n : buildLegacyPlanningPrompt(config.goal, maxIterations, taskBudget, pipelineId, contextSection);\r\n\r\n const task = teamStore.createTask({\r\n projectId,\r\n description: prompt,\r\n metadata: meta as unknown as Record<string, unknown>,\r\n });\r\n\r\n return { planningTaskId: task.task_id, pipelineId };\r\n}\r\n\r\n// ── Materialize (Phase 6c core: structured output → real tasks) ────\r\n\r\nexport interface MaterializeResult {\r\n success: boolean;\r\n taskIds: string[];\r\n graph?: TaskGraph;\r\n error?: string;\r\n warnings: string[];\r\n}\r\n\r\n/**\r\n * Parse planner agent's raw output into a TaskGraph, validate it,\r\n * and create real tasks in TeamStore with system-injected pipelineId.\r\n *\r\n * This eliminates D1 debt: pipelineId is set by the system, not by\r\n * the agent's prompt compliance.\r\n */\r\nexport function materializeTaskGraph(\r\n teamStore: TeamStore,\r\n projectId: string,\r\n pipelineId: string,\r\n plannerOutput: string,\r\n meta: { maxIterations: number; taskBudget: number; goal: string },\r\n): MaterializeResult {\r\n const parsed = parseTaskGraph(plannerOutput);\r\n if (!parsed.success) {\r\n return { success: false, taskIds: [], error: parsed.error, warnings: [] };\r\n }\r\n\r\n const { data: graph, warnings } = parsed;\r\n\r\n // Topological sort for correct creation order\r\n let sorted;\r\n try {\r\n sorted = topologicalSort(graph.tasks);\r\n } catch (e) {\r\n return { success: false, taskIds: [], error: (e as Error).message, warnings };\r\n }\r\n\r\n // Map tempId → real taskId\r\n const idMap = new Map<string, string>();\r\n const taskIds: string[] = [];\r\n\r\n for (const node of sorted) {\r\n // Resolve deps to real IDs\r\n const realDeps = node.deps.map(d => idMap.get(d)).filter(Boolean) as string[];\r\n\r\n // System-inject pipelineId into metadata (D1 fix)\r\n const taskMeta: Record<string, unknown> = { pipelineId, role: node.role };\r\n if (node.role === 'reviewer') {\r\n taskMeta.plannerType = 'review';\r\n taskMeta.goal = meta.goal;\r\n taskMeta.iteration = 1;\r\n taskMeta.maxIterations = meta.maxIterations;\r\n taskMeta.taskBudget = meta.taskBudget;\r\n }\r\n\r\n const created = teamStore.createTask({\r\n projectId,\r\n description: node.description,\r\n deps: realDeps,\r\n metadata: taskMeta,\r\n });\r\n\r\n idMap.set(node.tempId, created.task_id);\r\n taskIds.push(created.task_id);\r\n }\r\n\r\n return { success: true, taskIds, graph, warnings };\r\n}\r\n\r\n// ── Prompts ────────────────────────────────────────────────────────\r\n\r\n/**\r\n * Phase 6c: Structured JSON planning prompt.\r\n * Agent returns a JSON TaskGraph — no MCP tool calls needed.\r\n */\r\nfunction buildStructuredPlanningPrompt(\r\n goal: string,\r\n maxIterations: number,\r\n taskBudget: number,\r\n pipelineId: string,\r\n contextSection: string,\r\n): string {\r\n return `[Role: Project Planner — Autonomous Task Decomposition]\r\n\r\nYou are the technical lead and project planner for a team of AI agents.\r\nAnalyze the goal below and output a **structured JSON task plan**.\r\n\r\n## Goal\r\n${goal}\r\n${contextSection ? `\\n${contextSection}\\n` : ''}\r\n## Output Format\r\n\r\nReturn a single JSON object (inside a \\`\\`\\`json code fence) matching this schema:\r\n\r\n\\`\\`\\`json\r\n{\r\n \"summary\": \"One-paragraph summary of your plan\",\r\n \"tasks\": [\r\n {\r\n \"tempId\": \"t1\",\r\n \"role\": \"engineer\",\r\n \"description\": \"[Role: Engineer] Build module A — full spec inline, all file paths, acceptance criteria...\",\r\n \"deps\": [],\r\n \"files\": [\"src/moduleA.js\"]\r\n },\r\n {\r\n \"tempId\": \"t2\",\r\n \"role\": \"engineer\",\r\n \"description\": \"[Role: Engineer] Build module B — no dependency on t1, can run in parallel...\",\r\n \"deps\": [],\r\n \"files\": [\"src/moduleB.js\"]\r\n },\r\n {\r\n \"tempId\": \"t3\",\r\n \"role\": \"engineer\",\r\n \"description\": \"[Role: Engineer] Build integration layer — needs t1 and t2 output...\",\r\n \"deps\": [\"t1\", \"t2\"],\r\n \"files\": [\"src/main.js\"]\r\n },\r\n {\r\n \"tempId\": \"tN\",\r\n \"role\": \"reviewer\",\r\n \"description\": \"[Role: Reviewer — Quality Gate (iteration 1/${maxIterations})] Review all work...\",\r\n \"deps\": [\"t1\", \"t2\", \"t3\"]\r\n }\r\n ]\r\n}\r\n\\`\\`\\`\r\n\r\n## Schema Rules\r\n\r\n- **role** must be one of: \\`pm\\`, \\`engineer\\`, \\`qa\\`, \\`reviewer\\`\r\n- **description** must start with \\`[Role: ...]\\` and be **self-contained** (all context, file paths, acceptance criteria)\r\n- **deps** is an array of tempIds of prerequisite tasks\r\n- **The LAST task MUST be a reviewer** — it depends on ALL other tasks\r\n- **files** (optional) lists files the task creates or modifies\r\n\r\n## Suggested Structure — MAXIMIZE PARALLELISM\r\n\r\n- **Skip PM tasks unless truly necessary.** Instead, embed all requirements, specs, file paths, and acceptance criteria DIRECTLY into each engineer task description. This lets engineers start immediately in parallel.\r\n- Only create a PM task if the goal is so ambiguous that engineers cannot begin without a research phase.\r\n- Engineers with NO dependencies on each other should have \\`\"deps\": []\\` so they run in parallel.\r\n- Engineers that build on another engineer's output should depend on that specific task only.\r\n\r\nTypical structure (4–8 tasks):\r\n1. 2–5 engineer tasks (parallel where possible, deps only where truly needed)\r\n2. 0–1 QA tasks (optional, depends on engineers)\r\n3. 1 review task (MANDATORY, last, depends on ALL others)\r\n\r\n## Review Task Description Template\r\n\r\nThe reviewer description MUST include:\r\n- \"Review all completed work for this goal: \\\"{goal}\\\"\"\r\n- Instructions to check correctness, completeness, polish\r\n- If quality OK → call memorix_handoff with approval summary, exit\r\n- If issues → create fix tasks via team_task action=\"create\" (no deps), then a follow-up review task\r\n- If some pending tasks are unnecessary → create a cancellation note via memorix_handoff\r\n- Can also create NEW general tasks (not just fixes) if gaps are found\r\n- Task budget remaining: ~${taskBudget - 1}\r\n- The reviewer will receive a full Pipeline Progress ledger in its prompt\r\n\r\n## Rules\r\n- Task budget: **${taskBudget}** max tasks. Create only what's needed.\r\n- Maximum **${maxIterations}** review iterations.\r\n- Prefer fewer, focused tasks over many trivial ones.\r\n- Output ONLY the JSON. No other text before or after the code fence.\r\n\r\npipelineId (for your reference only, the system will inject this): ${pipelineId}`;\r\n}\r\n\r\n/**\r\n * Phase 5 legacy: agent calls team_task create directly.\r\n * Retained for --no-structured-plan fallback.\r\n */\r\nfunction buildLegacyPlanningPrompt(\r\n goal: string,\r\n maxIterations: number,\r\n taskBudget: number,\r\n pipelineId: string,\r\n contextSection: string,\r\n): string {\r\n const reviewMetaExample = JSON.stringify({\r\n plannerType: 'review',\r\n pipelineId,\r\n goal,\r\n iteration: 1,\r\n maxIterations,\r\n taskBudget,\r\n });\r\n const workerMetaExample = JSON.stringify({ pipelineId });\r\n\r\n return `[Role: Project Planner — Autonomous Task Decomposition]\r\n\r\nYou are the technical lead and project planner for a team of AI agents.\r\nAnalyze the goal below and create a concrete, executable task plan.\r\n\r\n## Goal\r\n${goal}\r\n${contextSection ? `\\n${contextSection}\\n` : ''}\r\n## Instructions\r\n\r\n1. **Analyze** the goal. Think about what roles are needed (PM, Engineer, QA, Reviewer) and what order tasks should run in.\r\n\r\n2. **Create tasks** using \\`team_task action=\"create\"\\`. For each task:\r\n - Write a clear, self-contained \\`description\\` starting with \\`[Role: <role>]\\`.\r\n - Include ALL context the executing agent will need — file paths, tech choices, acceptance criteria.\r\n - Set \\`deps\\` to task IDs of prerequisite tasks (returned by previous create calls).\r\n - **MANDATORY**: include \\`metadata\\` with at least: \\`'${workerMetaExample}'\\`\r\n (This \\`pipelineId\\` links every task to this pipeline for budget tracking.)\r\n\r\n3. **Suggested structure** (adapt to the goal):\r\n - 1–2 research / planning tasks (PM writes spec, explores approach)\r\n - 1–3 implementation tasks (Engineer builds deliverables)\r\n - 0–1 testing / QA tasks (validate output works)\r\n - 1 review task (**MANDATORY** — depends on ALL other tasks)\r\n\r\n4. **Review task** — create it LAST, depending on every other task. Its description MUST include:\r\n \\`\\`\\`\r\n [Role: Reviewer — Quality Gate (iteration 1/${maxIterations})]\r\n Review all completed work for this goal: \"${goal}\"\r\n Read every output file and check correctness, completeness, and polish.\r\n • If quality is satisfactory → call memorix_handoff with an approval summary, then exit.\r\n • If issues found → create fix tasks via team_task action=\"create\" (no deps),\r\n then create ONE follow-up review task with deps on those fix tasks\r\n and metadata: '${reviewMetaExample}'\r\n (increment \"iteration\" for the follow-up review).\r\n Task budget remaining: ~${taskBudget - 1}. Do NOT exceed it.\r\n \\`\\`\\`\r\n\r\n5. **Call memorix_handoff** to share your planning rationale with the team.\r\n\r\n## Rules\r\n- Task budget: **${taskBudget}** max total tasks (including this planning task). Create only what's needed.\r\n- Maximum **${maxIterations}** review iterations.\r\n- Each description must be **self-contained** — no assumptions about shared state beyond file paths.\r\n- Prefer fewer, focused tasks over many trivial ones.\r\n\r\nExit when all tasks are created.`;\r\n}\r\n\r\n/**\r\n * Build a hint string for review-iteration context.\r\n * Can be appended to review task descriptions by agents.\r\n */\r\nexport function buildReviewIterationHint(\r\n iteration: number,\r\n maxIterations: number,\r\n budgetRemaining: number,\r\n): string {\r\n if (iteration >= maxIterations) {\r\n return `\\n\\n[WARN] This is the FINAL review iteration (${iteration}/${maxIterations}). Do NOT create more tasks. Summarize remaining issues and exit.`;\r\n }\r\n return `\\n\\nReview iteration: ${iteration}/${maxIterations}. Budget remaining: ~${budgetRemaining} tasks. You may create fix tasks if needed.`;\r\n}\r\n","/**\r\n * Team Handoff — Structured context transfer between agents.\r\n *\r\n * Phase 4b: Creates a handoff artifact as a standard observation\r\n * (canonical path — no new JSON/file persistence).\r\n *\r\n * Architectural boundary (B4): The canonical record is an Observation\r\n * stored via storeObservation(). TeamStore only holds a reference pointer.\r\n * Handoff artifacts use valueCategory: 'core' so they are immune to\r\n * retention archival (Phase 1 provenance: core = immune).\r\n */\r\n\r\nimport type { TeamStore } from './team-store.js';\r\nimport type { ObservationType } from '../types.js';\r\n\r\n// ── Types ──────────────────────────────────────────────────────────\r\n\r\nexport interface HandoffInput {\r\n projectId: string;\r\n fromAgentId: string;\r\n toAgentId?: string; // null = anyone can pick up\r\n taskId?: string; // link to specific task\r\n summary: string; // human-readable summary of what was done\r\n context: string; // machine-readable context for the next agent\r\n filesModified?: string[]; // files touched during the work\r\n concepts?: string[]; // key concepts for search discoverability\r\n}\r\n\r\nexport interface HandoffResult {\r\n observationId: number;\r\n taskId?: string;\r\n fromAgentId: string;\r\n toAgentId?: string;\r\n summary: string;\r\n}\r\n\r\n// ── createHandoffArtifact ──────────────────────────────────────────\r\n\r\n/**\r\n * Create a structured handoff artifact stored as an observation.\r\n *\r\n * @param input - Handoff details\r\n * @param storeObservation - The canonical storeObservation function (injected to avoid circular deps)\r\n * @param teamStore - For sending notification message to recipient\r\n */\r\nexport async function createHandoffArtifact(\r\n input: HandoffInput,\r\n storeObservation: (params: {\r\n entityName: string;\r\n type: ObservationType;\r\n title: string;\r\n narrative: string;\r\n facts?: string[];\r\n filesModified?: string[];\r\n concepts?: string[];\r\n projectId: string;\r\n topicKey?: string;\r\n sourceDetail?: 'explicit' | 'hook' | 'git-ingest';\r\n valueCategory?: 'core' | 'contextual' | 'ephemeral';\r\n createdByAgentId?: string;\r\n }) => Promise<{ observation: { id: number }; upserted: boolean }>,\r\n teamStore: TeamStore,\r\n): Promise<HandoffResult> {\r\n // Build facts from handoff context\r\n const facts: string[] = [\r\n `Handoff from agent ${input.fromAgentId}`,\r\n ];\r\n if (input.toAgentId) facts.push(`Intended recipient: ${input.toAgentId}`);\r\n if (input.taskId) facts.push(`Related task: ${input.taskId}`);\r\n facts.push(`Context: ${input.context}`);\r\n\r\n // Store as observation — this IS the canonical record\r\n const { observation } = await storeObservation({\r\n entityName: 'team-handoff',\r\n type: 'what-changed',\r\n title: `[Handoff] ${input.summary}`,\r\n narrative: input.context,\r\n facts,\r\n filesModified: input.filesModified,\r\n concepts: ['handoff', ...(input.concepts ?? [])],\r\n projectId: input.projectId,\r\n topicKey: input.taskId ? `handoff:${input.taskId}:${input.fromAgentId}` : undefined,\r\n sourceDetail: 'explicit',\r\n valueCategory: 'core', // immune to retention archival\r\n createdByAgentId: input.fromAgentId,\r\n });\r\n\r\n // Emit handoff:created event (best-effort, process-local only).\r\n // Happens AFTER canonical write succeeds — listener errors never affect the handoff.\r\n try {\r\n teamStore.getEventBus()?.emit('handoff:created', {\r\n observationId: observation.id,\r\n projectId: input.projectId,\r\n fromAgent: input.fromAgentId,\r\n toAgent: input.toAgentId,\r\n taskId: input.taskId,\r\n });\r\n } catch {\r\n // Best-effort: event emission failure never affects canonical handoff\r\n }\r\n\r\n // Send notification message to recipient.\r\n // Broadcast handoff uses fanout-on-write (方案 A): instead of one NULL-recipient\r\n // shared message, each active agent (excluding sender) gets their own copy.\r\n // This prevents Agent A's markRead from consuming Agent B's unread state.\r\n try {\r\n if (input.toAgentId) {\r\n // Role validation: if the handoff is linked to a task with required_role,\r\n // verify the recipient's role matches before sending.\r\n if (input.taskId) {\r\n const task = teamStore.getTask(input.taskId);\r\n if (task?.required_role) {\r\n const recipient = teamStore.getAgent(input.toAgentId);\r\n if (recipient && recipient.role !== task.required_role) {\r\n // Log warning but don't block — handoff observation is still created\r\n console.error(\r\n `[memorix] Handoff role mismatch: task \"${input.taskId}\" requires role \"${task.required_role}\" but recipient \"${input.toAgentId}\" has role \"${recipient.role}\". Handoff proceeds but claim will be rejected.`\r\n );\r\n }\r\n }\r\n }\r\n // Targeted handoff — single recipient-specific message\r\n teamStore.sendMessage({\r\n projectId: input.projectId,\r\n senderAgentId: input.fromAgentId,\r\n recipientAgentId: input.toAgentId,\r\n type: 'handoff',\r\n content: `Handoff: ${input.summary}`,\r\n payload: {\r\n observationId: observation.id,\r\n taskId: input.taskId,\r\n filesModified: input.filesModified,\r\n },\r\n taskId: input.taskId,\r\n });\r\n } else {\r\n // Broadcast handoff — fanout to each active agent (excluding sender)\r\n const agents = teamStore.listAgents(input.projectId, { status: 'active' });\r\n for (const agent of agents) {\r\n if (agent.agent_id === input.fromAgentId) continue;\r\n teamStore.sendMessage({\r\n projectId: input.projectId,\r\n senderAgentId: input.fromAgentId,\r\n recipientAgentId: agent.agent_id,\r\n type: 'handoff',\r\n content: `Handoff: ${input.summary}`,\r\n payload: {\r\n observationId: observation.id,\r\n taskId: input.taskId,\r\n filesModified: input.filesModified,\r\n },\r\n taskId: input.taskId,\r\n });\r\n }\r\n }\r\n } catch {\r\n // Message sending is best-effort — handoff observation is the canonical record\r\n }\r\n\r\n return {\r\n observationId: observation.id,\r\n taskId: input.taskId,\r\n fromAgentId: input.fromAgentId,\r\n toAgentId: input.toAgentId,\r\n summary: input.summary,\r\n };\r\n}\r\n","/**\r\n * Image Loader — Vision LLM Integration\r\n *\r\n * Analyzes images via OpenAI Vision API (or compatible),\r\n * extracting descriptions, tags, and entities.\r\n */\r\n\r\nimport { getLLMApiKey, getLLMBaseUrl, getLLMModel } from '../config.js';\r\nimport { isLLMEnabled, getLLMConfig } from '../llm/provider.js';\r\n\r\n// Providers that use the OpenAI-compatible /chat/completions Vision endpoint\r\nconst OPENAI_COMPATIBLE_PROVIDERS = new Set(['openai', 'openrouter', 'custom']);\r\n\r\n// ── Types ────────────────────────────────────────────────────────────\r\n\r\nexport interface ImageInput {\r\n /** Base64-encoded image data */\r\n base64: string;\r\n /** Image MIME type (default: image/png) */\r\n mimeType?: string;\r\n /** Original filename */\r\n filename?: string;\r\n /** Custom analysis prompt */\r\n prompt?: string;\r\n}\r\n\r\nexport interface ImageAnalysisResult {\r\n /** Natural language description of the image */\r\n description: string;\r\n /** Relevant tags/categories */\r\n tags: string[];\r\n /** Key entities/concepts depicted */\r\n entities: string[];\r\n}\r\n\r\n// ── Internal Vision LLM Call ─────────────────────────────────────────\r\n\r\nasync function callVisionLLM(\r\n systemPrompt: string,\r\n imageBase64: string,\r\n mimeType: string,\r\n): Promise<string> {\r\n const apiKey = getLLMApiKey();\r\n if (!apiKey) {\r\n throw new Error('No LLM API key configured for image analysis.');\r\n }\r\n\r\n let baseUrl = getLLMBaseUrl('https://api.openai.com/v1').replace(/\\/+$/, '');\r\n if (!baseUrl.endsWith('/v1')) baseUrl += '/v1';\r\n const model = getLLMModel('gpt-4o');\r\n\r\n const response = await fetch(`${baseUrl}/chat/completions`, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n 'Authorization': `Bearer ${apiKey}`,\r\n },\r\n body: JSON.stringify({\r\n model,\r\n messages: [{\r\n role: 'user',\r\n content: [\r\n { type: 'text', text: systemPrompt },\r\n {\r\n type: 'image_url',\r\n image_url: { url: `data:${mimeType};base64,${imageBase64}` },\r\n },\r\n ],\r\n }],\r\n temperature: 0.1,\r\n max_tokens: 1024,\r\n }),\r\n signal: AbortSignal.timeout(30_000),\r\n });\r\n\r\n if (!response.ok) {\r\n const errorText = await response.text().catch(() => 'unknown error');\r\n throw new Error(`Vision LLM error (${response.status}): ${errorText}`);\r\n }\r\n\r\n const data = await response.json() as {\r\n choices: Array<{ message: { content: string } }>;\r\n };\r\n\r\n return data.choices[0]?.message?.content ?? '';\r\n}\r\n\r\n// ── Public API ───────────────────────────────────────────────────────\r\n\r\nconst DEFAULT_PROMPT =\r\n 'Analyze this image. Return ONLY a JSON object with this exact format: ' +\r\n '{\"description\": \"detailed description\", \"tags\": [\"tag1\", \"tag2\"], \"entities\": [\"entity1\", \"entity2\"]}';\r\n\r\n/**\r\n * Analyze an image using Vision LLM.\r\n *\r\n * @throws Error if LLM not configured.\r\n */\r\nexport async function analyzeImage(input: ImageInput): Promise<ImageAnalysisResult> {\r\n if (!isLLMEnabled()) {\r\n throw new Error(\r\n 'LLM not configured for image analysis. ' +\r\n 'Set MEMORIX_LLM_API_KEY or OPENAI_API_KEY.',\r\n );\r\n }\r\n\r\n const config = getLLMConfig()!;\r\n if (!OPENAI_COMPATIBLE_PROVIDERS.has(config.provider)) {\r\n throw new Error(\r\n `Image analysis requires an OpenAI-compatible provider (openai, openrouter, or custom). ` +\r\n `Current provider \"${config.provider}\" uses a different API shape. ` +\r\n `Set MEMORIX_LLM_PROVIDER=openai or configure an OpenAI-compatible base URL.`,\r\n );\r\n }\r\n\r\n const mimeType = input.mimeType ?? 'image/png';\r\n const prompt = input.prompt ?? DEFAULT_PROMPT;\r\n\r\n const response = await callVisionLLM(prompt, input.base64, mimeType);\r\n\r\n // Try to parse structured JSON response\r\n try {\r\n // Extract JSON from response (may be wrapped in markdown code block)\r\n const jsonMatch = response.match(/\\{[\\s\\S]*\\}/);\r\n if (jsonMatch) {\r\n const parsed = JSON.parse(jsonMatch[0]);\r\n return {\r\n description: parsed.description ?? response,\r\n tags: Array.isArray(parsed.tags) ? parsed.tags : [],\r\n entities: Array.isArray(parsed.entities) ? parsed.entities : [],\r\n };\r\n }\r\n } catch {\r\n // JSON parse failed — fall through to text extraction\r\n }\r\n\r\n // Fallback: treat entire response as description\r\n return {\r\n description: response,\r\n tags: [],\r\n entities: [],\r\n };\r\n}\r\n","/**\r\n * Audit Module - Track Memorix-written files\r\n *\r\n * Records all files written by Memorix to distinguish them from\r\n * project-native files. Provides audit trail for cleanup and rollback.\r\n */\r\n\r\nimport * as fs from 'node:fs/promises';\r\nimport * as path from 'node:path';\r\nimport { homedir } from 'node:os';\r\n\r\nfunction getAuditFilePath(): string {\r\n return process.env.MEMORIX_AUDIT_FILE || path.join(homedir(), '.memorix', 'audit.json');\r\n}\r\n\r\nexport interface AuditEntry {\r\n type: 'hook' | 'rule' | 'other';\r\n agent?: string;\r\n path: string;\r\n createdAt: string;\r\n}\r\n\r\nexport interface ProjectAudit {\r\n projectRoot: string;\r\n installedAt: string;\r\n entries: AuditEntry[];\r\n}\r\n\r\nexport interface AuditData {\r\n version: string;\r\n projects: Record<string, ProjectAudit>;\r\n}\r\n\r\n/**\r\n * Load audit data from disk.\r\n */\r\nexport async function loadAudit(): Promise<AuditData> {\r\n try {\r\n const content = await fs.readFile(getAuditFilePath(), 'utf-8');\r\n return JSON.parse(content) as AuditData;\r\n } catch {\r\n // No audit file yet\r\n return {\r\n version: '1.0.0',\r\n projects: {},\r\n };\r\n }\r\n}\r\n\r\n/**\r\n * Save audit data to disk.\r\n */\r\nexport async function saveAudit(data: AuditData): Promise<void> {\r\n const auditFile = getAuditFilePath();\r\n const dir = path.dirname(auditFile);\r\n await fs.mkdir(dir, { recursive: true });\r\n await fs.writeFile(auditFile, JSON.stringify(data, null, 2), 'utf-8');\r\n}\r\n\r\n/**\r\n * Get project ID from project root via .git detection.\r\n */\r\nexport function getProjectId(projectRoot: string): string {\r\n try {\r\n const { detectProject } = require('../project/detector.js');\r\n const project = detectProject(projectRoot);\r\n if (project) return project.id;\r\n } catch { /* fallback below */ }\r\n const normalized = projectRoot.replace(/\\\\/g, '/');\r\n return `untracked/${normalized}`;\r\n}\r\n\r\n/**\r\n * Record a file written by Memorix.\r\n */\r\nexport async function recordFile(\r\n projectRoot: string,\r\n type: AuditEntry['type'],\r\n filePath: string,\r\n agent?: string,\r\n): Promise<void> {\r\n const data = await loadAudit();\r\n const projectId = getProjectId(projectRoot);\r\n\r\n if (!data.projects[projectId]) {\r\n data.projects[projectId] = {\r\n projectRoot,\r\n installedAt: new Date().toISOString(),\r\n entries: [],\r\n };\r\n }\r\n\r\n // Check if entry already exists\r\n const existingIndex = data.projects[projectId].entries.findIndex(\r\n (e) => e.path === filePath\r\n );\r\n\r\n if (existingIndex === -1) {\r\n data.projects[projectId].entries.push({\r\n type,\r\n agent,\r\n path: filePath,\r\n createdAt: new Date().toISOString(),\r\n });\r\n }\r\n\r\n await saveAudit(data);\r\n}\r\n\r\n/**\r\n * Get all files written by Memorix for a project.\r\n */\r\nexport async function getProjectFiles(projectRoot: string): Promise<AuditEntry[]> {\r\n const data = await loadAudit();\r\n const projectId = getProjectId(projectRoot);\r\n return data.projects[projectId]?.entries || [];\r\n}\r\n\r\n/**\r\n * Remove a file from audit (when uninstalled).\r\n */\r\nexport async function removeFile(projectRoot: string, filePath: string): Promise<void> {\r\n const data = await loadAudit();\r\n const projectId = getProjectId(projectRoot);\r\n\r\n if (!data.projects[projectId]) return;\r\n\r\n data.projects[projectId].entries = data.projects[projectId].entries.filter(\r\n (e) => e.path !== filePath\r\n );\r\n\r\n // If no entries left, remove the project\r\n if (data.projects[projectId].entries.length === 0) {\r\n delete data.projects[projectId];\r\n }\r\n\r\n await saveAudit(data);\r\n}\r\n\r\n/**\r\n * Get all audit entries across all projects.\r\n */\r\nexport async function getAllAuditEntries(): Promise<\r\n Array<{ projectId: string; entry: AuditEntry }>\r\n> {\r\n const data = await loadAudit();\r\n const entries: Array<{ projectId: string; entry: AuditEntry }> = [];\r\n\r\n for (const [projectId, project] of Object.entries(data.projects)) {\r\n for (const entry of project.entries) {\r\n entries.push({ projectId, entry });\r\n }\r\n }\r\n\r\n return entries;\r\n}\r\n","/**\r\n * Hook Installers\r\n *\r\n * Auto-detect installed agents and generate hook configurations.\r\n * Each agent has a different config format but the hook command is the same:\r\n * memorix hook\r\n *\r\n * The hook handler reads stdin JSON from the agent, normalizes it, and auto-stores.\r\n */\r\n\r\nimport * as fs from 'node:fs/promises';\r\nimport * as path from 'node:path';\r\nimport * as os from 'node:os';\r\nimport { execSync } from 'node:child_process';\r\n\r\nimport type { AgentName, AgentHookConfig } from '../types.js';\r\n\r\n/**\r\n * Resolve the hook command for the current platform.\r\n * On Windows, bare 'memorix' may resolve to a .ps1 script that non-PowerShell\r\n * environments can't execute. Using 'memorix.cmd' explicitly targets the CMD\r\n * shim that npm creates, which works in all shell environments and properly\r\n * forwards stdin (unlike 'cmd /c memorix' which can break stdin piping).\r\n */\r\nfunction resolveHookCommand(): string {\r\n if (process.platform === 'win32') {\r\n return 'memorix.cmd';\r\n }\r\n return 'memorix';\r\n}\r\n\r\n/**\r\n * Generate Claude Code hook config.\r\n * Format: .claude/settings.json\r\n * See: https://docs.anthropic.com/en/docs/claude-code/hooks\r\n */\r\nfunction generateClaudeConfig(): Record<string, unknown> {\r\n const cmd = `${resolveHookCommand()} hook`;\r\n const hookEntry = {\r\n type: 'command',\r\n command: cmd,\r\n timeout: 10,\r\n };\r\n\r\n return {\r\n hooks: {\r\n SessionStart: [{ hooks: [hookEntry] }],\r\n PostToolUse: [{ hooks: [hookEntry] }],\r\n UserPromptSubmit: [{ hooks: [hookEntry] }],\r\n PreCompact: [{ hooks: [hookEntry] }],\r\n Stop: [{ hooks: [hookEntry] }],\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * Generate GitHub Copilot hook config.\r\n * Format: .github/hooks/memorix.json — version:1 + bash/powershell fields\r\n * See: https://docs.github.com/en/copilot/reference/hooks-configuration\r\n *\r\n * Windows note: Copilot CLI executes the `powershell` field via pwsh.exe\r\n * (PowerShell v6+). If pwsh is not installed, the hook silently fails with\r\n * \"spawn pwsh.exe ENOENT\". Strategy:\r\n * - If pwsh is available: include both bash and powershell fields\r\n * - If pwsh is NOT available: omit the powershell field entirely,\r\n * forcing Copilot to use the bash field (which works via Git Bash\r\n * on Windows — a standard dev environment prerequisite)\r\n * - Install/status commands warn if pwsh is missing on Windows\r\n */\r\nfunction generateCopilotConfig(): Record<string, unknown> {\r\n const cmd = `${resolveHookCommand()} hook`;\r\n\r\n // Detect pwsh availability at install time\r\n const hasPwsh = detectPwsh();\r\n\r\n const hookEntry: Record<string, unknown> = {\r\n type: 'command',\r\n bash: cmd,\r\n timeoutSec: 10,\r\n };\r\n // Only include powershell field if pwsh is available — otherwise Copilot\r\n // will try to spawn pwsh.exe and fail with ENOENT\r\n if (hasPwsh) {\r\n hookEntry.powershell = cmd;\r\n }\r\n\r\n return {\r\n version: 1,\r\n hooks: {\r\n sessionStart: [hookEntry],\r\n sessionEnd: [hookEntry],\r\n userPromptSubmitted: [hookEntry],\r\n // NOTE: preToolUse intentionally omitted — VS Code Copilot requires\r\n // hookSpecificOutput.permissionDecision in the response; memorix is\r\n // an observer, not a gatekeeper, so we only use postToolUse.\r\n postToolUse: [hookEntry],\r\n errorOccurred: [hookEntry],\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * Detect whether pwsh (PowerShell v6+) is available on the system.\r\n * Used by Copilot hook config generation to decide whether to include\r\n * the `powershell` field.\r\n */\r\nfunction detectPwsh(): boolean {\r\n try {\r\n execSync('pwsh --version', { encoding: 'utf-8', timeout: 3000, stdio: ['pipe', 'pipe', 'ignore'] });\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Generate Gemini CLI / Antigravity hook config.\r\n * Format: .gemini/settings.json — PascalCase events, timeout in milliseconds\r\n * See: https://geminicli.com/docs/hooks/\r\n */\r\nfunction generateGeminiConfig(): Record<string, unknown> {\r\n const cmd = `${resolveHookCommand()} hook`;\r\n\r\n // Gemini CLI hooks: defined in settings.json under \"hooks\" object.\r\n // Each event key (SessionStart, AfterTool, etc.) maps to an array of hook definitions.\r\n // No \"enabled\" flag needed — hooks are active simply by being defined.\r\n // See: https://geminicli.com/docs/hooks/reference/\r\n function entry(name: string, desc: string) {\r\n return {\r\n matcher: '*',\r\n hooks: [{ name, type: 'command', command: cmd, description: desc }],\r\n };\r\n }\r\n\r\n return {\r\n hooks: {\r\n SessionStart: [entry('memorix-session-start', 'Load memorix context at session start')],\r\n AfterTool: [entry('memorix-after-tool', 'Record tool usage in memorix')],\r\n AfterAgent: [entry('memorix-after-agent', 'Record agent response in memorix')],\r\n PreCompress: [entry('memorix-pre-compress', 'Save context before compression')],\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * Generate Gemini CLI hook config (standalone CLI tool).\r\n * Same format as Antigravity but the command includes --agent gemini-cli\r\n * so the hook normalizer can reliably identify the source agent.\r\n */\r\nfunction generateGeminiCLIConfig(): Record<string, unknown> {\r\n const cmd = `${resolveHookCommand()} hook --agent gemini-cli`;\r\n\r\n function entry(name: string, desc: string) {\r\n return {\r\n matcher: '*',\r\n hooks: [{ name, type: 'command', command: cmd, description: desc }],\r\n };\r\n }\r\n\r\n return {\r\n hooks: {\r\n SessionStart: [entry('memorix-session-start', 'Load memorix context at session start')],\r\n AfterTool: [entry('memorix-after-tool', 'Record tool usage in memorix')],\r\n AfterAgent: [entry('memorix-after-agent', 'Record agent response in memorix')],\r\n PreCompress: [entry('memorix-pre-compress', 'Save context before compression')],\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * Generate Windsurf Cascade hooks config.\r\n */\r\nfunction generateWindsurfConfig(): Record<string, unknown> {\r\n const cmd = `${resolveHookCommand()} hook`;\r\n const hookEntry = {\r\n command: cmd,\r\n show_output: false,\r\n };\r\n\r\n return {\r\n hooks: {\r\n post_write_code: [hookEntry],\r\n post_run_command: [hookEntry],\r\n post_mcp_tool_use: [hookEntry],\r\n pre_user_prompt: [hookEntry],\r\n post_cascade_response: [hookEntry],\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * Generate Cursor hooks config.\r\n */\r\nfunction generateCursorConfig(): Record<string, unknown> {\r\n const cmd = `${resolveHookCommand()} hook`;\r\n // Cursor hooks format: version (number) + each event is an array of hook scripts\r\n // See: https://cursor.com/docs/agent/hooks\r\n const hookScript = { command: cmd };\r\n return {\r\n version: 1,\r\n hooks: {\r\n sessionStart: [hookScript],\r\n beforeSubmitPrompt: [hookScript],\r\n afterFileEdit: [hookScript],\r\n beforeShellExecution: [hookScript],\r\n afterMCPExecution: [hookScript],\r\n preCompact: [hookScript],\r\n stop: [hookScript],\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * Generate Kiro hook files.\r\n * Format: .kiro/hooks/*.kiro.hook — JSON config\r\n * See: https://kiro.dev/docs/hooks/\r\n * Schema confirmed from: github.com/awsdataarchitect/kiro-best-practices\r\n */\r\nfunction generateKiroHookFiles(): Array<{ filename: string; content: string }> {\r\n const cmd = `${resolveHookCommand()} hook`;\r\n return [\r\n {\r\n filename: 'memorix-agent-stop.kiro.hook',\r\n content: JSON.stringify({\r\n enabled: true,\r\n name: 'Memorix Session Memory',\r\n description: 'Record session context when agent completes a turn',\r\n version: '1',\r\n when: { type: 'agentStop' },\r\n then: {\r\n type: 'askAgent',\r\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',\r\n },\r\n }, null, 2),\r\n },\r\n {\r\n filename: 'memorix-prompt-submit.kiro.hook',\r\n content: JSON.stringify({\r\n enabled: true,\r\n name: 'Memorix Context Loader',\r\n description: 'Load relevant memories when user submits a prompt',\r\n version: '1',\r\n when: { type: 'promptSubmit' },\r\n then: {\r\n type: 'askAgent',\r\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',\r\n },\r\n }, null, 2),\r\n },\r\n {\r\n filename: 'memorix-file-save.kiro.hook',\r\n content: JSON.stringify({\r\n enabled: true,\r\n name: 'Memorix File Change Tracker',\r\n description: 'Track significant file changes for cross-session memory',\r\n version: '1',\r\n when: {\r\n type: 'fileEdited',\r\n patterns: ['**/*.ts', '**/*.js', '**/*.tsx', '**/*.jsx', '**/*.py', '**/*.rs', '**/*.go', '**/*.java', '**/*.md'],\r\n },\r\n then: {\r\n type: 'runCommand',\r\n command: cmd,\r\n },\r\n }, null, 2),\r\n },\r\n ];\r\n}\r\n\r\n/**\r\n * Generate OpenCode plugin file content.\r\n * Format: .opencode/plugins/memorix.js — Bun-compatible JS module\r\n * See: https://opencode.ai/docs/plugins/\r\n *\r\n * Plugin contract (verified against official docs Apr 2026):\r\n * - Named export: export const MemorixPlugin = async (ctx) => { return { ... } }\r\n * - Return object keys are EVENT NAMES (e.g. \"session.created\", \"file.edited\")\r\n * - Each key maps to an async handler: (input, output) => { ... }\r\n * - Session/file/command events: handler receives ({ event }) for event-style hooks\r\n * OR (input, output) for tool-style hooks — both are valid\r\n * - Local plugins in .opencode/plugins/ and ~/.config/opencode/plugins/ are\r\n * automatically loaded at startup (no opencode.json registration needed)\r\n * - The `plugin` array in opencode.json is for npm packages only\r\n *\r\n * The plugin hooks into OpenCode events and spawns `memorix hook` via\r\n * child_process.spawnSync, piping JSON over stdin, matching the same\r\n * protocol used by all agents. spawnSync works in both Node.js and Bun\r\n * runtimes (OpenCode may fall back to Node.js on Windows).\r\n */\r\nconst OPENCODE_PLUGIN_VERSION = 5;\r\n\r\nfunction generateOpenCodePlugin(): string {\r\n return `/**\r\n * Memorix - Cross-Agent Memory Bridge Plugin for OpenCode\r\n * @generated-version ${OPENCODE_PLUGIN_VERSION}\r\n *\r\n * Automatically captures session context and tool usage,\r\n * piping events to \\`memorix hook\\` for cross-agent memory persistence.\r\n *\r\n * Plugin spec: https://opencode.ai/docs/plugins/\r\n * Generated by: memorix installHooks('opencode', projectRoot)\r\n * Docs: https://github.com/AVIDS2/memorix\r\n */\r\nimport { spawnSync } from 'node:child_process';\r\n\r\nexport const MemorixPlugin = async ({ project, client, $, directory, worktree }) => {\r\n // Generate a stable session ID for this plugin lifetime\r\n const sessionId = \\`opencode-\\${Date.now().toString(36)}-\\${Math.random().toString(36).slice(2, 8)}\\`;\r\n\r\n /**\r\n * Send event JSON to \\`memorix hook\\` via child_process.spawnSync.\r\n *\r\n * Uses spawnSync instead of Bun.spawn because:\r\n * - child_process works in both Node.js and Bun runtimes\r\n * - OpenCode may fall back to Node.js on Windows (Bun segfaults)\r\n * - spawnSync is simpler: no stream lifecycle, no writer.close() bugs\r\n * - stdin pipe via input option is reliable cross-platform\r\n */\r\n function runHook(payload) {\r\n payload.session_id = sessionId;\r\n const data = JSON.stringify(payload);\r\n const eventName = payload.hook_event_name || 'unknown';\r\n try {\r\n const cmd = process.platform === 'win32' ? 'memorix.cmd' : 'memorix';\r\n const result = spawnSync(cmd, ['hook'], {\r\n input: data,\r\n timeout: 10_000,\r\n encoding: 'utf-8',\r\n stdio: ['pipe', 'pipe', 'pipe'],\r\n });\r\n if (result.status !== 0) {\r\n console.error('[memorix-plugin] hook failed:', eventName,\r\n 'exit=', result.status,\r\n 'stderr=', (result.stderr || '').slice(0, 200));\r\n }\r\n } catch (e) {\r\n console.error('[memorix-plugin] hook delivery failed:', eventName, e?.message ?? e);\r\n }\r\n }\r\n\r\n return {\r\n /** Session created — record session start */\r\n 'session.created': async ({ session }) => {\r\n runHook({\r\n agent: 'opencode',\r\n hook_event_name: 'session.created',\r\n cwd: directory,\r\n });\r\n },\r\n\r\n /** Session idle — record session end */\r\n 'session.idle': async ({ session }) => {\r\n runHook({\r\n agent: 'opencode',\r\n hook_event_name: 'session.idle',\r\n cwd: directory,\r\n });\r\n },\r\n\r\n /** File edited — record file change */\r\n 'file.edited': async (input, output) => {\r\n const filePath = input?.path ?? input?.file ?? '';\r\n runHook({\r\n agent: 'opencode',\r\n hook_event_name: 'file.edited',\r\n file_path: filePath,\r\n cwd: directory,\r\n });\r\n },\r\n\r\n /** Command executed — record command */\r\n 'command.executed': async (input, output) => {\r\n runHook({\r\n agent: 'opencode',\r\n hook_event_name: 'command.executed',\r\n command: input?.command ?? input?.name ?? '',\r\n cwd: directory,\r\n });\r\n },\r\n\r\n /** Session compacted — record post-compact event */\r\n 'session.compacted': async ({ session }) => {\r\n runHook({\r\n agent: 'opencode',\r\n hook_event_name: 'session.compacted',\r\n cwd: directory,\r\n });\r\n },\r\n\r\n /** Record tool usage after execution */\r\n 'tool.execute.after': async (input, output) => {\r\n runHook({\r\n agent: 'opencode',\r\n hook_event_name: 'tool.execute.after',\r\n tool_name: input?.tool ?? '',\r\n tool_input: input?.args,\r\n cwd: directory,\r\n });\r\n },\r\n\r\n /** Structured continuation prompt for compaction (prompt-guided, not tool-automated) */\r\n 'experimental.session.compacting': async (input, output) => {\r\n output.context.push(\r\n '## Continuation Context (Memorix)\\\\n' +\r\n 'Include the following in the compaction summary so the next continuation can resume effectively:\\\\n' +\r\n '- **Current task**: what was being worked on and its status\\\\n' +\r\n '- **Key decisions**: architectural or design choices made this session\\\\n' +\r\n '- **Active files**: files currently being modified or reviewed\\\\n' +\r\n '- **Blockers**: any unresolved issues or errors\\\\n' +\r\n '- **Next steps**: what should happen next\\\\n' +\r\n '- **Active entities**: module names, config keys, or concepts in play\\\\n' +\r\n '- **Memorix context**: if memorix tools were used, note relevant entity names and memory topics for later retrieval'\r\n );\r\n },\r\n };\r\n};\r\n`;\r\n}\r\n\r\n/**\r\n * Get the config file path for an agent (project-level).\r\n */\r\nexport function getProjectConfigPath(agent: AgentName, projectRoot: string): string {\r\n switch (agent) {\r\n case 'claude':\r\n // Claude Code reads hooks from .claude/settings.local.json (project-level, gitignored)\r\n return path.join(projectRoot, '.claude', 'settings.local.json');\r\n case 'copilot':\r\n return path.join(projectRoot, '.github', 'hooks', 'memorix.json');\r\n case 'windsurf':\r\n return path.join(projectRoot, '.windsurf', 'hooks.json');\r\n case 'cursor':\r\n return path.join(projectRoot, '.cursor', 'hooks.json');\r\n case 'kiro':\r\n return path.join(projectRoot, '.kiro', 'hooks', 'memorix-agent-stop.kiro.hook');\r\n case 'codex':\r\n // Codex has no hooks system — only rules (AGENTS.md)\r\n return path.join(projectRoot, 'AGENTS.md');\r\n case 'trae':\r\n // Trae has no hooks system — only rules (.trae/rules/project_rules.md)\r\n return path.join(projectRoot, '.trae', 'rules', 'project_rules.md');\r\n case 'opencode':\r\n // OpenCode uses plugin files for hooks\r\n return path.join(projectRoot, '.opencode', 'plugins', 'memorix.js');\r\n case 'antigravity':\r\n return path.join(projectRoot, '.gemini', 'settings.json');\r\n case 'gemini-cli':\r\n return path.join(projectRoot, '.gemini', 'settings.json');\r\n default:\r\n return path.join(projectRoot, '.memorix', 'hooks.json');\r\n }\r\n}\r\n\r\n/**\r\n * Get the global config file path for an agent.\r\n *\r\n * Returns empty string for agents that do not support global hooks.\r\n * Currently, Copilot only supports project-level hooks (.github/hooks/*.json)\r\n * per the official docs: https://docs.github.com/en/copilot/concepts/agents/cloud-agent/about-hooks\r\n * Feature request for global hooks: https://github.com/github/copilot-cli/issues/1157\r\n */\r\nexport function getGlobalConfigPath(agent: AgentName): string {\r\n const home = os.homedir();\r\n switch (agent) {\r\n case 'claude':\r\n return path.join(home, '.claude', 'settings.json');\r\n case 'copilot':\r\n // GitHub Copilot does NOT support global hooks — only project-level\r\n // .github/hooks/*.json. See official docs and feature request #1157.\r\n return '';\r\n case 'windsurf':\r\n return path.join(home, '.codeium', 'windsurf', 'hooks.json');\r\n case 'cursor':\r\n return path.join(home, '.cursor', 'hooks.json');\r\n case 'antigravity':\r\n return path.join(home, '.gemini', 'settings.json');\r\n case 'gemini-cli':\r\n return path.join(home, '.gemini', 'settings.json');\r\n case 'opencode':\r\n return path.join(home, '.config', 'opencode', 'plugins', 'memorix.js');\r\n case 'trae':\r\n return path.join(home, '.trae', 'rules', 'project_rules.md');\r\n default:\r\n return path.join(home, '.memorix', 'hooks.json');\r\n }\r\n}\r\n\r\n/**\r\n * Detect whether VS Code Copilot extension is installed.\r\n * Checks for GitHub Copilot extension in VS Code extensions directories.\r\n * This is more accurate than checking ~/.vscode which exists for any VS Code user.\r\n */\r\nasync function detectCopilotExtension(home: string): Promise<boolean> {\r\n // Check common VS Code extensions directories\r\n const extDirs = [\r\n path.join(home, '.vscode', 'extensions'),\r\n path.join(home, '.vscode-insiders', 'extensions'),\r\n ];\r\n\r\n for (const extDir of extDirs) {\r\n try {\r\n const entries = await fs.readdir(extDir);\r\n // Copilot extension folder name starts with \"github.copilot-\"\r\n if (entries.some(e => e.startsWith('github.copilot-'))) {\r\n return true;\r\n }\r\n } catch { /* directory doesn't exist or not readable */ }\r\n }\r\n return false;\r\n}\r\n\r\n/**\r\n * Detect which agents are installed on the system.\r\n */\r\nexport async function detectInstalledAgents(): Promise<AgentName[]> {\r\n const agents: AgentName[] = [];\r\n const home = os.homedir();\r\n\r\n // Check for Claude Code\r\n const claudeDir = path.join(home, '.claude');\r\n try {\r\n await fs.access(claudeDir);\r\n agents.push('claude');\r\n } catch { /* not installed */ }\r\n\r\n // Check for Windsurf\r\n const windsurfDir = path.join(home, '.codeium', 'windsurf');\r\n try {\r\n await fs.access(windsurfDir);\r\n agents.push('windsurf');\r\n } catch { /* not installed */ }\r\n\r\n // Check for Cursor\r\n const cursorDir = path.join(home, '.cursor');\r\n try {\r\n await fs.access(cursorDir);\r\n agents.push('cursor');\r\n } catch { /* not installed */ }\r\n\r\n // Check for VS Code Copilot — look for the Copilot extension in VS Code extensions dir,\r\n // not just ~/.vscode (which exists for any VS Code user, not just Copilot users).\r\n const copilotDetected = await detectCopilotExtension(home);\r\n if (copilotDetected) {\r\n agents.push('copilot');\r\n }\r\n\r\n // Check for Kiro\r\n const kiroConfig = path.join(home, '.kiro');\r\n try {\r\n await fs.access(kiroConfig);\r\n agents.push('kiro');\r\n } catch { /* not installed */ }\r\n\r\n // Check for Codex\r\n const codexDir = path.join(home, '.codex');\r\n try {\r\n await fs.access(codexDir);\r\n agents.push('codex');\r\n } catch { /* not installed */ }\r\n\r\n // Check for Antigravity (Google's AI IDE)\r\n // Antigravity creates ~/.gemini/antigravity/ for its own configs (mcp_config.json, etc.)\r\n const antigravityDir = path.join(home, '.gemini', 'antigravity');\r\n try {\r\n await fs.access(antigravityDir);\r\n agents.push('antigravity');\r\n } catch { /* not installed */ }\r\n\r\n // Check for Gemini CLI (standalone CLI tool)\r\n // Detected by the presence of the `gemini` binary on PATH\r\n try {\r\n const { execSync } = await import('node:child_process');\r\n const whereCmd = process.platform === 'win32' ? 'where gemini' : 'which gemini';\r\n execSync(whereCmd, { stdio: 'ignore' });\r\n agents.push('gemini-cli');\r\n } catch { /* not installed */ }\r\n\r\n // Check for OpenCode\r\n const opencodeDir = path.join(home, '.config', 'opencode');\r\n try {\r\n await fs.access(opencodeDir);\r\n agents.push('opencode');\r\n } catch { /* not installed */ }\r\n\r\n // Check for Trae\r\n const traeDir = path.join(home, '.trae');\r\n try {\r\n await fs.access(traeDir);\r\n agents.push('trae');\r\n } catch { /* not installed */ }\r\n\r\n return agents;\r\n}\r\n\r\n/**\r\n * Install hooks for a specific agent.\r\n */\r\nexport async function installHooks(\r\n agent: AgentName,\r\n projectRoot: string,\r\n global = false,\r\n): Promise<AgentHookConfig> {\r\n // Guard: reject global install for agents that don't support it\r\n if (global && getGlobalConfigPath(agent) === '') {\r\n return {\r\n agent,\r\n configPath: getProjectConfigPath(agent, projectRoot),\r\n events: [],\r\n generated: { note: `${agent} does not support global hooks — only project-level. Use without --global flag.` },\r\n };\r\n }\r\n\r\n const configPath = global\r\n ? getGlobalConfigPath(agent)\r\n : getProjectConfigPath(agent, projectRoot);\r\n\r\n // Clean up previous memorix-written files for this agent before reinstalling.\r\n // This ensures stale config from older versions is removed, while preserving\r\n // user's own customizations in shared config files (e.g. AGENTS.md, GEMINI.md).\r\n try {\r\n const { getProjectFiles, removeFile } = await import('../../audit/index.js');\r\n const prevFiles = await getProjectFiles(projectRoot);\r\n const agentPrev = prevFiles.filter(e => e.agent === agent);\r\n for (const entry of agentPrev) {\r\n try {\r\n const { access, unlink } = await import('node:fs/promises');\r\n await access(entry.path);\r\n // For shared context files (AGENTS.md, GEMINI.md), don't delete —\r\n // the install logic below will handle in-place update.\r\n const basename = path.basename(entry.path);\r\n if (basename === 'AGENTS.md' || basename === 'GEMINI.md' || basename === 'CONTEXT.md') {\r\n continue;\r\n }\r\n await unlink(entry.path);\r\n await removeFile(projectRoot, entry.path);\r\n } catch { /* file already gone */ }\r\n }\r\n } catch { /* audit cleanup is best-effort */ }\r\n\r\n let generated: Record<string, unknown> | string;\r\n\r\n switch (agent) {\r\n case 'claude':\r\n generated = generateClaudeConfig();\r\n break;\r\n case 'copilot':\r\n generated = generateCopilotConfig();\r\n break;\r\n case 'windsurf':\r\n generated = generateWindsurfConfig();\r\n break;\r\n case 'cursor':\r\n generated = generateCursorConfig();\r\n break;\r\n case 'antigravity':\r\n generated = generateGeminiConfig();\r\n break;\r\n case 'gemini-cli':\r\n generated = generateGeminiCLIConfig();\r\n break;\r\n case 'kiro':\r\n generated = 'kiro-multi'; // handled separately below\r\n break;\r\n case 'codex':\r\n // Codex has no hooks — only install rules\r\n await installAgentRules(agent, projectRoot);\r\n return {\r\n agent,\r\n configPath: getProjectConfigPath(agent, projectRoot),\r\n events: [],\r\n generated: { note: 'Codex has no hooks system, only rules (AGENTS.md) installed' },\r\n };\r\n case 'trae':\r\n // Trae has no hooks system — only install rules\r\n await installAgentRules(agent, projectRoot);\r\n return {\r\n agent,\r\n configPath: getProjectConfigPath(agent, projectRoot),\r\n events: [],\r\n generated: { note: 'Trae has no hooks system, only rules (.trae/rules/project_rules.md) installed' },\r\n };\r\n case 'opencode': {\r\n // OpenCode uses JS plugin files for hooks\r\n const pluginContent = generateOpenCodePlugin();\r\n const pluginPath = global\r\n ? getGlobalConfigPath(agent)\r\n : getProjectConfigPath(agent, projectRoot);\r\n await fs.mkdir(path.dirname(pluginPath), { recursive: true });\r\n await fs.writeFile(pluginPath, pluginContent, 'utf-8');\r\n \r\n // Record audit entry (non-critical, don't break install)\r\n try {\r\n const { recordFile } = await import('../../audit/index.js');\r\n await recordFile(projectRoot, 'hook', pluginPath, agent);\r\n } catch { /* audit is optional */ }\r\n \r\n await installAgentRules(agent, projectRoot);\r\n return {\r\n agent,\r\n configPath: pluginPath,\r\n events: ['session_start', 'session_end', 'post_tool', 'post_edit', 'post_compact', 'post_command'],\r\n generated: { note: 'OpenCode plugin installed at ' + pluginPath },\r\n };\r\n }\r\n default:\r\n generated = generateClaudeConfig(); // fallback\r\n }\r\n\r\n // Ensure directory exists\r\n await fs.mkdir(path.dirname(configPath), { recursive: true });\r\n\r\n if (agent === 'kiro') {\r\n // Kiro uses multiple .kiro.hook files\r\n const hookFiles = generateKiroHookFiles();\r\n const hooksDir = path.join(path.dirname(configPath));\r\n await fs.mkdir(hooksDir, { recursive: true });\r\n for (const hf of hookFiles) {\r\n const hookPath = path.join(hooksDir, hf.filename);\r\n await fs.writeFile(hookPath, hf.content, 'utf-8');\r\n \r\n // Record audit entry (non-critical, don't break install)\r\n try {\r\n const { recordFile } = await import('../../audit/index.js');\r\n await recordFile(projectRoot, 'hook', hookPath, agent);\r\n } catch { /* audit is optional */ }\r\n }\r\n } else {\r\n // JSON-based configs: merge with existing if present\r\n let existing: Record<string, unknown> = {};\r\n try {\r\n const content = await fs.readFile(configPath, 'utf-8');\r\n existing = JSON.parse(content);\r\n } catch { /* file doesn't exist yet */ }\r\n\r\n // Deep-merge generated keys so we don't overwrite user's existing config\r\n const gen = generated as Record<string, unknown>;\r\n const merged = { ...existing };\r\n\r\n // CRITICAL: version must be a number (Cursor requires this)\r\n // Always use generated version to fix corrupted configs\r\n if (typeof gen.version === 'number') {\r\n merged.version = gen.version;\r\n } else if (typeof merged.version !== 'number') {\r\n // Fallback: ensure version is always a number\r\n merged.version = 1;\r\n }\r\n\r\n // Merge 'hooks' key (all agents)\r\n if (gen.hooks && typeof gen.hooks === 'object') {\r\n const existingHooks = (existing.hooks && typeof existing.hooks === 'object')\r\n ? existing.hooks as Record<string, unknown>\r\n : {};\r\n merged.hooks = { ...existingHooks, ...(gen.hooks as Record<string, unknown>) };\r\n }\r\n\r\n // Merge 'tools' key (preserve any user-defined tools config)\r\n if (gen.tools && typeof gen.tools === 'object') {\r\n const existingTools = (existing.tools && typeof existing.tools === 'object')\r\n ? existing.tools as Record<string, unknown>\r\n : {};\r\n merged.tools = { ...existingTools, ...(gen.tools as Record<string, unknown>) };\r\n }\r\n\r\n // Clean up stale keys from older memorix versions\r\n if (agent === 'antigravity' || agent === 'gemini-cli') {\r\n const h = merged.hooks as Record<string, unknown> | undefined;\r\n if (h && typeof h.enabled === 'boolean') delete h.enabled;\r\n const t = merged.tools as Record<string, unknown> | undefined;\r\n if (t) {\r\n delete t.enableHooks;\r\n if (Object.keys(t).length === 0) delete merged.tools;\r\n }\r\n }\r\n if (agent === 'copilot') {\r\n // Remove preToolUse — VS Code Copilot requires hookSpecificOutput\r\n // in response which memorix doesn't provide (observer, not gatekeeper)\r\n const h = merged.hooks as Record<string, unknown> | undefined;\r\n if (h) delete h.preToolUse;\r\n }\r\n\r\n await fs.writeFile(configPath, JSON.stringify(merged, null, 2), 'utf-8');\r\n \r\n // Record audit entry (non-critical, don't break install)\r\n try {\r\n const { recordFile } = await import('../../audit/index.js');\r\n await recordFile(projectRoot, 'hook', configPath, agent);\r\n } catch { /* audit is optional */ }\r\n }\r\n\r\n const events: Array<import('../types.js').HookEvent> = [];\r\n switch (agent) {\r\n case 'claude':\r\n events.push('session_start', 'post_tool', 'user_prompt', 'pre_compact', 'session_end');\r\n break;\r\n case 'copilot':\r\n events.push('session_start', 'session_end', 'user_prompt', 'post_tool');\r\n break;\r\n case 'windsurf':\r\n events.push('post_edit', 'post_command', 'post_tool', 'user_prompt', 'post_response');\r\n break;\r\n case 'cursor':\r\n events.push('session_start', 'user_prompt', 'post_edit', 'post_tool', 'pre_compact', 'session_end');\r\n break;\r\n case 'antigravity':\r\n events.push('session_start', 'post_tool', 'post_response', 'pre_compact');\r\n break;\r\n case 'gemini-cli':\r\n events.push('session_start', 'post_tool', 'post_response', 'pre_compact');\r\n break;\r\n case 'kiro':\r\n events.push('session_end', 'user_prompt', 'post_edit');\r\n break;\r\n }\r\n\r\n // Install agent rules alongside hooks\r\n await installAgentRules(agent, projectRoot);\r\n\r\n return {\r\n agent,\r\n configPath,\r\n events,\r\n generated: typeof generated === 'string' ? { content: generated } : generated,\r\n };\r\n}\r\n\r\n/**\r\n * Install memorix agent rules for a specific agent.\r\n * Rules instruct the agent to proactively use memorix for context continuity.\r\n */\r\nasync function installAgentRules(agent: AgentName, projectRoot: string): Promise<void> {\r\n const rulesContent = getAgentRulesContent(agent);\r\n let rulesPath: string;\r\n\r\n switch (agent) {\r\n case 'windsurf':\r\n rulesPath = path.join(projectRoot, '.windsurf', 'rules', 'memorix.md');\r\n break;\r\n case 'cursor':\r\n rulesPath = path.join(projectRoot, '.cursor', 'rules', 'memorix.mdc');\r\n break;\r\n case 'claude':\r\n case 'copilot':\r\n rulesPath = path.join(projectRoot, '.github', 'copilot-instructions.md');\r\n break;\r\n case 'codex':\r\n rulesPath = path.join(projectRoot, 'AGENTS.md');\r\n break;\r\n case 'kiro':\r\n rulesPath = path.join(projectRoot, '.kiro', 'steering', 'memorix.md');\r\n break;\r\n case 'opencode':\r\n // OpenCode reads AGENTS.md (same as Codex), also supports CLAUDE.md as fallback\r\n rulesPath = path.join(projectRoot, 'AGENTS.md');\r\n break;\r\n case 'antigravity':\r\n // Antigravity reads context from GEMINI.md by default\r\n rulesPath = path.join(projectRoot, 'GEMINI.md');\r\n break;\r\n case 'gemini-cli':\r\n // Gemini CLI reads context from GEMINI.md by default (like Codex reads AGENTS.md)\r\n // See: context.fileName defaults to [\"GEMINI.md\", \"CONTEXT.md\"]\r\n rulesPath = path.join(projectRoot, 'GEMINI.md');\r\n break;\r\n case 'trae':\r\n rulesPath = path.join(projectRoot, '.trae', 'rules', 'project_rules.md');\r\n break;\r\n default:\r\n rulesPath = path.join(projectRoot, '.agent', 'rules', 'memorix.md');\r\n break;\r\n }\r\n\r\n try {\r\n await fs.mkdir(path.dirname(rulesPath), { recursive: true });\r\n\r\n if (agent === 'codex' || agent === 'opencode' || agent === 'antigravity' || agent === 'gemini-cli') {\r\n // For shared context files (AGENTS.md / GEMINI.md), append rather than overwrite\r\n try {\r\n const existing = await fs.readFile(rulesPath, 'utf-8');\r\n if (existing.includes('Memorix')) {\r\n // Already contains memorix rules — but still record audit entry\r\n // in case audit.json was lost/corrupted and we're re-installing\r\n try {\r\n const { recordFile } = await import('../../audit/index.js');\r\n await recordFile(projectRoot, 'rule', rulesPath, agent);\r\n } catch { /* audit is optional */ }\r\n return;\r\n }\r\n // Append to existing file\r\n await fs.writeFile(rulesPath, existing + '\\n\\n' + rulesContent, 'utf-8');\r\n \r\n // Record audit entry (non-critical)\r\n try {\r\n const { recordFile } = await import('../../audit/index.js');\r\n await recordFile(projectRoot, 'rule', rulesPath, agent);\r\n } catch { /* audit is optional */ }\r\n } catch {\r\n // File doesn't exist, create it\r\n await fs.writeFile(rulesPath, rulesContent, 'utf-8');\r\n \r\n // Record audit entry (non-critical) — needed for uninstallHooks cleanup\r\n try {\r\n const { recordFile } = await import('../../audit/index.js');\r\n await recordFile(projectRoot, 'rule', rulesPath, agent);\r\n } catch { /* audit is optional */ }\r\n }\r\n } else {\r\n // Only write if not already present\r\n try {\r\n await fs.access(rulesPath);\r\n // File exists — don't overwrite user customizations\r\n } catch {\r\n await fs.writeFile(rulesPath, rulesContent, 'utf-8');\r\n \r\n // Record audit entry for new file (non-critical)\r\n try {\r\n const { recordFile } = await import('../../audit/index.js');\r\n await recordFile(projectRoot, 'rule', rulesPath, agent);\r\n } catch { /* audit is optional */ }\r\n }\r\n }\r\n } catch { /* silent */ }\r\n}\r\n\r\n/**\r\n * Get the memorix agent rules content.\r\n * Windsurf requires YAML frontmatter with trigger mode.\r\n * Cursor .mdc files use a similar frontmatter format.\r\n */\r\nfunction getAgentRulesContent(agent?: AgentName): string {\r\n let frontmatter = '';\r\n if (agent === 'windsurf') {\r\n frontmatter = `---\r\ntrigger: always_on\r\n---\r\n\r\n`;\r\n } else if (agent === 'cursor') {\r\n frontmatter = `---\r\ndescription: Memorix automatic memory recording rules\r\nalwaysApply: true\r\n---\r\n\r\n`;\r\n }\r\n return `${frontmatter}# Memorix — Automatic Memory Rules\r\n\r\nYou have access to Memorix memory tools. Follow these rules to maintain persistent context across sessions.\r\n\r\n## RULE 1: Session Start — Bind Project, Then Load Context\r\n\r\nAt the **beginning of every conversation**, BEFORE responding to the user:\r\n\r\n1. Call \\`memorix_session_start\\` with parameters:\r\n - \\`agent\\`: your agent identifier (e.g. \"windsurf\", \"codex\", \"antigravity\")\r\n - \\`projectRoot\\`: the **absolute path** of the current workspace or repo root\r\n This binds the session to the correct project. Without \\`projectRoot\\`, memories may go to the wrong bucket.\r\n2. Then call \\`memorix_search\\` with a query related to the user's first message for additional context\r\n3. If search results are found, use \\`memorix_detail\\` to fetch the most relevant ones\r\n4. Reference relevant memories naturally — the user should feel you \"remember\" them\r\n\r\n**Important:** \\`projectRoot\\` is a detection anchor only; Git remains the source of truth for project identity.\r\nIn HTTP control-plane mode (\\`memorix serve-http\\` / \\`memorix background start\\`), explicit \\`projectRoot\\` binding is required for correct multi-project isolation.\r\n\\`memorix_session_start\\` is lightweight by default: it starts memory/session context only. Do not set \\`joinTeam\\` unless the user explicitly needs autonomous Agent Team tasks, messages, file locks, or orchestrated CLI-agent workflows.\n\r\n## RULE 2: Store Important Context\r\n\r\n**Proactively** call \\`memorix_store\\` when any of the following happen:\r\n\r\n### What MUST be recorded:\r\n- Architecture/design decisions → type: \\`decision\\`\r\n- Bug identified and fixed → type: \\`problem-solution\\`\r\n- Unexpected behavior or gotcha → type: \\`gotcha\\`\r\n- Config changed (env vars, ports, deps) → type: \\`what-changed\\`\r\n- Feature completed or milestone → type: \\`what-changed\\`\r\n- Trade-off discussed with conclusion → type: \\`trade-off\\`\r\n\r\n### What should NOT be recorded:\r\n- Simple file reads, greetings, trivial commands (ls, pwd, git status)\r\n\r\n### Use topicKey for evolving topics:\r\nFor decisions, architecture docs, or any topic that evolves over time, ALWAYS use \\`topicKey\\` parameter.\r\nThis ensures the memory is UPDATED instead of creating duplicates.\r\nUse \\`memorix_suggest_topic_key\\` to generate a stable key.\r\n\r\nExample: \\`topicKey: \"architecture/auth-model\"\\` — subsequent stores with the same key update the existing memory.\r\n\r\n### Track progress with the progress parameter:\r\nWhen working on features or tasks, include the \\`progress\\` parameter:\r\n\\`\\`\\`json\r\n{\r\n \"progress\": {\r\n \"feature\": \"user authentication\",\r\n \"status\": \"in-progress\",\r\n \"completion\": 60\r\n }\r\n}\r\n\\`\\`\\`\r\nStatus values: \\`in-progress\\`, \\`completed\\`, \\`blocked\\`\r\n\r\n## RULE 3: Resolve Completed Memories\r\n\r\nWhen a task is completed, a bug is fixed, or information becomes outdated:\r\n\r\n1. Call \\`memorix_resolve\\` with the observation IDs to mark them as resolved\r\n2. Resolved memories are hidden from default search, preventing context pollution\r\n\r\nThis is critical — without resolving, old bug reports and completed tasks will keep appearing in future searches.\r\n\r\n## RULE 4: Session End — Store Decision Chain Summary\r\n\r\nWhen the conversation is ending, create a **decision chain summary** (not just a checklist):\r\n\r\n1. Call \\`memorix_store\\` with type \\`session-request\\` and \\`topicKey: \"session/latest-summary\"\\`:\r\n\r\n **Required structure:**\r\n \\`\\`\\`\r\n ## Goal\r\n [What we were working on — specific, not vague]\r\n\r\n ## Key Decisions & Reasoning\r\n - Chose X because Y. Rejected Z because [reason].\r\n - [Every architectural/design decision with WHY]\r\n\r\n ## What Changed\r\n - [File path] — [what changed and why]\r\n\r\n ## Current State\r\n - [What works now, what's pending]\r\n - [Any blockers or risks]\r\n\r\n ## Next Steps\r\n - [Concrete next actions, in priority order]\r\n \\`\\`\\`\r\n\r\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.\r\n\r\n2. Call \\`memorix_resolve\\` on any memories for tasks completed in this session\r\n\r\n## RULE 5: Compact Awareness\r\n\r\nMemorix automatically compacts memories on store:\r\n- **With LLM API configured:** Smart dedup — extracts facts, compares with existing, merges or skips duplicates\r\n- **Without LLM (free mode):** Heuristic dedup — uses similarity scores to detect and merge duplicate memories\r\n- **You don't need to manually deduplicate.** Just store naturally and compact handles the rest.\r\n- If you notice excessive duplicate memories, call \\`memorix_deduplicate\\` for batch cleanup.\r\n\r\n## Guidelines\r\n\r\n- **Use concise titles** (~5-10 words) and structured facts\r\n- **Include file paths** in filesModified when relevant\r\n- **Include related concepts** for better searchability\r\n- **Always use topicKey** for recurring topics to prevent duplicates\r\n- **Always resolve** completed tasks and fixed bugs\r\n- **Always include reasoning** — \"chose X because Y\" is 10x more valuable than \"did X\"\r\n- Search defaults to \\`status=\"active\"\\` — use \\`status=\"all\"\\` to include resolved memories\r\n\r\n## Beyond These Rules\r\n\r\nThis file contains the **minimum operating rules** for Memorix memory tools. It is NOT the complete truth about runtime behavior, support tiers, or team semantics.\r\n\r\nFor authoritative, up-to-date details on:\r\n- **Support tiers** (core / extended / community) and what \"installed\" vs \"runtime-ready\" means\r\n- **HTTP control-plane binding** and \\`projectRoot\\` isolation rules\r\n- **Opt-in team semantics** (\\`joinTeam\\`, \\`team_manage join\\`, roles, task claim, handoff validation)\r\n- **Install vs runtime-ready distinction** — hook config written ≠ agent will execute it\r\n- **Agent-specific caveats** (Copilot project-level only, OpenCode plugin lifecycle, etc.)\r\n\r\n→ **Read \\`docs/AGENT_OPERATOR_PLAYBOOK.md\\`** in the Memorix source or npm package.\r\n\r\nIf this file and the playbook conflict, the playbook is authoritative.\r\n`;\r\n}\r\n\r\n/**\r\n * Uninstall hooks for a specific agent.\r\n */\r\nexport async function uninstallHooks(\r\n agent: AgentName,\r\n projectRoot: string,\r\n global = false,\r\n): Promise<boolean> {\r\n // Guard: reject global uninstall for agents that don't support it\r\n if (global && getGlobalConfigPath(agent) === '') {\r\n return false;\r\n }\r\n\r\n const configPath = global\r\n ? getGlobalConfigPath(agent)\r\n : getProjectConfigPath(agent, projectRoot);\r\n\r\n let success = false;\r\n\r\n try {\r\n if (agent === 'kiro' || agent === 'opencode') {\r\n await fs.unlink(configPath);\r\n success = true;\r\n } else {\r\n // For JSON configs, remove the hooks key\r\n const content = await fs.readFile(configPath, 'utf-8');\r\n const config = JSON.parse(content);\r\n delete config.hooks;\r\n\r\n if (Object.keys(config).length === 0) {\r\n await fs.unlink(configPath);\r\n } else {\r\n await fs.writeFile(configPath, JSON.stringify(config, null, 2), 'utf-8');\r\n }\r\n success = true;\r\n }\r\n } catch { /* config file may not exist */ }\r\n\r\n // Also clean up rules files written by memorix\r\n let auditCleaned = false;\r\n try {\r\n const { getProjectFiles, removeFile } = await import('../../audit/index.js');\r\n const prevFiles = await getProjectFiles(projectRoot);\r\n const agentFiles = prevFiles.filter(e => e.agent === agent);\r\n for (const entry of agentFiles) {\r\n try {\r\n const basename = path.basename(entry.path);\r\n // Shared context files: remove only the Memorix block, not the whole file\r\n if (basename === 'AGENTS.md' || basename === 'GEMINI.md' || basename === 'CONTEXT.md') {\r\n try {\r\n const content = await fs.readFile(entry.path, 'utf-8');\r\n const memorixStart = content.indexOf('# Memorix');\r\n if (memorixStart >= 0) {\r\n // Find the next top-level heading after Memorix block\r\n const afterMemorix = content.substring(memorixStart);\r\n const nextHeadingMatch = afterMemorix.match(/\\n# [^#]/);\r\n let before = content.substring(0, memorixStart).trimEnd();\r\n let after = '';\r\n if (nextHeadingMatch && nextHeadingMatch.index != null) {\r\n after = afterMemorix.substring(nextHeadingMatch.index + 1).trimStart();\r\n }\r\n const cleaned = (before + '\\n' + after).trim();\r\n if (cleaned.length === 0) {\r\n // File only had Memorix content — delete it\r\n await fs.unlink(entry.path);\r\n } else {\r\n await fs.writeFile(entry.path, cleaned + '\\n', 'utf-8');\r\n }\r\n }\r\n } catch { /* file read failed, skip */ }\r\n await removeFile(projectRoot, entry.path);\r\n auditCleaned = true;\r\n continue;\r\n }\r\n // Non-shared files: safe to unlink entirely\r\n await fs.unlink(entry.path);\r\n await removeFile(projectRoot, entry.path);\r\n auditCleaned = true;\r\n } catch { /* file already gone */ }\r\n }\r\n } catch { /* audit cleanup is best-effort */ }\r\n\r\n // For rules-only agents, audit cleanup success counts as overall success\r\n if (auditCleaned) success = true;\r\n\r\n // Remove empty parent directories left behind (e.g. .cursor/rules/ if empty)\r\n if (success) {\r\n try {\r\n const { rm } = await import('node:fs/promises');\r\n const dir = path.dirname(configPath);\r\n // Try to remove empty dirs up to project root (max 3 levels)\r\n let current = dir;\r\n for (let i = 0; i < 3; i++) {\r\n try {\r\n const entries = await fs.readdir(current);\r\n if (entries.length === 0) {\r\n await rm(current, { recursive: true });\r\n current = path.dirname(current);\r\n } else {\r\n break; // non-empty dir, stop\r\n }\r\n } catch { break; }\r\n }\r\n } catch { /* cleanup is best-effort */ }\r\n }\r\n\r\n return success;\r\n}\r\n\r\n/**\r\n * Check hook installation status for all agents.\r\n *\r\n * For config-based agents (Claude, Cursor, etc.), file existence is a reliable\r\n * indicator because the agent reads the config file directly.\r\n *\r\n * For OpenCode (plugin-based), file existence alone is NOT sufficient to confirm\r\n * the plugin is actually loaded and firing events. The `verified` field distinguishes:\r\n * - false: plugin file exists but runtime load is unverified\r\n * - true: not currently achievable programmatically (would require OpenCode API)\r\n *\r\n * The `outdated` field for OpenCode also detects the old v3 plugin (which used an\r\n * invalid catch-all `event` handler that never fires) vs the correct v4+ format\r\n * (individual event-name keys like `session.created`, `file.edited`).\r\n */\r\nexport async function getHookStatus(\r\n projectRoot: string,\r\n): Promise<Array<{ agent: AgentName; installed: boolean; outdated: boolean; verified: boolean; runtimeReady: boolean; configPath: string }>> {\r\n const results: Array<{ agent: AgentName; installed: boolean; outdated: boolean; verified: boolean; runtimeReady: boolean; configPath: string }> = [];\r\n const agents: AgentName[] = ['claude', 'copilot', 'windsurf', 'cursor', 'kiro', 'codex', 'antigravity', 'gemini-cli', 'opencode', 'trae'];\r\n\r\n for (const agent of agents) {\r\n const projectPath = getProjectConfigPath(agent, projectRoot);\r\n const globalPath = getGlobalConfigPath(agent);\r\n\r\n let installed = false;\r\n let outdated = false;\r\n let usedPath = projectPath;\r\n\r\n // Config-based agents: file existence = verified (agent reads config directly)\r\n // Plugin-based agents (OpenCode): file existence ≠ verified (must be loaded by runtime)\r\n const verifiedByDefault = agent !== 'opencode';\r\n\r\n try {\r\n await fs.access(projectPath);\r\n installed = true;\r\n } catch {\r\n // Only check global path if the agent actually supports global hooks\r\n // (empty string = not supported, e.g. Copilot)\r\n if (globalPath) {\r\n try {\r\n await fs.access(globalPath);\r\n installed = true;\r\n usedPath = globalPath;\r\n } catch { /* not installed */ }\r\n }\r\n }\r\n\r\n if (installed && agent === 'opencode') {\r\n try {\r\n const content = await fs.readFile(usedPath, 'utf-8');\r\n const match = content.match(/@generated-version\\s+(\\d+)/);\r\n const installedVersion = match ? parseInt(match[1], 10) : 0;\r\n outdated = installedVersion < OPENCODE_PLUGIN_VERSION;\r\n } catch {\r\n outdated = false;\r\n }\r\n }\r\n\r\n // Runtime readiness: Copilot on Windows requires pwsh for the powershell field\r\n let runtimeReady = true;\r\n if (agent === 'copilot' && process.platform === 'win32' && installed) {\r\n runtimeReady = detectPwsh();\r\n }\r\n\r\n results.push({\r\n agent,\r\n installed,\r\n outdated,\r\n verified: installed && verifiedByDefault,\r\n runtimeReady,\r\n configPath: usedPath,\r\n });\r\n }\r\n\r\n return results;\r\n}\r\n","/**\r\n * Git hooks path resolver — worktree-safe.\r\n *\r\n * In a normal repo: .git is a directory → hooks at .git/hooks/\r\n * In a git worktree: .git is a FILE containing \"gitdir: /path/to/actual/git/dir\"\r\n * → hooks at that resolved path + /hooks/\r\n *\r\n * This utility ensures all hook install/uninstall/check operations\r\n * work correctly in both scenarios.\r\n */\r\n\r\nimport { existsSync, readFileSync, statSync, mkdirSync } from 'node:fs';\r\nimport path from 'node:path';\r\n\r\n/**\r\n * Resolve the actual .git directory path, following worktree indirection.\r\n *\r\n * @param projectRoot - The root of the working tree (where .git lives)\r\n * @returns Absolute path to the real git dir, or null if no .git found\r\n */\r\nexport function resolveGitDir(projectRoot: string): string | null {\r\n const dotGit = path.join(projectRoot, '.git');\r\n\r\n if (!existsSync(dotGit)) return null;\r\n\r\n const stat = statSync(dotGit);\r\n\r\n if (stat.isDirectory()) {\r\n // Normal repo — .git is a directory\r\n return dotGit;\r\n }\r\n\r\n if (stat.isFile()) {\r\n // Worktree — .git is a file: \"gitdir: /path/to/actual/git/dir\"\r\n try {\r\n const content = readFileSync(dotGit, 'utf-8').trim();\r\n const match = content.match(/^gitdir:\\s*(.+)$/);\r\n if (match) {\r\n const gitdir = match[1].trim();\r\n // Resolve relative paths against the project root\r\n const resolved = path.isAbsolute(gitdir)\r\n ? gitdir\r\n : path.resolve(projectRoot, gitdir);\r\n if (existsSync(resolved)) {\r\n return resolved;\r\n }\r\n }\r\n } catch {\r\n // Unreadable .git file — fall through\r\n }\r\n }\r\n\r\n return null;\r\n}\r\n\r\n/**\r\n * Resolve the hooks directory for a project (read-only — does NOT create directories).\r\n * Handles both normal repos and git worktrees.\r\n *\r\n * @param projectRoot - The root of the working tree\r\n * @returns Object with hooksDir and hookPath for post-commit, or null if no .git found\r\n */\r\nexport function resolveHooksDir(projectRoot: string): { hooksDir: string; hookPath: string } | null {\r\n const gitDir = resolveGitDir(projectRoot);\r\n if (!gitDir) return null;\r\n\r\n const hooksDir = path.join(gitDir, 'hooks');\r\n\r\n return {\r\n hooksDir,\r\n hookPath: path.join(hooksDir, 'post-commit'),\r\n };\r\n}\r\n\r\n/**\r\n * Resolve hooks directory AND ensure it exists on disk.\r\n * Use this only in write paths (hook install / autoHook).\r\n */\r\nexport function ensureHooksDir(projectRoot: string): { hooksDir: string; hookPath: string } | null {\r\n const resolved = resolveHooksDir(projectRoot);\r\n if (!resolved) return null;\r\n\r\n mkdirSync(resolved.hooksDir, { recursive: true });\r\n return resolved;\r\n}\r\n","/**\r\n * Memorix SDK — Programmatic API for embedding Memorix into your own projects.\r\n *\r\n * Usage:\r\n * import { createMemoryClient } from 'memorix/sdk';\r\n *\r\n * const client = await createMemoryClient({ projectRoot: '/path/to/repo' });\r\n * await client.store({ entityName: 'auth', type: 'decision', title: '...', narrative: '...' });\r\n * const results = await client.search('auth decisions');\r\n * await client.close();\r\n *\r\n * For MCP server embedding:\r\n * import { createMemorixServer } from 'memorix/sdk';\r\n *\r\n * const { server, projectId } = await createMemorixServer('/path/to/repo');\r\n * // Connect to your own transport\r\n */\r\n\r\nimport type {\r\n Observation,\r\n ObservationType,\r\n ObservationStatus,\r\n IndexEntry,\r\n SearchOptions,\r\n ProgressInfo,\r\n ProjectInfo,\r\n DetectionResult,\r\n} from './types.js';\r\n\r\n// ── Re-exports for convenience ──────────────────────────────────────\r\n\r\nexport { createMemorixServer } from './server.js';\r\nexport type { CreateMemorixServerOptions } from './server.js';\r\nexport { detectProject, detectProjectWithDiagnostics } from './project/detector.js';\r\nexport * from './types.js';\r\n\r\n// ── SDK Client ──────────────────────────────────────────────────────\r\n\r\n/** Options for creating a MemoryClient */\r\nexport interface MemoryClientOptions {\r\n /** Absolute path to a Git project root. Required. */\r\n projectRoot: string;\r\n /**\r\n * If true, suppress console.error diagnostic logs during initialization.\r\n * Default: false.\r\n */\r\n silent?: boolean;\r\n}\r\n\r\n/** Input for storing an observation */\r\nexport interface StoreInput {\r\n entityName: string;\r\n type: ObservationType;\r\n title: string;\r\n narrative: string;\r\n facts?: string[];\r\n filesModified?: string[];\r\n concepts?: string[];\r\n topicKey?: string;\r\n sessionId?: string;\r\n progress?: ProgressInfo;\r\n source?: 'agent' | 'git' | 'manual';\r\n commitHash?: string;\r\n relatedCommits?: string[];\r\n relatedEntities?: string[];\r\n sourceDetail?: 'explicit' | 'hook' | 'git-ingest';\r\n valueCategory?: 'core' | 'contextual' | 'ephemeral';\r\n}\r\n\r\n/** Result from storing an observation */\r\nexport interface StoreResult {\r\n observation: Observation;\r\n upserted: boolean;\r\n}\r\n\r\n/** Options for searching */\r\nexport interface ClientSearchOptions {\r\n query: string;\r\n /** Filter by observation type */\r\n type?: ObservationType;\r\n /** Filter by observation source */\r\n source?: 'agent' | 'git' | 'manual';\r\n /** Filter by status. Default: 'active' */\r\n status?: ObservationStatus | 'all';\r\n /** Maximum results. Default: 20 */\r\n limit?: number;\r\n}\r\n\r\n/** Result from resolving observations */\r\nexport interface ResolveResult {\r\n resolved: number[];\r\n notFound: number[];\r\n}\r\n\r\n/**\r\n * A lightweight, self-contained memory client for reading and writing\r\n * Memorix observations without MCP overhead.\r\n *\r\n * Each client initializes its own SQLite backend and Orama search index,\r\n * scoped to a single project. Call `close()` when done to release resources.\r\n */\r\nexport class MemoryClient {\r\n private _projectId: string;\r\n private _projectRoot: string;\r\n private _dataDir: string;\r\n private _closed = false;\r\n\r\n // Internal module references — loaded lazily to avoid top-level side effects\r\n private _observations!: typeof import('./memory/observations.js');\r\n private _oramaStore!: typeof import('./store/orama-store.js');\r\n private _obsStore!: typeof import('./store/obs-store.js');\r\n private _freshness!: typeof import('./memory/freshness.js');\r\n\r\n /** @internal — use createMemoryClient() instead */\r\n constructor(projectId: string, projectRoot: string, dataDir: string) {\r\n this._projectId = projectId;\r\n this._projectRoot = projectRoot;\r\n this._dataDir = dataDir;\r\n }\r\n\r\n /** The canonical project ID (derived from Git remote or local path) */\r\n get projectId(): string { return this._projectId; }\r\n\r\n /** The project root path */\r\n get projectRoot(): string { return this._projectRoot; }\r\n\r\n /** The Memorix data directory for this project */\r\n get dataDir(): string { return this._dataDir; }\r\n\r\n /**\r\n * @internal Initialize stores and search index.\r\n * Called by createMemoryClient(). Do not call directly.\r\n */\r\n async _init(silent: boolean): Promise<void> {\r\n // Suppress logs if requested\r\n const originalError = console.error;\r\n if (silent) {\r\n console.error = () => {};\r\n }\r\n\r\n try {\r\n this._obsStore = await import('./store/obs-store.js');\r\n this._observations = await import('./memory/observations.js');\r\n this._oramaStore = await import('./store/orama-store.js');\r\n this._freshness = await import('./memory/freshness.js');\r\n\r\n // Initialize observation store (SQLite backend)\r\n await this._obsStore.initObservationStore(this._dataDir);\r\n\r\n // Initialize observations in-memory state\r\n await this._observations.initObservations(this._dataDir);\r\n\r\n // Prepare search index (hydrate Orama from SQLite)\r\n await this._observations.prepareSearchIndex();\r\n } finally {\r\n if (silent) {\r\n console.error = originalError;\r\n }\r\n }\r\n }\r\n\r\n private _ensureOpen(): void {\r\n if (this._closed) throw new Error('[memorix-sdk] MemoryClient is closed');\r\n }\r\n\r\n /**\r\n * Store a new observation (or upsert if topicKey matches an existing one).\r\n *\r\n * @example\r\n * ```ts\r\n * const { observation } = await client.store({\r\n * entityName: 'auth-module',\r\n * type: 'decision',\r\n * title: 'Use JWT for API auth',\r\n * narrative: 'Chose JWT over session cookies for stateless API authentication.',\r\n * facts: ['Token expiry: 1h', 'Refresh token: 7d'],\r\n * });\r\n * ```\r\n */\r\n async store(input: StoreInput): Promise<StoreResult> {\r\n this._ensureOpen();\r\n return this._observations.storeObservation({\r\n ...input,\r\n projectId: this._projectId,\r\n });\r\n }\r\n\r\n /**\r\n * Search observations using full-text and optional vector search.\r\n *\r\n * @example\r\n * ```ts\r\n * const results = await client.search({ query: 'authentication decisions' });\r\n * for (const r of results) {\r\n * console.log(`${r.title} (score: ${r.score})`);\r\n * }\r\n * ```\r\n */\r\n async search(options: ClientSearchOptions): Promise<IndexEntry[]> {\r\n this._ensureOpen();\r\n await this._freshness.withFreshIndex(() => {});\r\n\r\n const searchOpts: SearchOptions = {\r\n query: options.query,\r\n projectId: this._projectId,\r\n limit: options.limit ?? 20,\r\n type: options.type,\r\n source: options.source,\r\n status: options.status === 'all' ? undefined : (options.status ?? 'active'),\r\n };\r\n\r\n return this._oramaStore.searchObservations(searchOpts);\r\n }\r\n\r\n /**\r\n * Get a single observation by ID.\r\n */\r\n async get(id: number): Promise<Observation | undefined> {\r\n this._ensureOpen();\r\n await this._freshness.withFreshIndex(() => {});\r\n return this._observations.getObservation(id, this._projectId);\r\n }\r\n\r\n /**\r\n * Get all observations for this project.\r\n */\r\n async getAll(): Promise<Observation[]> {\r\n this._ensureOpen();\r\n await this._freshness.withFreshIndex(() => {});\r\n return this._observations.getProjectObservations(this._projectId);\r\n }\r\n\r\n /**\r\n * Get the total observation count for this project.\r\n */\r\n async count(): Promise<number> {\r\n this._ensureOpen();\r\n await this._freshness.withFreshIndex(() => {});\r\n return this._observations.getProjectObservations(this._projectId).length;\r\n }\r\n\r\n /**\r\n * Mark observations as resolved or archived.\r\n *\r\n * Resolved observations are hidden from default search but recoverable.\r\n * Archived observations are permanently hidden.\r\n *\r\n * @example\r\n * ```ts\r\n * await client.resolve([1, 2, 3]);\r\n * await client.resolve([4], 'archived');\r\n * ```\r\n */\r\n async resolve(ids: number[], status: ObservationStatus = 'resolved'): Promise<ResolveResult> {\r\n this._ensureOpen();\r\n return this._observations.resolveObservations(ids, status);\r\n }\r\n\r\n /**\r\n * Release resources (close SQLite handle, reset index).\r\n * The client cannot be used after calling close().\r\n */\r\n async close(): Promise<void> {\r\n if (this._closed) return;\r\n this._closed = true;\r\n try {\r\n this._obsStore.resetObservationStore();\r\n await this._oramaStore.resetDb();\r\n } catch {\r\n // best-effort cleanup\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Create a new MemoryClient for a project.\r\n *\r\n * This initializes SQLite, loads observations, and prepares the search index.\r\n * Each client is independent — you can have multiple clients for different projects.\r\n *\r\n * @example\r\n * ```ts\r\n * import { createMemoryClient } from 'memorix/sdk';\r\n *\r\n * const client = await createMemoryClient({ projectRoot: '/home/user/my-project' });\r\n *\r\n * // Store a memory\r\n * await client.store({\r\n * entityName: 'api-gateway',\r\n * type: 'gotcha',\r\n * title: 'Rate limiter resets on deploy',\r\n * narrative: 'In-memory rate limiter state is lost on every deploy...',\r\n * });\r\n *\r\n * // Search memories\r\n * const results = await client.search({ query: 'rate limiter' });\r\n *\r\n * // Clean up\r\n * await client.close();\r\n * ```\r\n */\r\nexport async function createMemoryClient(options: MemoryClientOptions): Promise<MemoryClient> {\r\n const { projectRoot, silent = false } = options;\r\n\r\n // Detect project from Git root\r\n const { detectProject: detect } = await import('./project/detector.js');\r\n const project = detect(projectRoot);\r\n if (!project) {\r\n throw new Error(\r\n `[memorix-sdk] No Git repository found at \"${projectRoot}\". ` +\r\n 'Memorix requires a Git-tracked project for identity resolution.',\r\n );\r\n }\r\n\r\n // Resolve data directory\r\n const path = await import('node:path');\r\n const os = await import('node:os');\r\n const dataDir = path.join(os.homedir(), '.memorix', 'data', project.id.replace(/\\//g, path.sep));\r\n\r\n // Ensure data directory exists\r\n const fs = await import('node:fs');\r\n fs.mkdirSync(dataDir, { recursive: true });\r\n\r\n const client = new MemoryClient(project.id, projectRoot, dataDir);\r\n await client._init(silent);\r\n return client;\r\n}\r\n","/**\r\n * Memorix MCP Server\r\n *\r\n * Registers all MCP tools and handles the server lifecycle.\r\n *\r\n * Tool sources:\r\n * - memorix_store / memorix_search / memorix_detail / memorix_timeline:\r\n * Memorix extensions using claude-mem's 3-layer Progressive Disclosure\r\n * - create_entities / create_relations / add_observations / delete_entities /\r\n * delete_observations / delete_relations / search_nodes / open_nodes / read_graph:\r\n * MCP Official Memory Server compatible interface (P1)\r\n *\r\n * Extensibility:\r\n * - New tools can be registered via server.registerTool()\r\n * - Rules sync tools will be added in P2\r\n * - New agent format adapters plug in without changing this file\r\n */\r\n\r\nimport { createHash } from 'node:crypto';\r\nimport { watchFile } from 'node:fs';\r\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport { z } from 'zod';\r\nimport { KnowledgeGraphManager } from './memory/graph.js';\r\nimport { initObservations, storeObservation, prepareSearchIndex, migrateProjectIds, getObservation, getAllObservations } from './memory/observations.js';\r\nimport { withFreshIndex } from './memory/freshness.js';\r\nimport { initObservationStore, getObservationStore } from './store/obs-store.js';\r\nimport { resetDb } from './store/orama-store.js';\r\nimport { initMiniSkillStore } from './store/mini-skill-store.js';\r\nimport { initSessionStore } from './store/session-store.js';\r\nimport { checkProjectAttribution, auditProjectObservations } from './memory/attribution-guard.js';\r\nimport { createAutoRelations } from './memory/auto-relations.js';\r\nimport { extractEntities } from './memory/entity-extractor.js';\r\nimport { compactSearch, compactTimeline, compactDetail } from './compact/engine.js';\r\nimport { detectProject } from './project/detector.js';\r\nimport { registerAlias, initAliasRegistry, resolveAliases, autoMergeByBaseName } from './project/aliases.js';\r\nimport { getProjectDataDir } from './store/persistence.js';\r\nimport type { ObservationType, RuleSource, AgentTarget, MCPServerEntry } from './types.js';\r\nimport { RulesSyncer } from './rules/syncer.js';\r\nimport { WorkspaceSyncEngine } from './workspace/engine.js';\r\nimport {\r\n resolveToolProfile,\r\n isToolInProfile,\r\n describeProfile,\r\n type ToolProfile,\r\n} from './server/tool-profile.js';\r\nimport { initLLM, isLLMEnabled, getLLMConfig } from './llm/provider.js';\r\nimport { compactOnWrite, deduplicateMemory } from './llm/memory-manager.js';\r\nimport type { ExistingMemory } from './llm/memory-manager.js';\r\nimport { runFormation, getMetricsSummary, getBeforeAfterMetrics } from './memory/formation/index.js';\r\nimport type { FormationConfig, SearchHit, FormedMemory, FormationStage, FormationStageEvent } from './memory/formation/types.js';\r\nimport { parseFormationTimeoutMs } from './server/formation-timeout.js';\r\n\r\n// ── Timeout budgets for LLM-heavy paths ──────────────────────────\r\nconst FORMATION_TIMEOUT_MS = parseFormationTimeoutMs(process.env.MEMORIX_FORMATION_TIMEOUT_MS); // Formation pipeline (extract+resolve+evaluate)\r\nconst COMPACT_ON_WRITE_TIMEOUT_MS = 12_000; // Legacy compact-on-write fallback path\r\nconst COMPRESSION_TIMEOUT_MS = 5_000; // Narrative compression\r\nconst DEDUP_PER_PAIR_TIMEOUT_MS = 5_000; // Per-pair dedup LLM call\r\n\r\n/** Race a promise against a timeout. Rejects with a descriptive Error on timeout. */\r\nfunction withTimeout<T>(promise: Promise<T>, ms: number, label: string): Promise<T> {\r\n let timer: ReturnType<typeof setTimeout>;\r\n return Promise.race([\r\n promise,\r\n new Promise<never>((_, reject) => {\r\n timer = setTimeout(() => reject(new Error(`${label} timed out after ${ms}ms`)), ms);\r\n }),\r\n ]).finally(() => clearTimeout(timer!));\r\n}\r\n\r\nfunction formatFormationStageDurations(stageDurationsMs: Partial<Record<FormationStage, number>>): string {\r\n const orderedStages: FormationStage[] = ['extract', 'resolve', 'evaluate'];\r\n const parts = orderedStages\r\n .filter(stage => stageDurationsMs[stage] !== undefined)\r\n .map(stage => `${stage}=${stageDurationsMs[stage]}ms`);\r\n return parts.join(', ');\r\n}\r\n\r\n/** Timestamp of last MCP-initiated write — hot-reload skips changes within 10s */\r\nlet lastInternalWriteMs = 0;\r\nconst markInternalWrite = () => { lastInternalWriteMs = Date.now(); };\r\n\r\n/** Valid observation types for input validation */\r\nconst OBSERVATION_TYPES: [string, ...string[]] = [\r\n 'session-request',\r\n 'gotcha',\r\n 'problem-solution',\r\n 'reasoning',\r\n 'how-it-works',\r\n 'what-changed',\r\n 'discovery',\r\n 'why-it-exists',\r\n 'decision',\r\n 'trade-off',\r\n];\r\n\r\n/**\r\n * Defensive parameter coercion for Claude Code CLI + non-Anthropic models (e.g. GLM).\r\n * Claude Code CLI has a known bug (#5504, #26027) where JSON objects/arrays\r\n * get serialized as strings. GLM models amplify this by producing string-encoded\r\n * arrays/numbers in tool calls. These helpers ensure Memorix works regardless.\r\n */\r\nfunction coerceNumberArray(val: unknown): number[] {\r\n if (Array.isArray(val)) return val.map(Number);\r\n if (typeof val === 'string') {\r\n try {\r\n const parsed = JSON.parse(val);\r\n if (Array.isArray(parsed)) return parsed.map(Number);\r\n } catch { /* not valid JSON */ }\r\n }\r\n return [];\r\n}\r\n\r\nfunction coerceObservationRefs(val: unknown): Array<{ id: number; projectId?: string }> {\r\n if (Array.isArray(val)) {\r\n const refs: Array<{ id: number; projectId?: string }> = [];\r\n for (const item of val) {\r\n if (!item || typeof item !== 'object') continue;\r\n const record = item as Record<string, unknown>;\r\n const id = Number(record['id']);\r\n if (!Number.isFinite(id) || id <= 0) continue;\r\n\r\n const projectId = typeof record['projectId'] === 'string' ? record['projectId'] : undefined;\r\n refs.push(projectId ? { id, projectId } : { id });\r\n }\r\n return refs;\r\n }\r\n if (typeof val === 'string') {\r\n try {\r\n const parsed = JSON.parse(val);\r\n return coerceObservationRefs(parsed);\r\n } catch {\r\n return [];\r\n }\r\n }\r\n return [];\r\n}\r\n\r\nfunction coerceNumber(val: unknown, fallback: number): number {\r\n if (typeof val === 'number') return val;\r\n if (typeof val === 'string') {\r\n const n = Number(val);\r\n if (!Number.isNaN(n)) return n;\r\n }\r\n return fallback;\r\n}\r\n\r\nfunction coerceStringArray(val: unknown): string[] {\r\n if (Array.isArray(val)) return val.map(String);\r\n if (typeof val === 'string') {\r\n try {\r\n const parsed = JSON.parse(val);\r\n if (Array.isArray(parsed)) return parsed.map(String);\r\n } catch { /* not valid JSON */ }\r\n }\r\n return [];\r\n}\r\n\r\nfunction coerceObject<T>(val: unknown): T | null {\r\n if (typeof val === 'object' && val !== null && !Array.isArray(val)) return val as T;\r\n if (typeof val === 'string') {\r\n try {\r\n const parsed = JSON.parse(val);\r\n if (typeof parsed === 'object' && parsed !== null) return parsed as T;\r\n } catch { /* not valid JSON */ }\r\n }\r\n return null;\r\n}\r\n\r\nfunction coerceObjectArray<T>(val: unknown): T[] {\r\n if (Array.isArray(val)) {\r\n return val.map(item => {\r\n if (typeof item === 'string') {\r\n try { return JSON.parse(item); } catch { return item; }\r\n }\r\n return item;\r\n });\r\n }\r\n if (typeof val === 'string') {\r\n try {\r\n const parsed = JSON.parse(val);\r\n if (Array.isArray(parsed)) return parsed;\r\n } catch { /* not valid JSON */ }\r\n }\r\n return [];\r\n}\r\n\r\nfunction createDeterministicInstanceId(projectId: string, agentType: string, agentName?: string): string {\r\n const digest = createHash('sha256')\r\n .update(projectId)\r\n .update('\\n')\r\n .update(agentType)\r\n .update('\\n')\r\n .update(agentName ?? '')\r\n .digest('hex')\r\n .slice(0, 24);\r\n return `auto-${digest}`;\r\n}\r\n\r\n/**\r\n * Create and configure the Memorix MCP Server.\r\n */\r\n/** Optional shared TeamStore — passed by serve-http so all sessions share state */\r\nexport interface SharedTeamInstances {\r\n teamStore: import('./team/team-store.js').TeamStore;\r\n}\r\n\r\nexport interface CreateMemorixServerOptions {\r\n allowUntrackedFallback?: boolean;\r\n deferProjectInitUntilBound?: boolean;\r\n dashboardMode?: 'standalone' | 'control-plane';\r\n dashboardPort?: number;\r\n toolProfile?: ToolProfile;\r\n}\r\n\r\nexport async function createMemorixServer(\r\n cwd?: string,\r\n existingServer?: McpServer,\r\n sharedTeam?: SharedTeamInstances,\r\n options: CreateMemorixServerOptions = {},\r\n): Promise<{\r\n server: McpServer;\r\n graphManager: KnowledgeGraphManager;\r\n projectId: string;\r\n deferredInit: () => Promise<void>;\r\n switchProject: (newCwd: string) => Promise<boolean>;\r\n isExplicitlyBound: () => boolean;\r\n handleTransportClose: () => void;\r\n}> {\r\n // Detect current project — strict .git-based detection\r\n const allowUntrackedFallback = options.allowUntrackedFallback ?? true;\r\n const deferProjectInitUntilBound = options.deferProjectInitUntilBound ?? false;\r\n const dashboardMode = options.dashboardMode ?? (sharedTeam ? 'control-plane' : 'standalone');\r\n const configuredDashboardPort = options.dashboardPort ?? (dashboardMode === 'control-plane' ? 3211 : 3210);\r\n const toolProfile = resolveToolProfile({\r\n explicit: options.toolProfile,\r\n envValue: process.env.MEMORIX_MODE,\r\n fallback: sharedTeam ? 'team' : 'lite',\r\n });\r\n const teamFeaturesEnabled = isToolInProfile('team_manage', toolProfile);\r\n const detectedProject = detectProject(cwd);\r\n let rawProject: import('./types.js').ProjectInfo;\r\n let projectResolved = true;\r\n let projectResolutionError: string | null = null;\r\n let explicitProjectBound = false; // Set true when memorix_session_start binds via projectRoot\r\n let currentAgentId: string | undefined; // Session-scoped Agent Team identity for attribution after explicit join\r\n if (detectedProject) {\r\n rawProject = detectedProject;\r\n } else {\r\n const basePath = cwd ?? process.cwd();\r\n const name = (await import('node:path')).basename(basePath) || 'unknown';\r\n projectResolved = false;\r\n projectResolutionError =\r\n `No git project could be resolved from \"${basePath}\". ` +\r\n 'This client did not provide a usable workspace root, so project-scoped tools are disabled until a git-backed project is detected.';\r\n rawProject = allowUntrackedFallback\r\n ? { id: `untracked/${name}`, name, rootPath: basePath }\r\n : { id: '__unresolved__', name, rootPath: basePath };\r\n if (!allowUntrackedFallback && !deferProjectInitUntilBound) {\r\n console.error(`[memorix] WARNING: ${projectResolutionError}`);\r\n } else if (allowUntrackedFallback) {\r\n console.error(`[memorix] WARNING: No .git found in \"${basePath}\" - project isolation degraded`);\r\n console.error(`[memorix] Run \"git init\" in your project for proper isolation.`);\r\n }\r\n }\r\n\r\n // Migrate legacy per-project subdirectories into flat base directory (one-time, silent)\r\n try {\r\n const { migrateSubdirsToFlat } = await import('./store/persistence.js');\r\n const migrated = await migrateSubdirsToFlat();\r\n if (migrated) {\r\n console.error(`[memorix] Migrated per-project subdirectories into flat storage`);\r\n }\r\n } catch { /* migration is optional */ }\r\n\r\n let projectDir = await getProjectDataDir(rawProject.id);\r\n\r\n // Register aliases only for git-backed projects. Unresolved sessions should not\r\n // silently create canonical IDs or pollute alias mappings.\r\n let project = rawProject;\r\n if (projectResolved) {\r\n initAliasRegistry(projectDir);\r\n const canonicalId = await registerAlias(rawProject);\r\n project = { ...rawProject, id: canonicalId };\r\n if (canonicalId !== rawProject.id) {\r\n console.error(`[memorix] Alias resolved: ${rawProject.id} -> ${canonicalId}`);\r\n }\r\n }\r\n\r\n // Initialize project root for YAML config resolution — ensures all config getters\r\n // (getLLMApiKey, getGitConfig, etc.) pick up project-level memorix.yml, not just user-level.\r\n // Also load .env from project root for secrets (API keys, base URLs).\r\n try {\r\n const { initProjectRoot } = await import('./config/yaml-loader.js');\r\n initProjectRoot(project.rootPath);\r\n const { loadDotenv } = await import('./config/dotenv-loader.js');\r\n loadDotenv(project.rootPath);\r\n } catch { /* config init is best-effort */ }\r\n\r\n // Initialize components\r\n await initObservationStore(projectDir);\r\n await initMiniSkillStore(projectDir);\r\n await initSessionStore(projectDir);\r\n {\r\n const store = getObservationStore();\r\n console.error(`[memorix] ObservationStore backend: ${store.getBackendName()}, generation: ${store.getGeneration()}`);\r\n }\r\n let graphManager = new KnowledgeGraphManager(projectDir);\r\n await graphManager.init();\r\n await initObservations(projectDir);\r\n\r\n const lightweightUnresolvedSession = !projectResolved && deferProjectInitUntilBound;\r\n\r\n const initializeProjectRuntime = async (logPrefix: 'startup' | 'switch'): Promise<void> => {\r\n await initObservationStore(projectDir);\r\n await initMiniSkillStore(projectDir);\r\n await initSessionStore(projectDir);\r\n graphManager = new KnowledgeGraphManager(projectDir);\r\n await graphManager.init();\r\n await initObservations(projectDir);\r\n\r\n const indexed = await prepareSearchIndex();\r\n if (indexed > 0) {\r\n console.error(`[memorix] Prepared search index for ${indexed} observations in project: ${project.id}`);\r\n }\r\n\r\n const llmConfig = initLLM();\r\n if (llmConfig) {\r\n console.error(`[memorix] LLM enhanced mode: ${llmConfig.provider}/${llmConfig.model}`);\r\n } else {\r\n console.error(`[memorix] LLM mode: off (set MEMORIX_LLM_API_KEY or OPENAI_API_KEY to enable)`);\r\n }\r\n\r\n if (logPrefix === 'startup') {\r\n console.error(`[memorix] Tool profile: ${describeProfile(toolProfile)}`);\r\n }\r\n\r\n if (logPrefix === 'startup') {\r\n console.error(`[memorix] Project: ${project.id} (${project.name})`);\r\n console.error(`[memorix] Data dir: ${projectDir}`);\r\n } else {\r\n console.error(`[memorix] Project switched to: ${project.id} (${project.name})`);\r\n console.error(`[memorix] Data dir: ${projectDir}`);\r\n }\r\n };\r\n\r\n if (!lightweightUnresolvedSession) {\r\n // Auto-merge obvious alias groups by scanning observed projectIds in data.\r\n // This detects splits like local/foo + user/foo (legacy data migration)\r\n try {\r\n const { getAllObservations } = await import('./memory/observations.js');\r\n const allObs = getAllObservations();\r\n const observedIds = [...new Set(allObs.map(o => o.projectId))];\r\n const merged = await autoMergeByBaseName(observedIds);\r\n if (merged > 0) {\r\n console.error(`[memorix] Auto-merged ${merged} alias group(s) by base name`);\r\n }\r\n } catch { /* auto-merge is optional */ }\r\n\r\n // Migrate existing observations to canonical project ID for ALL alias groups.\r\n // This normalizes split projectIds like local/foo + user/foo → canonical.\r\n try {\r\n const { getAllAliasGroups } = await import('./project/aliases.js');\r\n const groups = await getAllAliasGroups();\r\n let totalMigrated = 0;\r\n for (const group of groups) {\r\n if (group.aliases.length > 1) {\r\n const migrated = await migrateProjectIds(group.aliases, group.canonical);\r\n if (migrated > 0) {\r\n console.error(`[memorix] Migrated ${migrated} observations → ${group.canonical}`);\r\n totalMigrated += migrated;\r\n }\r\n }\r\n }\r\n if (totalMigrated > 0) {\r\n console.error(`[memorix] Total migrated: ${totalMigrated} observations across ${groups.filter(g => g.aliases.length > 1).length} project(s)`);\r\n }\r\n } catch { /* migration is optional */ }\r\n\r\n await initializeProjectRuntime('startup');\r\n } else {\r\n // Intentionally silent — serve-http.ts deferred logging handles session lifecycle visibility.\r\n // Noisy per-probe 'awaiting binding' log was removed to reduce terminal spam.\r\n }\r\n\r\n // Sync advisory variables — populated by deferredInit(), used by memorix_search\r\n let syncAdvisoryShown = false;\r\n let syncAdvisory: string | null = null;\r\n const requireResolvedProject = (action: string) => {\r\n if (projectResolved) return null;\r\n return {\r\n content: [{\r\n type: 'text' as const,\r\n text:\r\n `Cannot ${action} yet.\\n` +\r\n `${projectResolutionError ?? 'No git-backed project is currently bound to this session.'}\\n\\n` +\r\n 'To bind this session to a project, call memorix_session_start with the projectRoot parameter:\\n' +\r\n ' memorix_session_start({ projectRoot: \"/path/to/your/project\" })\\n\\n' +\r\n 'The path should point to a directory containing a .git folder.',\r\n }],\r\n isError: true as const,\r\n };\r\n };\r\n\r\n // Create MCP server (or use existing one from roots-aware flow)\r\n const server = existingServer ?? new McpServer({\r\n name: 'memorix',\r\n version: typeof __MEMORIX_VERSION__ !== 'undefined' ? __MEMORIX_VERSION__ : '1.0.1',\r\n });\r\n\r\n const originalRegisterTool = server.registerTool.bind(server);\r\n server.registerTool = ((name: string, ...args: unknown[]) => {\r\n if (!isToolInProfile(name, toolProfile)) {\r\n return undefined as never;\r\n }\r\n return (originalRegisterTool as (...innerArgs: unknown[]) => unknown)(name, ...args) as never;\r\n }) as typeof server.registerTool;\r\n\r\n // ================================================================\r\n // Memorix Extended Tools (3-layer Progressive Disclosure)\r\n // ================================================================\r\n\r\n /**\r\n * memorix_store — Store a new observation\r\n *\r\n * Primary write API. Agents call this to persist knowledge.\r\n * Auto-assigns ID, counts tokens, indexes for search.\r\n */\r\n server.registerTool(\r\n 'memorix_store',\r\n {\r\n title: 'Store Memory',\r\n description:\r\n 'Store a new observation/memory. Automatically indexed for search. ' +\r\n 'Use type to classify: gotcha ([GOTCHA] critical pitfall), decision ([DECISION] architecture choice), ' +\r\n 'problem-solution ([FIX] bug fix), how-it-works ([INFO] explanation), what-changed ([CHANGE] change), ' +\r\n 'discovery ([DISCOVERY] insight), why-it-exists ([WHY] rationale), trade-off ([TRADEOFF] compromise), ' +\r\n 'session-request ([SESSION] original goal). ' +\r\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.',\r\n inputSchema: {\r\n entityName: z.string().describe('The entity this observation belongs to (e.g., \"auth-module\", \"port-config\")'),\r\n type: z.enum(OBSERVATION_TYPES).describe('Observation type for classification'),\r\n title: z.string().describe('Short descriptive title (~5-10 words)'),\r\n narrative: z.string().describe('Full description of the observation'),\r\n facts: z.array(z.string()).optional().describe('Structured facts (e.g., \"Default timeout: 60s\")'),\r\n filesModified: z.array(z.string()).optional().describe('Files involved'),\r\n concepts: z.array(z.string()).optional().describe('Related concepts/keywords'),\r\n topicKey: z.string().optional().describe(\r\n 'Optional topic identifier for upserts (e.g., \"architecture/auth-model\"). ' +\r\n 'If an observation with the same topicKey already exists in this project, it will be UPDATED instead of creating a new one. ' +\r\n 'Use memorix_suggest_topic_key to generate a stable key. Good for evolving decisions, architecture docs, etc.',\r\n ),\r\n progress: z.object({\r\n feature: z.string().describe('Feature or task name'),\r\n status: z.enum(['in-progress', 'completed', 'blocked']).describe('Current status'),\r\n completion: z.number().optional().describe('Completion percentage 0-100'),\r\n }).optional().describe('Progress tracking for task/feature observations'),\r\n relatedCommits: z.array(z.string()).optional().describe('Git commit hashes this memory relates to (links ground truth ↔ reasoning)'),\r\n relatedEntities: z.array(z.string()).optional().describe('Other entity names this memory cross-references'),\r\n },\r\n },\r\n async ({ entityName: rawEntityName, type: rawType, title: rawTitle, narrative, facts, filesModified, concepts, topicKey, progress, relatedCommits, relatedEntities }) => {\r\n const unresolved = requireResolvedProject('store memory in the current project');\r\n if (unresolved) return unresolved;\r\n return withFreshIndex(async () => {\r\n\r\n // Mutable copies — Formation Pipeline may improve these\r\n let entityName = rawEntityName;\r\n let type = rawType;\r\n let title = rawTitle;\r\n // Defensive coercion: Claude Code CLI + GLM may send string-encoded arrays\r\n let safeFacts = facts ? coerceStringArray(facts) : undefined;\r\n const safeFiles = filesModified ? coerceStringArray(filesModified) : undefined;\r\n const safeConcepts = concepts ? coerceStringArray(concepts) : undefined;\r\n\r\n // ── Determine decision maker based on Formation mode ─────────────\r\n // Priority: env var override > config.json > default (active)\r\n // - shadow: Formation observes only, old compact decides\r\n // - active: Formation decides storage behavior (new/merge/evolve/discard) [default]\r\n // - fallback: old compact decides (safe rollback)\r\n let formationMode: 'shadow' | 'active' | 'fallback' = 'active';\r\n if (process.env.MEMORIX_FORMATION_MODE) {\r\n formationMode = process.env.MEMORIX_FORMATION_MODE as typeof formationMode;\r\n } else {\r\n try {\r\n const { getBehaviorConfig } = await import('./config/behavior.js');\r\n formationMode = getBehaviorConfig().formationMode;\r\n } catch { /* default to active */ }\r\n }\r\n const useFormation = formationMode === 'active';\r\n\r\n // ── Formation Pipeline (active mode: decides storage) ─────────────\r\n let formationResult: FormedMemory | null = null;\r\n let formationNote = '';\r\n if (useFormation && !topicKey && !progress) {\r\n let currentFormationStage: FormationStage | 'setup' = 'setup';\r\n const completedFormationStages: Partial<Record<FormationStage, number>> = {};\r\n const formationStartTime = Date.now();\r\n const onFormationStageEvent = (event: FormationStageEvent): void => {\r\n if (event.status === 'start') {\r\n currentFormationStage = event.stage;\r\n return;\r\n }\r\n currentFormationStage = event.stage;\r\n if (event.stageDurationMs !== undefined) {\r\n completedFormationStages[event.stage] = event.stageDurationMs;\r\n }\r\n };\r\n try {\r\n const formationConfig: FormationConfig = {\r\n mode: 'active',\r\n useLLM: isLLMEnabled(),\r\n minValueScore: 0.3,\r\n searchMemories: async (q: string, limit: number, pid: string): Promise<SearchHit[]> => {\r\n const result = await compactSearch({ query: q, limit, projectId: pid, status: 'active' });\r\n if (result.entries.length === 0) return [];\r\n const details = await compactDetail(result.entries.map(e => e.id));\r\n return details.documents.map((d, i) => ({\r\n id: Number(d.id.replace('obs-', '')),\r\n observationId: d.observationId,\r\n title: d.title,\r\n narrative: d.narrative,\r\n facts: d.facts,\r\n entityName: d.entityName,\r\n type: d.type,\r\n score: result.entries[i]?.score ?? 0,\r\n }));\r\n },\r\n getObservation: (id: number) => {\r\n const o = getObservation(id);\r\n if (!o) return null;\r\n return {\r\n id: o.id,\r\n entityName: o.entityName,\r\n type: o.type,\r\n title: o.title,\r\n narrative: o.narrative,\r\n facts: o.facts,\r\n topicKey: o.topicKey,\r\n };\r\n },\r\n getEntityNames: () => graphManager.getEntityNames(),\r\n onStageEvent: onFormationStageEvent,\r\n };\r\n\r\n formationResult = await withTimeout(\r\n runFormation({\r\n entityName,\r\n type: type as ObservationType,\r\n title,\r\n narrative,\r\n facts: safeFacts,\r\n projectId: project.id,\r\n source: 'explicit',\r\n }, formationConfig),\r\n FORMATION_TIMEOUT_MS,\r\n 'Formation pipeline',\r\n );\r\n\r\n const modeIcon = '[FAST]';\r\n formationNote = `\\n${modeIcon} Formation[active]: ${formationResult.evaluation.category} (${formationResult.evaluation.score.toFixed(2)}) | ${formationResult.resolution.action} | ${formationResult.pipeline.durationMs}ms`;\r\n if (formationResult.extraction.extractedFacts.length > 0) {\r\n formationNote += ` | +${formationResult.extraction.extractedFacts.length} facts`;\r\n }\r\n if (formationResult.extraction.titleImproved) formationNote += ' | title↑';\r\n if (formationResult.extraction.entityResolved) formationNote += ` | entity→${formationResult.entityName}`;\r\n if (formationResult.extraction.typeCorrected) formationNote += ` | type→${formationResult.type}`;\r\n } catch (formationErr) {\r\n // Formation timeout or failure → fall through to store without enrichment\r\n const isTimeout = formationErr instanceof Error && formationErr.message.includes('timed out');\r\n const elapsedMs = Date.now() - formationStartTime;\r\n const stageSummary = formatFormationStageDurations(completedFormationStages);\r\n console.error(\r\n `[memorix] Formation ${isTimeout ? 'timed out' : 'failed'} in memorix_store after ${elapsedMs}ms/${FORMATION_TIMEOUT_MS}ms at stage ${currentFormationStage}${stageSummary ? ` | completed: ${stageSummary}` : ''}`,\r\n );\r\n if (!isTimeout && formationErr instanceof Error) {\r\n console.error(`[memorix] Formation error: ${formationErr.message}`);\r\n }\r\n formationNote = `\\n[WARN] Formation ${isTimeout ? 'timed out' : 'failed'} — storing base observation without enrichment`;\r\n }\r\n }\r\n\r\n // ── Apply Formation decision (active mode only) ───────────────────\r\n if (useFormation && formationResult && formationResult.resolution.action !== 'new') {\r\n const { action, targetId, reason } = formationResult.resolution;\r\n\r\n if (action === 'merge' && targetId) {\r\n // Merge into existing observation\r\n const targetObs = getObservation(targetId);\r\n if (targetObs) {\r\n markInternalWrite();\r\n await storeObservation({\r\n entityName: targetObs.entityName,\r\n type: targetObs.type,\r\n title: formationResult.title,\r\n narrative: formationResult.narrative,\r\n facts: formationResult.facts,\r\n filesModified: safeFiles,\r\n concepts: safeConcepts,\r\n projectId: project.id,\r\n topicKey: targetObs.topicKey,\r\n progress: progress as import('./types.js').ProgressInfo | undefined,\r\n sourceDetail: 'explicit',\r\n createdByAgentId: currentAgentId,\r\n });\r\n return {\r\n content: [{\r\n type: 'text' as const,\r\n text: `[UPDATED] Formation MERGE: merged into #${targetId} (${reason})${formationNote}`,\r\n }],\r\n };\r\n }\r\n } else if (action === 'evolve' && targetId) {\r\n // Evolve existing observation\r\n const targetObs = getObservation(targetId);\r\n if (targetObs) {\r\n markInternalWrite();\r\n await storeObservation({\r\n entityName: targetObs.entityName,\r\n type: targetObs.type,\r\n title: formationResult.title,\r\n narrative: formationResult.narrative,\r\n facts: formationResult.facts,\r\n filesModified: safeFiles,\r\n concepts: safeConcepts,\r\n projectId: project.id,\r\n topicKey: targetObs.topicKey,\r\n progress: progress as import('./types.js').ProgressInfo | undefined,\r\n sourceDetail: 'explicit',\r\n createdByAgentId: currentAgentId,\r\n });\r\n return {\r\n content: [{\r\n type: 'text' as const,\r\n text: `[UPDATED] Formation EVOLVE: evolved #${targetId} (${reason})${formationNote}`,\r\n }],\r\n };\r\n }\r\n } else if (action === 'discard') {\r\n // Skip storing entirely\r\n return {\r\n content: [{\r\n type: 'text' as const,\r\n text: `[SKIP] Formation DISCARD: ${reason}${formationNote}`,\r\n }],\r\n };\r\n }\r\n }\r\n\r\n // ── Compact on Write (fallback mode or Formation said 'new') ───────\r\n // Search for similar existing memories BEFORE storing.\r\n // If compact says UPDATE → merge into existing; NONE → skip storing.\r\n // This keeps memory count low and prevents duplication (Mem0-style).\r\n let compactAction = '';\r\n let compactMerged = false;\r\n if (!useFormation && !topicKey && !progress) {\r\n try {\r\n const searchResult = await compactSearch({\r\n query: `${title} ${narrative.substring(0, 200)}`,\r\n limit: 5,\r\n projectId: project.id,\r\n status: 'active',\r\n });\r\n const similarEntries = searchResult.entries.map(e => e);\r\n if (similarEntries.length > 0) {\r\n // Fetch full details for comparison\r\n const similarIds = similarEntries.map(e => e.id);\r\n const details = await compactDetail(similarIds);\r\n const existingMemories: ExistingMemory[] = details.documents.map((d, i) => ({\r\n id: d.observationId,\r\n title: d.title,\r\n narrative: d.narrative,\r\n facts: d.facts,\r\n score: similarEntries[i]?.score ?? 0,\r\n }));\r\n\r\n const decision = await withTimeout(\r\n compactOnWrite(\r\n { title, narrative, facts: safeFacts ?? [] },\r\n existingMemories,\r\n ),\r\n COMPACT_ON_WRITE_TIMEOUT_MS,\r\n 'Compact-on-write',\r\n );\r\n\r\n if (decision.action === 'UPDATE' && decision.targetId) {\r\n // Merge into existing memory (Mem0-style UPDATE)\r\n const targetObs = getObservation(decision.targetId);\r\n if (targetObs) {\r\n markInternalWrite();\r\n await storeObservation({\r\n entityName: targetObs.entityName,\r\n type: targetObs.type,\r\n title: decision.mergedNarrative ? title : targetObs.title,\r\n narrative: decision.mergedNarrative ?? narrative,\r\n facts: decision.mergedFacts ?? safeFacts,\r\n filesModified: safeFiles,\r\n concepts: safeConcepts,\r\n projectId: project.id,\r\n topicKey: targetObs.topicKey,\r\n progress: progress as import('./types.js').ProgressInfo | undefined,\r\n sourceDetail: 'explicit',\r\n createdByAgentId: currentAgentId,\r\n });\r\n compactAction = `[UPDATED] Compact UPDATE: merged into #${decision.targetId} (${decision.reason})`;\r\n compactMerged = true;\r\n\r\n // Return early — we updated existing, no new observation needed\r\n return {\r\n content: [{\r\n type: 'text' as const,\r\n text: `${compactAction}\\nMode: ${decision.usedLLM ? 'LLM' : 'heuristic'}`,\r\n }],\r\n };\r\n }\r\n } else if (decision.action === 'NONE') {\r\n // Memory is redundant — skip storing entirely\r\n return {\r\n content: [{\r\n type: 'text' as const,\r\n text: `[SKIP] Compact SKIP: ${decision.reason}\\nExisting memory #${decision.targetId} already covers this.\\nMode: ${decision.usedLLM ? 'LLM' : 'heuristic'}`,\r\n }],\r\n };\r\n } else if (decision.action === 'DELETE' && decision.targetId) {\r\n // Old memory is outdated — resolve it, then ADD the new one\r\n const { resolveObservations } = await import('./memory/observations.js');\r\n await resolveObservations([decision.targetId], 'resolved');\r\n compactAction = ` | Compact: resolved outdated #${decision.targetId}`;\r\n }\r\n // decision.action === 'ADD' or DELETE fallthrough → proceed to store normally\r\n if (decision.enrichedFacts && decision.enrichedFacts.length > 0) {\r\n // LLM extracted additional facts — merge them in\r\n const currentFacts = safeFacts ?? [];\r\n const newFacts = decision.enrichedFacts.filter((f: string) => !currentFacts.includes(f));\r\n if (newFacts.length > 0) {\r\n compactAction += ` | +${newFacts.length} LLM-extracted facts`;\r\n }\r\n }\r\n }\r\n } catch { /* compact is best-effort */ }\r\n }\r\n\r\n // ── Apply Formation enrichments for 'new' action ─────────────────\r\n // When Formation decided 'new', merge LLM-extracted facts into the store.\r\n if (formationResult && formationResult.resolution.action === 'new') {\r\n const llmFacts = formationResult.extraction.extractedFacts;\r\n if (llmFacts.length > 0) {\r\n const currentFacts = safeFacts ?? [];\r\n const currentLower = new Set(currentFacts.map(f => f.toLowerCase().trim()));\r\n const newFacts = llmFacts.filter(f => !currentLower.has(f.toLowerCase().trim()));\r\n if (newFacts.length > 0) {\r\n safeFacts = [...currentFacts, ...newFacts];\r\n }\r\n }\r\n if (formationResult.extraction.titleImproved && formationResult.title) {\r\n title = formationResult.title;\r\n }\r\n if (formationResult.extraction.typeCorrected && formationResult.type) {\r\n type = formationResult.type;\r\n }\r\n if (formationResult.extraction.entityResolved && formationResult.entityName) {\r\n entityName = formationResult.entityName;\r\n }\r\n }\r\n\r\n // ── Standard store flow ─────────────────────────────────────────\r\n // Ensure entity exists in knowledge graph\r\n await graphManager.createEntities([\r\n { name: entityName, entityType: 'auto', observations: [] },\r\n ]);\r\n\r\n // Auto-associate sessionId from active session\r\n let sessionId: string | undefined;\r\n try {\r\n const { getActiveSession } = await import('./memory/session.js');\r\n const active = await getActiveSession(projectDir, project.id);\r\n if (active) sessionId = active.id;\r\n } catch { /* session module not critical */ }\r\n\r\n // ── LLM Narrative Compression (premium quality) ─────────────────\r\n // Compress verbose narratives into concise core knowledge before storing.\r\n // Reduces token consumption ~60% while preserving all technical facts.\r\n let finalNarrative = narrative;\r\n let compressionNote = '';\r\n try {\r\n const { compressNarrative } = await import('./llm/quality.js');\r\n const { compressed, saved, usedLLM } = await withTimeout(\r\n compressNarrative(narrative, safeFacts, type),\r\n COMPRESSION_TIMEOUT_MS,\r\n 'Narrative compression',\r\n );\r\n if (usedLLM && saved > 0) {\r\n finalNarrative = compressed;\r\n compressionNote = ` | compressed -${saved} tokens`;\r\n }\r\n } catch { /* compression is best-effort (timeout or LLM failure) */ }\r\n\r\n // ── Attribution guard (passive, non-blocking) ─────────────────\r\n // Warns when entityName is unknown in this project but well-established\r\n // in a different project — signals a potential wrong-bucket write.\r\n let attributionWarning = '';\r\n try {\r\n const attrCheck = await checkProjectAttribution(entityName, project.id, getAllObservations());\r\n if (attrCheck.suspicious) {\r\n attributionWarning = `\\n[WARN] Attribution notice: entity \"${entityName}\" has 0 observations in ` +\r\n `\"${project.id}\" but ${attrCheck.count} in \"${attrCheck.knownIn}\" ` +\r\n `(confidence: ${attrCheck.confidence}). Verify the correct project is bound before storing.`;\r\n }\r\n } catch { /* guard is best-effort — never blocks the write */ }\r\n\r\n // Store the observation (may upsert if topicKey matches existing)\r\n markInternalWrite();\r\n const { observation: obs, upserted } = await storeObservation({\r\n entityName,\r\n type: type as ObservationType,\r\n title,\r\n narrative: finalNarrative,\r\n facts: safeFacts,\r\n filesModified: safeFiles,\r\n concepts: safeConcepts,\r\n projectId: project.id,\r\n topicKey,\r\n sessionId,\r\n progress: progress as import('./types.js').ProgressInfo | undefined,\r\n relatedCommits,\r\n relatedEntities,\r\n sourceDetail: 'explicit',\r\n valueCategory: formationResult?.evaluation.category,\r\n createdByAgentId: currentAgentId,\r\n });\r\n\r\n // Add a reference to the entity's observations\r\n await graphManager.addObservations([\r\n { entityName, contents: [`[#${obs.id}] ${title}`] },\r\n ]);\r\n\r\n // Implicit memory: auto-create relations from entity extraction\r\n const extracted = extractEntities([title, narrative, ...(safeFacts ?? [])].join(' '));\r\n const autoRelCount = await createAutoRelations(obs, extracted, graphManager);\r\n\r\n // Build enrichment summary\r\n const enrichmentParts: string[] = [];\r\n const autoFiles = obs.filesModified.filter((f: string) => !(safeFiles ?? []).includes(f));\r\n const autoConcepts = obs.concepts.filter((c: string) => !(safeConcepts ?? []).includes(c));\r\n if (autoFiles.length > 0) enrichmentParts.push(`+${autoFiles.length} files extracted`);\r\n if (autoConcepts.length > 0) enrichmentParts.push(`+${autoConcepts.length} concepts enriched`);\r\n if (autoRelCount > 0) enrichmentParts.push(`+${autoRelCount} relations auto-created`);\r\n if (obs.hasCausalLanguage) enrichmentParts.push('causal language detected');\r\n if (upserted) enrichmentParts.push(`topic upserted (rev ${obs.revisionCount ?? 1})`);\r\n const enrichment = enrichmentParts.length > 0 ? `\\nAuto-enriched: ${enrichmentParts.join(', ')}` : '';\r\n\r\n const action = upserted ? '[UPDATED] Updated' : '[OK] Stored';\r\n\r\n // ── Formation Pipeline (shadow/fallback mode: observe only) ─────\r\n // Fire-and-forget: runs after storage to collect metrics.\r\n // Never blocks the MCP response — purely for A/B comparison data.\r\n if (!useFormation && !topicKey && !progress) {\r\n const shadowFormation = async () => {\r\n let oldCompactDecision: { action: string, targetId?: number, reason?: string, durationMs?: number } | null = null;\r\n try {\r\n const compactStart = Date.now();\r\n const searchResult = await compactSearch({\r\n query: `${title} ${narrative.substring(0, 200)}`,\r\n limit: 5,\r\n projectId: project.id,\r\n status: 'active',\r\n });\r\n const similarEntries = searchResult.entries.map(e => e);\r\n if (similarEntries.length > 0) {\r\n const similarIds = similarEntries.map(e => e.id);\r\n const details = await compactDetail(similarIds);\r\n const existingMemories: ExistingMemory[] = details.documents.map((d, i) => ({\r\n id: d.observationId,\r\n title: d.title,\r\n narrative: d.narrative,\r\n facts: d.facts,\r\n score: similarEntries[i]?.score ?? 0,\r\n }));\r\n const decision = await compactOnWrite(\r\n { title, narrative, facts: safeFacts ?? [] },\r\n existingMemories,\r\n );\r\n oldCompactDecision = {\r\n action: decision.action,\r\n targetId: decision.targetId,\r\n reason: decision.reason,\r\n durationMs: Date.now() - compactStart,\r\n };\r\n }\r\n } catch { /* best-effort */ }\r\n\r\n const formationConfig: FormationConfig = {\r\n mode: formationMode,\r\n useLLM: isLLMEnabled(),\r\n minValueScore: 0.3,\r\n searchMemories: async (q: string, limit: number, pid: string): Promise<SearchHit[]> => {\r\n const result = await compactSearch({ query: q, limit, projectId: pid, status: 'active' });\r\n if (result.entries.length === 0) return [];\r\n const details = await compactDetail(result.entries.map(e => e.id));\r\n return details.documents.map((d, i) => ({\r\n id: Number(d.id.replace('obs-', '')),\r\n observationId: d.observationId,\r\n title: d.title,\r\n narrative: d.narrative,\r\n facts: d.facts,\r\n entityName: d.entityName,\r\n type: d.type,\r\n score: result.entries[i]?.score ?? 0,\r\n }));\r\n },\r\n getObservation: (id: number) => {\r\n const o = getObservation(id);\r\n if (!o) return null;\r\n return { id: o.id, entityName: o.entityName, type: o.type, title: o.title, narrative: o.narrative, facts: o.facts, topicKey: o.topicKey };\r\n },\r\n getEntityNames: () => graphManager.getEntityNames(),\r\n };\r\n\r\n const formed = await withTimeout(\r\n runFormation({ entityName, type: type as ObservationType, title, narrative, facts: safeFacts, projectId: project.id, source: 'explicit', topicKey }, formationConfig),\r\n FORMATION_TIMEOUT_MS,\r\n 'Shadow formation',\r\n );\r\n\r\n const { recordBeforeAfterMetrics } = await import('./memory/formation/index.js');\r\n if (oldCompactDecision) {\r\n recordBeforeAfterMetrics({\r\n formationAction: formed.resolution.action,\r\n formationTargetId: formed.resolution.targetId,\r\n oldCompactAction: oldCompactDecision.action as 'ADD' | 'UPDATE' | 'NONE' | 'DELETE',\r\n oldCompactTargetId: oldCompactDecision.targetId,\r\n oldCompactReason: oldCompactDecision.reason,\r\n formationValueScore: formed.evaluation.score,\r\n formationValueCategory: formed.evaluation.category,\r\n formationDurationMs: formed.pipeline.durationMs,\r\n compactDurationMs: oldCompactDecision.durationMs,\r\n });\r\n }\r\n };\r\n // Fire-and-forget — do not await\r\n shadowFormation().catch(() => {});\r\n }\r\n\r\n return {\r\n content: [\r\n {\r\n type: 'text' as const,\r\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}${formationNote}${attributionWarning}`,\r\n },\r\n ],\r\n };\r\n }); // withFreshIndex\r\n },\r\n );\r\n\r\n /**\r\n * memorix_suggest_topic_key — Suggest a stable topic key for upserts\r\n *\r\n * Use before memorix_store when you want evolving topics to upsert\r\n * into a single observation instead of creating duplicates.\r\n */\r\n server.registerTool(\r\n 'memorix_suggest_topic_key',\r\n {\r\n title: 'Suggest Topic Key',\r\n description:\r\n 'Suggest a stable topic_key for memory upserts. Use this before memorix_store when you want evolving topics ' +\r\n '(like architecture decisions, config docs) to update a single observation over time instead of creating duplicates. ' +\r\n 'Returns a key like \"architecture/auth-model\" or \"bug/timeout-in-api-gateway\".',\r\n inputSchema: {\r\n type: z.string().describe('Observation type (e.g., decision, architecture, bugfix, discovery)'),\r\n title: z.string().describe('Observation title — used to generate the stable key'),\r\n },\r\n },\r\n async ({ type: obsType, title }) => {\r\n const { suggestTopicKey } = await import('./memory/observations.js');\r\n const key = suggestTopicKey(obsType, title);\r\n\r\n if (!key) {\r\n return {\r\n content: [{ type: 'text' as const, text: 'Could not suggest topic_key from the given input. Provide a more descriptive title.' }],\r\n isError: true,\r\n };\r\n }\r\n\r\n return {\r\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.` }],\r\n };\r\n },\r\n );\r\n\r\n /**\r\n * memorix_search — Layer 1: Compact index search\r\n *\r\n * Returns a lightweight table of matching observations.\r\n * ~50-100 tokens per result. Agent scans this to decide what to fetch.\r\n */\r\n server.registerTool(\r\n 'memorix_search',\r\n {\r\n title: 'Search Memory',\r\n description:\r\n 'Search project memory. Returns a compact index (~50-100 tokens/result). ' +\r\n 'Use memorix_detail to fetch full content for specific IDs. ' +\r\n 'Use memorix_timeline to see chronological context. ' +\r\n 'Searches across all observations stored from any IDE session — enabling cross-session and cross-agent context retrieval.',\r\n inputSchema: {\r\n query: z.string().describe('Search query (natural language or keywords)'),\r\n limit: z.number().optional().describe('Max results (default: 20)'),\r\n type: z.enum(OBSERVATION_TYPES).optional().describe('Filter by observation type'),\r\n maxTokens: z.number().optional().describe('Token budget — trim results to fit (0 = unlimited)'),\r\n scope: z.enum(['project', 'global']).optional().default('project').describe(\r\n 'Search scope: \"project\" (default) only searches current project, \"global\" searches all projects',\r\n ),\r\n since: z.string().optional().describe('Only return observations created after this date (ISO 8601 or natural like \"2025-01-15\")'),\r\n until: z.string().optional().describe('Only return observations created before this date (ISO 8601 or natural like \"2025-02-01\")'),\r\n status: z.enum(['active', 'resolved', 'archived', 'all']).optional().default('active').describe(\r\n 'Filter by memory status. \"active\" (default) shows current memories, \"all\" includes resolved/archived.',\r\n ),\r\n source: z.enum(['agent', 'git', 'manual']).optional().describe(\r\n 'Filter by memory source. \"git\" returns only commit-derived ground truth memories. Omit for all sources.',\r\n ),\r\n },\r\n },\r\n async ({ query, limit, type, maxTokens, scope, since, until, status, source }) => {\r\n if (scope !== 'global') {\r\n const unresolved = requireResolvedProject('search the current project');\r\n if (unresolved) return unresolved;\r\n }\r\n return withFreshIndex(async () => {\r\n\r\n const safeLimit = limit != null ? coerceNumber(limit, 20) : undefined;\r\n const safeMaxTokens = maxTokens != null ? coerceNumber(maxTokens, 0) : undefined;\r\n\r\n // Tool-level timeout: abort if search takes longer than 30 seconds\r\n const TIMEOUT_MS = 30000;\r\n const searchPromise = compactSearch({\r\n query,\r\n limit: safeLimit,\r\n type: type as ObservationType | undefined,\r\n maxTokens: safeMaxTokens,\r\n since,\r\n until,\r\n // Default to project-scoped search to prevent cross-project pollution.\r\n // Use scope: 'global' to explicitly search all projects.\r\n projectId: scope === 'global' ? undefined : project.id,\r\n status: (status as 'active' | 'resolved' | 'archived' | 'all') ?? 'active',\r\n source: source as 'agent' | 'git' | 'manual' | undefined,\r\n });\r\n\r\n const timeoutPromise = new Promise<never>((_, reject) =>\r\n setTimeout(() => reject(new Error(`Search timeout after ${TIMEOUT_MS}ms`)), TIMEOUT_MS)\r\n );\r\n\r\n let result;\r\n try {\r\n result = await Promise.race([searchPromise, timeoutPromise]);\r\n } catch (error) {\r\n if (error instanceof Error && error.message.includes('timeout')) {\r\n // Timeout: return empty result with error message\r\n return {\r\n content: [\r\n {\r\n type: 'text' as const,\r\n text: `Error: Search timeout after ${TIMEOUT_MS}ms. Try a simpler query or check if the service is responsive.`,\r\n },\r\n ],\r\n isError: true,\r\n };\r\n }\r\n throw error;\r\n }\r\n\r\n // Append search mode and sync advisory\r\n let text = result.formatted;\r\n try {\r\n const { getLastSearchMode } = await import('./store/orama-store.js');\r\n text += `\\n\\n_Search mode: ${getLastSearchMode(project.id)}_`;\r\n } catch { /* best-effort */ }\r\n if (!syncAdvisoryShown && syncAdvisory) {\r\n text += syncAdvisory;\r\n syncAdvisoryShown = true;\r\n }\r\n\r\n return {\r\n content: [\r\n {\r\n type: 'text' as const,\r\n text,\r\n },\r\n ],\r\n };\r\n }); // withFreshIndex\r\n },\r\n );\r\n\r\n /**\r\n * memorix_resolve — Mark memories as resolved/completed\r\n *\r\n * Prevents resolved memories from polluting future searches.\r\n * Default search only returns 'active' memories.\r\n */\r\n server.registerTool(\r\n 'memorix_resolve',\r\n {\r\n title: 'Resolve Memories',\r\n description:\r\n 'Mark observations as resolved (completed/no longer active). ' +\r\n 'Resolved memories are hidden from default search but can still be found with status=\"all\". ' +\r\n 'Use this to mark completed tasks, fixed bugs, or outdated information so they don\\'t pollute future context.',\r\n inputSchema: {\r\n ids: z.array(z.number()).describe('Observation IDs to mark as resolved'),\r\n status: z.enum(['resolved', 'archived']).optional().default('resolved').describe(\r\n 'Target status: \"resolved\" (default, completed/done) or \"archived\" (permanently hidden)',\r\n ),\r\n },\r\n },\r\n async ({ ids, status }) => {\r\n const { resolveObservations } = await import('./memory/observations.js');\r\n const safeIds = (Array.isArray(ids) ? ids : [ids]).map(id => coerceNumber(id, 0)).filter(id => id > 0);\r\n const result = await resolveObservations(safeIds, (status as 'resolved' | 'archived') ?? 'resolved');\r\n\r\n const parts: string[] = [];\r\n if (result.resolved.length > 0) {\r\n parts.push(`[OK] Resolved ${result.resolved.length} observation(s): #${result.resolved.join(', #')}`);\r\n }\r\n if (result.notFound.length > 0) {\r\n parts.push(`[WARN] Not found: #${result.notFound.join(', #')}`);\r\n }\r\n parts.push('\\nResolved memories are hidden from default search. Use status=\"all\" to include them.');\r\n parts.push('[STATS] Run `memorix_retention` with `action: \"report\"` to check remaining cleanup status.');\r\n\r\n return {\r\n content: [{ type: 'text' as const, text: parts.join('\\n') }],\r\n };\r\n },\r\n );\r\n\r\n /**\r\n * memorix_store_reasoning — System 2 Reasoning Memory\r\n *\r\n * Store WHY a decision was made, what alternatives were considered,\r\n * and what the expected outcome is. This is the \"reasoning trace\" —\r\n * not just what changed, but the thought process behind it.\r\n *\r\n * Inspired by Cipher's dual-memory (Knowledge + Reflection).\r\n */\r\n server.registerTool(\r\n 'memorix_store_reasoning',\r\n {\r\n title: 'Store Reasoning Trace',\r\n description:\r\n 'Store a reasoning trace — WHY you chose this approach, what alternatives you considered, ' +\r\n 'and what outcome you expect. This creates a searchable record of your decision-making process. ' +\r\n 'Use this when making non-trivial technical decisions, choosing between approaches, or ' +\r\n 'solving complex problems. Unlike regular memories that record WHAT happened, reasoning ' +\r\n 'memories record HOW you thought about it.',\r\n inputSchema: {\r\n entityName: z.string().describe('The entity this reasoning applies to (e.g., \"auth-module\", \"database-schema\")'),\r\n decision: z.string().describe('What was decided or chosen'),\r\n alternatives: z.array(z.string()).optional().describe('Other options that were considered'),\r\n rationale: z.string().describe('Why this approach was chosen over alternatives'),\r\n constraints: z.array(z.string()).optional().describe('Constraints that influenced the decision (time, perf, compat, etc.)'),\r\n expectedOutcome: z.string().optional().describe('What outcome is expected from this decision'),\r\n risks: z.array(z.string()).optional().describe('Known risks or potential downsides'),\r\n concepts: z.array(z.string()).optional().describe('Related technical concepts'),\r\n filesModified: z.array(z.string()).optional().describe('Files related to this reasoning'),\r\n relatedCommits: z.array(z.string()).optional().describe('Git commit hashes this reasoning explains (links ground truth ↔ reasoning)'),\r\n relatedEntities: z.array(z.string()).optional().describe('Other entity names this reasoning relates to (cross-references)'),\r\n },\r\n },\r\n async ({ entityName, decision, alternatives, rationale, constraints, expectedOutcome, risks, concepts, filesModified, relatedCommits, relatedEntities }) => {\r\n const unresolved = requireResolvedProject('store reasoning in the current project');\r\n if (unresolved) return unresolved;\r\n return withFreshIndex(async () => {\r\n\r\n // Build structured narrative from reasoning fields\r\n const narrativeParts: string[] = [rationale];\r\n if (alternatives && alternatives.length > 0) {\r\n narrativeParts.push(`Alternatives considered: ${alternatives.join('; ')}`);\r\n }\r\n if (constraints && constraints.length > 0) {\r\n narrativeParts.push(`Constraints: ${constraints.join('; ')}`);\r\n }\r\n if (expectedOutcome) {\r\n narrativeParts.push(`Expected outcome: ${expectedOutcome}`);\r\n }\r\n const narrative = narrativeParts.join('. ');\r\n\r\n // Build facts from structured fields\r\n const facts: string[] = [`Decision: ${decision}`];\r\n if (alternatives) alternatives.forEach(a => facts.push(`Alternative considered: ${a}`));\r\n if (constraints) constraints.forEach(c => facts.push(`Constraint: ${c}`));\r\n if (risks) risks.forEach(r => facts.push(`Risk: ${r}`));\r\n if (expectedOutcome) facts.push(`Expected outcome: ${expectedOutcome}`);\r\n\r\n await graphManager.createEntities([\r\n { name: entityName, entityType: 'auto', observations: [] },\r\n ]);\r\n\r\n // ── Attribution guard (passive, non-blocking) ─────────────────\r\n let reasoningAttributionWarning = '';\r\n try {\r\n const attrCheck = await checkProjectAttribution(entityName, project.id, getAllObservations());\r\n if (attrCheck.suspicious) {\r\n reasoningAttributionWarning = `\\n[WARN] Attribution notice: entity \"${entityName}\" has 0 observations in ` +\r\n `\"${project.id}\" but ${attrCheck.count} in \"${attrCheck.knownIn}\" ` +\r\n `(confidence: ${attrCheck.confidence}). Verify the correct project is bound before storing.`;\r\n }\r\n } catch { /* guard is best-effort — never blocks the write */ }\r\n\r\n markInternalWrite();\r\n const { observation: obs } = await storeObservation({\r\n entityName,\r\n type: 'reasoning' as ObservationType,\r\n title: decision.length > 80 ? decision.substring(0, 77) + '...' : decision,\r\n narrative,\r\n facts,\r\n concepts: concepts ?? [],\r\n filesModified: filesModified ?? [],\r\n projectId: project.id,\r\n source: 'agent',\r\n relatedCommits,\r\n relatedEntities,\r\n sourceDetail: 'explicit',\r\n createdByAgentId: currentAgentId,\r\n });\r\n\r\n await graphManager.addObservations([\r\n { entityName, contents: [`[#${obs.id}] [REASONING] ${decision}`] },\r\n ]);\r\n\r\n return {\r\n content: [{\r\n type: 'text' as const,\r\n text: `[REASONING] Reasoning trace stored #${obs.id}: \"${decision}\"\\nEntity: ${entityName} | ${facts.length} facts | ${obs.tokens} tokens${reasoningAttributionWarning}`,\r\n }],\r\n };\r\n }); // withFreshIndex\r\n },\r\n );\r\n\r\n /**\r\n * memorix_audit_project — Scan for misattributed observations\r\n *\r\n * Read-only audit: identifies observations in the current project whose\r\n * entityName is well-known in a different project but absent here.\r\n * Use the results to decide which observations to archive with memorix_resolve.\r\n */\r\n server.registerTool(\r\n 'memorix_audit_project',\r\n {\r\n title: 'Audit Project Attribution',\r\n description:\r\n 'Scan the current project for observations that may have been written to the wrong project bucket. ' +\r\n 'Identifies observations whose entityName appears exclusively in a different project. ' +\r\n 'Read-only — no data is changed. Use memorix_resolve to archive confirmed mis-attributed observations.',\r\n inputSchema: {\r\n threshold: z.number().int().min(1).optional().describe(\r\n 'Minimum occurrences of an entityName in another project to flag it as suspicious (default: 2)',\r\n ),\r\n },\r\n },\r\n async ({ threshold }) => {\r\n const unresolved = requireResolvedProject('audit project attribution');\r\n if (unresolved) return unresolved;\r\n const minCount = threshold ?? 2;\r\n let entries: import('./memory/attribution-guard.js').AuditEntry[];\r\n try {\r\n entries = await auditProjectObservations(project.id, await withFreshIndex(() => getAllObservations()), minCount);\r\n } catch (err) {\r\n return {\r\n content: [{\r\n type: 'text' as const,\r\n text: `Audit failed: ${err instanceof Error ? err.message : String(err)}`,\r\n }],\r\n };\r\n }\r\n\r\n if (entries.length === 0) {\r\n return {\r\n content: [{\r\n type: 'text' as const,\r\n text: `[OK] No suspicious observations found in project \"${project.id}\" (threshold: ${minCount}).`,\r\n }],\r\n };\r\n }\r\n\r\n const lines: string[] = [\r\n `## Attribution Audit — ${project.id}`,\r\n `Found **${entries.length}** potentially mis-attributed observation(s) (threshold: ≥${minCount} occurrences in another project).\\n`,\r\n '| ID | Entity | Title | Source | Detail | Likely Belongs To | Count | Confidence |',\r\n '|----|--------|-------|--------|--------|-------------------|-------|------------|',\r\n ];\r\n\r\n for (const e of entries) {\r\n const titleTrunc = e.title.length > 50 ? e.title.slice(0, 47) + '...' : e.title;\r\n lines.push(\r\n `| #${e.id} | ${e.entityName} | ${titleTrunc} | ${e.source} | ${e.sourceDetail ?? '-'} | ${e.likelyBelongsTo} | ${e.count} | ${e.confidence} |`,\r\n );\r\n }\r\n\r\n // Actionable IDs block (cap display to avoid very long outputs)\r\n const auditIds = entries.map(e => e.id);\r\n const auditPreview = auditIds.slice(0, 20);\r\n const auditSummary = `[${auditPreview.join(', ')}]${auditIds.length > 20 ? ` … (${auditIds.length} total)` : ''}`;\r\n lines.push('');\r\n lines.push('### Suggested Actions');\r\n lines.push(`Suggested IDs: ${auditSummary}`);\r\n lines.push('- Archive confirmed mis-attributed observations: use `memorix_resolve` with the specific IDs above and `status: \"archived\"`.');\r\n lines.push('- Review first with `memorix_detail` if unsure.');\r\n\r\n return {\r\n content: [{ type: 'text' as const, text: lines.join('\\n') }],\r\n };\r\n },\r\n );\r\n\r\n /**\r\n * memorix_search_reasoning — Search reasoning patterns\r\n *\r\n * Find past reasoning traces to understand WHY decisions were made.\r\n * Useful when revisiting code and needing to understand the thought\r\n * process behind the current implementation.\r\n */\r\n server.registerTool(\r\n 'memorix_search_reasoning',\r\n {\r\n title: 'Search Reasoning Patterns',\r\n description:\r\n 'Search past reasoning traces to understand WHY decisions were made. ' +\r\n 'Returns reasoning memories that explain the thought process behind technical choices. ' +\r\n 'Use this when revisiting code, questioning a design decision, or looking for precedent ' +\r\n 'on how similar problems were solved before.',\r\n inputSchema: {\r\n query: z.string().describe('Search query — describe what reasoning you want to find (e.g., \"why did we choose PostgreSQL\", \"auth approach rationale\")'),\r\n limit: z.number().optional().describe('Max results (default: 10)'),\r\n scope: z.enum(['project', 'global']).optional().default('project').describe('Search scope'),\r\n },\r\n },\r\n async ({ query, limit, scope }) => {\r\n if (scope !== 'global') {\r\n const unresolved = requireResolvedProject('search reasoning in the current project');\r\n if (unresolved) return unresolved;\r\n }\r\n const safeLimit = limit != null ? coerceNumber(limit, 10) : 10;\r\n const result = await withFreshIndex(() => compactSearch({\r\n query,\r\n limit: safeLimit,\r\n type: 'reasoning' as ObservationType,\r\n projectId: scope === 'global' ? undefined : project.id,\r\n status: 'active',\r\n }));\r\n\r\n if (result.entries.length === 0) {\r\n return {\r\n content: [{ type: 'text' as const, text: 'No reasoning traces found. Use memorix_store_reasoning to record decision rationale.' }],\r\n };\r\n }\r\n\r\n return {\r\n content: [{ type: 'text' as const, text: `[REASONING] Reasoning Traces:\\n${result.formatted}` }],\r\n };\r\n },\r\n );\r\n\r\n /**\r\n * memorix_deduplicate — LLM-powered batch deduplication\r\n *\r\n * Scans active memories for duplicates/contradictions and auto-resolves them.\r\n * Requires LLM to be configured (MEMORIX_LLM_API_KEY or OPENAI_API_KEY).\r\n */\r\n server.registerTool(\r\n 'memorix_deduplicate',\r\n {\r\n title: 'Deduplicate Memories',\r\n description:\r\n 'Scan active memories for duplicates, contradictions, and outdated information using LLM analysis. ' +\r\n 'Automatically resolves redundant memories. Requires LLM to be configured ' +\r\n '(set MEMORIX_LLM_API_KEY or OPENAI_API_KEY environment variable). ' +\r\n 'Without LLM, falls back to basic similarity-based consolidation.',\r\n inputSchema: {\r\n query: z.string().optional().describe('Optional query to scope dedup to a topic (default: scan all)'),\r\n dryRun: z.boolean().optional().default(false).describe('Preview only — show what would be resolved without making changes'),\r\n },\r\n },\r\n async ({ query, dryRun }) => {\r\n const { getAllObservations, resolveObservations } = await import('./memory/observations.js');\r\n const allObs = await withFreshIndex(() => getAllObservations().filter(o => (o.status ?? 'active') === 'active' && o.projectId === project.id));\r\n\r\n if (allObs.length < 2) {\r\n return { content: [{ type: 'text' as const, text: 'Not enough active memories to deduplicate.' }] };\r\n }\r\n\r\n if (!isLLMEnabled()) {\r\n return {\r\n content: [{\r\n type: 'text' as const,\r\n text: '[WARN] LLM not configured. Set MEMORIX_LLM_API_KEY or OPENAI_API_KEY to enable intelligent dedup.\\n\\n' +\r\n 'Tip: Use memorix_consolidate for basic similarity-based merging without LLM.',\r\n }],\r\n };\r\n }\r\n\r\n // If query provided, search for relevant memories; otherwise take latest 20\r\n let candidates: typeof allObs;\r\n if (query) {\r\n const searchResult = await compactSearch({ query, limit: 20, projectId: project.id, status: 'active' });\r\n const idSet = new Set(searchResult.entries.map(e => e.id));\r\n candidates = allObs.filter(o => idSet.has(o.id));\r\n } else {\r\n candidates = allObs.slice(-20);\r\n }\r\n\r\n if (candidates.length < 2) {\r\n return { content: [{ type: 'text' as const, text: 'Not enough memories in scope to deduplicate.' }] };\r\n }\r\n\r\n // Group by entity for focused dedup\r\n const byEntity = new Map<string, typeof candidates>();\r\n for (const obs of candidates) {\r\n const list = byEntity.get(obs.entityName) ?? [];\r\n list.push(obs);\r\n byEntity.set(obs.entityName, list);\r\n }\r\n\r\n const actions: string[] = [];\r\n const toResolve: number[] = [];\r\n\r\n for (const [entity, group] of byEntity) {\r\n if (group.length < 2) continue;\r\n\r\n // Compare each pair within entity group\r\n for (let i = 0; i < group.length; i++) {\r\n for (let j = i + 1; j < group.length; j++) {\r\n const newer = group[j];\r\n const older = group[i];\r\n try {\r\n const decision = await deduplicateMemory(\r\n { title: newer.title, narrative: newer.narrative, facts: newer.facts },\r\n [{ id: older.id, title: older.title, narrative: older.narrative, facts: older.facts.join('\\n') }],\r\n );\r\n if (decision && decision.action === 'UPDATE' && decision.targetId) {\r\n actions.push(`[UPDATED] #${older.id} \"${older.title}\" → superseded by #${newer.id} (${decision.reason})${decision.usedLLM ? ' [LLM]' : ' [heuristic]'}`);\r\n toResolve.push(older.id);\r\n } else if (decision && decision.action === 'NONE') {\r\n actions.push(`[DELETE] #${newer.id} \"${newer.title}\" → redundant (${decision.reason})${decision.usedLLM ? ' [LLM]' : ' [heuristic]'}`);\r\n toResolve.push(newer.id);\r\n } else if (decision && decision.action === 'DELETE') {\r\n actions.push(`[ERROR] #${decision.targetId ?? older.id} → outdated (${decision.reason})${decision.usedLLM ? ' [LLM]' : ' [heuristic]'}`);\r\n toResolve.push(decision.targetId ?? older.id);\r\n }\r\n } catch (dedupErr) { actions.push(`[WARN] comparison failed: ${(dedupErr as Error)?.message ?? dedupErr}`); }\r\n }\r\n }\r\n }\r\n\r\n if (actions.length === 0) {\r\n return { content: [{ type: 'text' as const, text: `[OK] Scanned ${candidates.length} memories across ${byEntity.size} entities — no duplicates found.` }] };\r\n }\r\n\r\n if (dryRun) {\r\n return {\r\n content: [{\r\n type: 'text' as const,\r\n text: `[SEARCH] DRY RUN — ${actions.length} action(s) found:\\n\\n${actions.join('\\n')}\\n\\nRun with dryRun=false to apply.`,\r\n }],\r\n };\r\n }\r\n\r\n // Apply resolutions\r\n const unique = [...new Set(toResolve)];\r\n await resolveObservations(unique, 'resolved');\r\n\r\n return {\r\n content: [{\r\n type: 'text' as const,\r\n text: `[CLEANUP] Deduplicated: resolved ${unique.length} memory(ies)\\n\\n${actions.join('\\n')}`,\r\n }],\r\n };\r\n },\r\n );\r\n\r\n /**\r\n * memorix_timeline — Deep retrieval: provenance-aware chronological expansion\r\n *\r\n * Natural follow-up after session L1 routing hints (hook traces) or L3\r\n * evidence pointers (git memory). Distinguishes explicit memory evolution,\r\n * hook activity traces, and git-backed facts via Src column when available.\r\n */\r\n server.registerTool(\r\n 'memorix_timeline',\r\n {\r\n title: 'Memory Timeline',\r\n description:\r\n 'Deep retrieval: expand chronological context around a specific observation — ' +\r\n 'distinguishes explicit memory evolution, hook activity traces, and git-backed facts. ' +\r\n 'Natural follow-up after session L1 routing hints (hook traces) or L3 evidence pointers (git memory).',\r\n inputSchema: {\r\n anchorId: z.number().describe('Observation ID to center the timeline on'),\r\n depthBefore: z.number().optional().describe('Number of observations before (default: 3)'),\r\n depthAfter: z.number().optional().describe('Number of observations after (default: 3)'),\r\n },\r\n },\r\n async ({ anchorId, depthBefore, depthAfter }) => {\r\n const safeAnchor = coerceNumber(anchorId, 0);\r\n const safeBefore = depthBefore != null ? coerceNumber(depthBefore, 3) : undefined;\r\n const safeAfter = depthAfter != null ? coerceNumber(depthAfter, 3) : undefined;\r\n const result = await compactTimeline(\r\n safeAnchor,\r\n project.id,\r\n safeBefore,\r\n safeAfter,\r\n );\r\n\r\n return {\r\n content: [\r\n {\r\n type: 'text' as const,\r\n text: result.formatted,\r\n },\r\n ],\r\n };\r\n },\r\n );\r\n\r\n /**\r\n * memorix_detail — Layer 3: Provenance-aware full observation details\r\n *\r\n * Opens explicit memories, hook traces, or git evidence depending on source.\r\n * Output includes a provenance header identifying the evidence kind, value\r\n * category (core / ephemeral), and cross-references to related items.\r\n */\r\n server.registerTool(\r\n 'memorix_detail',\r\n {\r\n title: 'Memory Details',\r\n description:\r\n 'Fetch full observation or mini-skill details — includes source kind (explicit memory / hook trace / git evidence), ' +\r\n 'value category, and cross-references (~500-1000 tokens each). ' +\r\n 'Always use memorix_search first to find relevant IDs, then fetch only what you need. ' +\r\n 'Accepts typed refs from search results (e.g. \"obs:42\", \"skill:3\") via the typedRefs field, ' +\r\n 'or legacy numeric ids / object refs for backward compatibility.',\r\n inputSchema: {\r\n ids: z.array(z.number()).optional().describe('Observation IDs to fetch (legacy, from memorix_search results)'),\r\n refs: z.array(\r\n z.object({\r\n id: z.number().describe('Observation ID'),\r\n projectId: z.string().optional().describe('Project ID for global-search disambiguation'),\r\n }),\r\n ).optional().describe('Explicit observation refs. Prefer this for global search results.'),\r\n typedRefs: z.array(z.string()).optional().describe('Typed memory refs from search results, e.g. \"obs:42\", \"skill:3\", \"obs:42@org/proj\"'),\r\n },\r\n },\r\n async ({ ids, refs, typedRefs }) => {\r\n // Defensive coercion: Claude Code CLI + GLM may send \"[16]\" instead of [16]\r\n const safeIds = coerceNumberArray(ids);\r\n const safeRefs = coerceObservationRefs(refs);\r\n const safeTypedRefs = coerceStringArray(typedRefs);\r\n\r\n // Priority: typedRefs > refs > ids (each is a complete, homogeneous input path)\r\n let result;\r\n try {\r\n if (safeTypedRefs.length > 0) {\r\n // Pass typed ref strings directly — compactDetail handles parsing\r\n result = await compactDetail(safeTypedRefs);\r\n } else if (safeRefs.length > 0) {\r\n result = await compactDetail(safeRefs);\r\n } else {\r\n // Bare numeric IDs are scoped to the current project\r\n result = await compactDetail(safeIds.map(id => ({ id, projectId: project.id })));\r\n }\r\n } catch (err) {\r\n return { content: [{ type: 'text' as const, text: err instanceof Error ? err.message : String(err) }], isError: true };\r\n }\r\n\r\n return {\r\n content: [\r\n {\r\n type: 'text' as const,\r\n text: result.documents.length > 0\r\n ? result.formatted\r\n : safeTypedRefs.length > 0\r\n ? `No memories found for refs: ${safeTypedRefs.join(', ')}`\r\n : safeRefs.length > 0\r\n ? `No memories found for refs: ${safeRefs.map((ref) => `${ref.projectId ?? 'current'}#${ref.id}`).join(', ')}`\r\n : `No memories found for IDs: ${safeIds.join(', ')}`,\r\n },\r\n ],\r\n };\r\n },\r\n );\r\n\r\n // ================================================================\r\n // Memorix Retention & Decay Tools (inspired by mcp-memory-service + MemCP)\r\n // ================================================================\r\n\r\n /**\r\n * memorix_retention — Memory retention status\r\n *\r\n * Shows which observations are active, stale, or candidates for archiving.\r\n * Uses exponential decay scoring from mcp-memory-service.\r\n */\r\n server.registerTool(\r\n 'memorix_retention',\r\n {\r\n title: 'Memory Retention Status & Archive',\r\n description:\r\n 'Show memory retention status or archive expired memories. ' +\r\n 'action=\"report\" (default): show active/stale/archive-candidate counts. ' +\r\n 'action=\"archive\": move expired observations to archive file (reversible). ' +\r\n 'action=\"stale\": list stale observations with full retention explanation. ' +\r\n 'Uses exponential decay scoring based on importance, age, and access patterns.',\r\n inputSchema: {\r\n action: z.enum(['report', 'archive', 'stale']).optional().describe('Action: \"report\" (show status, default) or \"archive\" (move expired to archive) or \"stale\" (list stale observations with explanation)'),\r\n },\r\n },\r\n async (args: { action?: string }) => {\r\n const action = args.action ?? 'report';\r\n const { getRetentionSummary, getArchiveCandidates, rankByRelevance, archiveExpired, getRetentionZone, explainRetention } = await import('./memory/retention.js');\r\n const { getDb } = await import('./store/orama-store.js');\r\n const { search } = await import('@orama/orama');\r\n\r\n // Shared: build MemorixDocument[] from in-memory observations\r\n const { getAllObservations } = await import('./memory/observations.js');\r\n const allObs = await withFreshIndex(() => getAllObservations());\r\n\r\n // Pull current access metadata from the live Orama index so access-based\r\n // immunity (e.g. accessCount >= 3) still works in retention/report/archive\r\n // paths even though observations.json itself does not persist those fields.\r\n const accessMap = new Map<number, { accessCount: number; lastAccessedAt: string }>();\r\n try {\r\n const database = await getDb();\r\n const accessResults = await search(database, {\r\n term: '',\r\n limit: Math.max(1, allObs.length),\r\n });\r\n for (const hit of accessResults.hits) {\r\n const doc = hit.document as unknown as import('./types.js').MemorixDocument;\r\n accessMap.set(doc.observationId, {\r\n accessCount: doc.accessCount ?? 0,\r\n lastAccessedAt: doc.lastAccessedAt ?? '',\r\n });\r\n }\r\n } catch {\r\n // Best-effort: retention still works without access metadata, just with\r\n // less precise immunity/reporting.\r\n }\r\n\r\n // Handle archive action\r\n if (action === 'archive') {\r\n const result = await archiveExpired(projectDir, undefined, accessMap);\r\n if (result.archived === 0) {\r\n return {\r\n content: [{ type: 'text' as const, text: '[OK] No expired observations to archive. All memories are within their retention period.' }],\r\n };\r\n }\r\n return {\r\n content: [{ type: 'text' as const, text: `[ARCHIVED] Archived ${result.archived} expired observations (status set to 'archived' in-place)\\n${result.remaining} active observations remaining.\\n\\nArchived memories are hidden from default search but can be found with status: \"all\".` }],\r\n };\r\n }\r\n\r\n const docs: import('./types.js').MemorixDocument[] = allObs.map(obs => ({\r\n id: `obs-${obs.id}`,\r\n observationId: obs.id,\r\n entityName: obs.entityName,\r\n type: obs.type,\r\n title: obs.title,\r\n narrative: obs.narrative,\r\n facts: obs.facts.join('\\n'),\r\n filesModified: obs.filesModified.join('\\n'),\r\n concepts: obs.concepts.join(', '),\r\n tokens: obs.tokens,\r\n createdAt: obs.createdAt,\r\n projectId: obs.projectId,\r\n accessCount: accessMap.get(obs.id)?.accessCount ?? 0,\r\n lastAccessedAt: accessMap.get(obs.id)?.lastAccessedAt ?? '',\r\n status: obs.status ?? 'active',\r\n source: obs.source ?? 'agent',\r\n sourceDetail: obs.sourceDetail ?? '',\r\n valueCategory: obs.valueCategory ?? '',\r\n }));\r\n\r\n if (docs.length === 0) {\r\n return {\r\n content: [{ type: 'text' as const, text: 'No observations found for this project.' }],\r\n };\r\n }\r\n\r\n // ── action=\"stale\": full table of stale observations with explanation ──\r\n if (action === 'stale') {\r\n const staleDocs = docs.filter(d => getRetentionZone(d) === 'stale');\r\n if (staleDocs.length === 0) {\r\n return {\r\n content: [{ type: 'text' as const, text: '[OK] No stale observations. All active memories are within 50% of their retention period.' }],\r\n };\r\n }\r\n const staleLines: string[] = [\r\n `## Stale Observations (${staleDocs.length})`,\r\n '',\r\n '| ID | Entity | Title | Age | Source | Retention | Why |',\r\n '|----|--------|-------|-----|--------|-----------|-----|',\r\n ];\r\n for (const d of staleDocs) {\r\n const exp = explainRetention(d);\r\n const src = d.sourceDetail || '—';\r\n const vc = d.valueCategory || '—';\r\n staleLines.push(\r\n `| ${d.observationId} | ${d.entityName} | ${d.title} | ${exp.ageDays}d | ${src} (${vc}) | ${exp.effectiveRetentionDays}d | ${exp.summary} |`,\r\n );\r\n }\r\n staleLines.push('');\r\n staleLines.push('> [TIP] Stale = past 50% of effective retention. Review or access to keep; otherwise will become archive candidates.');\r\n\r\n // Actionable IDs block\r\n const staleIds = staleDocs.map(d => d.observationId);\r\n staleLines.push('');\r\n staleLines.push('### Suggested Actions');\r\n staleLines.push(`Suggested IDs: [${staleIds.join(', ')}]`);\r\n staleLines.push(`- Archive stale observations: \\`memorix_resolve\\` with \\`ids: [${staleIds.join(', ')}]\\` and \\`status: \"archived\"\\``);\r\n staleLines.push('- Or review individually with `memorix_detail` before deciding.');\r\n\r\n return {\r\n content: [{ type: 'text' as const, text: staleLines.join('\\n') }],\r\n };\r\n }\r\n\r\n // ── action=\"report\" (default): concise summary ──\r\n const summary = getRetentionSummary(docs);\r\n const candidates = getArchiveCandidates(docs);\r\n const ranked = rankByRelevance(docs);\r\n\r\n // Source breakdown\r\n const srcCounts = new Map<string, number>();\r\n for (const d of docs) {\r\n const key = d.sourceDetail || '(undefined)';\r\n srcCounts.set(key, (srcCounts.get(key) ?? 0) + 1);\r\n }\r\n\r\n const lines: string[] = [\r\n `## Memory Retention Status`,\r\n ``,\r\n `| Zone | Count |`,\r\n `|------|-------|`,\r\n `| Active | ${summary.active} |`,\r\n `| Stale | ${summary.stale} |`,\r\n `| Archive Candidates | ${summary.archiveCandidates} |`,\r\n `| Immune | ${summary.immune} |`,\r\n `| **Total** | **${docs.length}** |`,\r\n ``,\r\n `### Source Breakdown`,\r\n `| Source | Count |`,\r\n `|--------|-------|`,\r\n ];\r\n for (const [src, count] of [...srcCounts.entries()].sort((a, b) => b[1] - a[1])) {\r\n lines.push(`| ${src} | ${count} |`);\r\n }\r\n lines.push('');\r\n\r\n if (candidates.length > 0) {\r\n lines.push(`### Archive Candidates (${candidates.length})`);\r\n lines.push(`| ID | Title | Age | Retention | Why |`);\r\n lines.push(`|----|-------|-----|-----------|-----|`);\r\n for (const c of candidates.slice(0, 10)) {\r\n const exp = explainRetention(c);\r\n lines.push(`| ${c.observationId} | ${c.title} | ${exp.ageDays}d | ${exp.effectiveRetentionDays}d | ${exp.summary} |`);\r\n }\r\n if (candidates.length > 10) {\r\n lines.push(`| … | *(${candidates.length - 10} more)* | | | |`);\r\n }\r\n const candidateIds = candidates.map(c => c.observationId);\r\n lines.push('');\r\n lines.push(`Candidate IDs: [${candidateIds.slice(0, 20).join(', ')}]${candidateIds.length > 20 ? ` … (${candidateIds.length} total)` : ''}`);\r\n lines.push(`> [TIP] Use \\`memorix_retention\\` with \\`action: \"archive\"\\` to move all, or \\`memorix_resolve\\` with specific IDs.`);\r\n lines.push('');\r\n }\r\n\r\n if (summary.stale > 0) {\r\n lines.push(`> [TASK] ${summary.stale} stale observation(s) — use \\`memorix_retention\\` with \\`action: \"stale\"\\` for full details.`);\r\n lines.push('');\r\n }\r\n\r\n // Top 5 most relevant\r\n lines.push(`### Top 5 Most Relevant`);\r\n lines.push(`| ID | Title | Score | Decay | Access Boost |`);\r\n lines.push(`|----|-------|-------|-------|-------------|`);\r\n for (const r of ranked.slice(0, 5)) {\r\n const doc = docs.find((d) => d.observationId === r.observationId);\r\n lines.push(\r\n `| ${r.observationId} | ${doc?.title ?? '?'} | ${r.totalScore.toFixed(3)} | ${r.decayFactor.toFixed(3)} | ${r.accessBoost.toFixed(1)}× |`,\r\n );\r\n }\r\n\r\n return {\r\n content: [{ type: 'text' as const, text: lines.join('\\n') }],\r\n };\r\n },\r\n );\r\n\r\n /**\r\n * memorix_formation_metrics — Formation Pipeline shadow mode metrics\r\n *\r\n * Shows aggregated metrics from the Memory Formation Pipeline running\r\n * in shadow mode. Useful for evaluating pipeline quality before\r\n * switching from shadow to active mode.\r\n */\r\n server.registerTool(\r\n 'memorix_formation_metrics',\r\n {\r\n title: 'Formation Pipeline Metrics',\r\n description:\r\n 'Show aggregated metrics from recent Memory Formation Pipeline runs. ' +\r\n 'Reports value scores, resolution actions, fact extraction rates, and processing times.',\r\n inputSchema: {},\r\n },\r\n async () => {\r\n const summary = getMetricsSummary();\r\n const beforeAfter = getBeforeAfterMetrics();\r\n\r\n if (summary.total === 0) {\r\n return {\r\n content: [{\r\n type: 'text' as const,\r\n text: '[STATS] Formation Pipeline: No metrics collected yet.\\nStore some observations to start collecting runtime data.',\r\n }],\r\n };\r\n }\r\n\r\n const lines: string[] = [\r\n '[STATS] **Formation Pipeline Metrics**',\r\n '',\r\n `**Total observations processed:** ${summary.total}`,\r\n `**Average value score:** ${summary.avgValueScore.toFixed(3)}`,\r\n `**Average processing time:** ${summary.avgDurationMs.toFixed(1)}ms`,\r\n '',\r\n '### Quality Indicators',\r\n `- **Avg system-extracted facts:** ${summary.avgExtractedFacts.toFixed(1)} per observation`,\r\n `- **Title improved rate:** ${(summary.titleImprovedRate * 100).toFixed(1)}%`,\r\n `- **Entity resolved rate:** ${(summary.entityResolvedRate * 100).toFixed(1)}%`,\r\n `- **Type corrected rate:** ${(summary.typeCorectedRate * 100).toFixed(1)}%`,\r\n '',\r\n '### Value Categories',\r\n ];\r\n\r\n for (const [cat, count] of Object.entries(summary.categoryBreakdown)) {\r\n const pct = ((count / summary.total) * 100).toFixed(1);\r\n const icon = cat === 'core' ? '[CHANGE]' : cat === 'contextual' ? '[FIX]' : '[GOTCHA]';\r\n lines.push(`- ${icon} **${cat}:** ${count} (${pct}%)`);\r\n }\r\n\r\n lines.push('', '### Resolution Actions');\r\n for (const [action, count] of Object.entries(summary.resolutionBreakdown)) {\r\n const pct = ((count / summary.total) * 100).toFixed(1);\r\n lines.push(`- **${action}:** ${count} (${pct}%)`);\r\n }\r\n\r\n // ── Before/After Comparison Metrics ─────────────────────────\r\n if (beforeAfter.totalProcessed > 0) {\r\n lines.push(\r\n '',\r\n '### Before/After Comparison (Formation vs Old Compact)',\r\n `**Total comparisons:** ${beforeAfter.totalProcessed}`,\r\n `**Agreements:** ${beforeAfter.agreements} (${((beforeAfter.agreements / beforeAfter.totalProcessed) * 100).toFixed(1)}%)`,\r\n `**Disagreements:** ${beforeAfter.disagreements} (${((beforeAfter.disagreements / beforeAfter.totalProcessed) * 100).toFixed(1)}%)`,\r\n '',\r\n '### Disagreement Breakdown',\r\n `- Formation discarded, Compact added: ${beforeAfter.disagreementBreakdown.formationDiscardedCompactAdded}`,\r\n `- Formation merged, Compact added: ${beforeAfter.disagreementBreakdown.formationMergedCompactAdded}`,\r\n `- Formation added, Compact discarded: ${beforeAfter.disagreementBreakdown.formationAddedCompactDiscarded}`,\r\n '- Formation added, Compact merged: ' + beforeAfter.disagreementBreakdown.formationAddedCompactMerged,\r\n '- Formation evolved, Compact added: ' + beforeAfter.disagreementBreakdown.formationEvolvedCompactAdded,\r\n '- Other: ' + beforeAfter.disagreementBreakdown.other,\r\n '',\r\n '### Quality Improvements',\r\n `- Formation discarded low-value: ${beforeAfter.quality.formationDiscardedLowValue}`,\r\n `- Formation merged duplicates: ${beforeAfter.quality.formationMergedDuplicates}`,\r\n `- Formation evolved outdated: ${beforeAfter.quality.formationEvolvedOutdated}`,\r\n `- Compact missed duplicates: ${beforeAfter.quality.compactMissedDuplicates}`,\r\n `- Compact kept low-value: ${beforeAfter.quality.compactKeptLowValue}`,\r\n '',\r\n `### Duration Comparison`,\r\n `- Formation avg: ${beforeAfter.duration.formationAvgMs.toFixed(1)}ms`,\r\n `- Compact avg: ${beforeAfter.duration.compactAvgMs.toFixed(1)}ms`,\r\n `- Diff: ${beforeAfter.duration.diffMs.toFixed(1)}ms`,\r\n );\r\n }\r\n\r\n return {\r\n content: [{ type: 'text' as const, text: lines.join('\\n') }],\r\n };\r\n },\r\n );\r\n\r\n // ================================================================\r\n // MCP Official Memory Server Compatible Tools (optional — 9 tools)\r\n // Enable via ~/.memorix/settings.json { \"knowledgeGraph\": true }\r\n // ================================================================\r\n\r\n let enableKG = isToolInProfile('create_entities', toolProfile);\r\n try {\r\n const { homedir } = await import('node:os');\r\n const { join } = await import('node:path');\r\n const { readFile } = await import('node:fs/promises');\r\n const raw = await readFile(join(homedir(), '.memorix', 'settings.json'), 'utf-8');\r\n const s = JSON.parse(raw);\r\n if (s.knowledgeGraph === true) enableKG = true;\r\n } catch { /* no settings or parse error — default off */ }\r\n\r\n if (enableKG) {\r\n\r\n /** create_entities — MCP Official compatible */\r\n server.registerTool(\r\n 'create_entities',\r\n {\r\n title: 'Create Entities',\r\n description: 'Create multiple new entities in the knowledge graph',\r\n inputSchema: {\r\n entities: z.array(z.object({\r\n name: z.string().describe('The name of the entity'),\r\n entityType: z.string().describe('The type of the entity'),\r\n observations: z.array(z.string()).describe('Initial observations'),\r\n })),\r\n },\r\n },\r\n async ({ entities }) => {\r\n const unresolved = requireResolvedProject('create entities in the knowledge graph');\r\n if (unresolved) return unresolved;\r\n const safeEntities = coerceObjectArray<{ name: string; entityType: string; observations: string[] }>(entities);\r\n const result = await graphManager.createEntities(safeEntities);\r\n return {\r\n content: [{ type: 'text' as const, text: JSON.stringify(result, null, 2) }],\r\n };\r\n },\r\n );\r\n\r\n /** create_relations — MCP Official compatible, enhanced with typed relation suggestions */\r\n server.registerTool(\r\n 'create_relations',\r\n {\r\n title: 'Create Relations',\r\n description:\r\n 'Create multiple new relations between entities in the knowledge graph. Relations should be in active voice. ' +\r\n 'Recommended relation types (from mcp-memory-service): causes, fixes, supports, opposes, contradicts, ' +\r\n 'depends_on, implements, extends, replaces, documents',\r\n inputSchema: {\r\n relations: z.array(z.object({\r\n from: z.string().describe('Source entity name'),\r\n to: z.string().describe('Target entity name'),\r\n relationType: z.string().describe('Type of relation (e.g., causes, fixes, supports, depends_on, implements)'),\r\n })),\r\n },\r\n },\r\n async ({ relations }) => {\r\n const unresolved = requireResolvedProject('create relations in the knowledge graph');\r\n if (unresolved) return unresolved;\r\n const safeRelations = coerceObjectArray<{ from: string; to: string; relationType: string }>(relations);\r\n const result = await graphManager.createRelations(safeRelations);\r\n return {\r\n content: [{ type: 'text' as const, text: JSON.stringify(result, null, 2) }],\r\n };\r\n },\r\n );\r\n\r\n /** add_observations — MCP Official compatible */\r\n server.registerTool(\r\n 'add_observations',\r\n {\r\n title: 'Add Observations',\r\n description: 'Add new observations to existing entities in the knowledge graph',\r\n inputSchema: {\r\n observations: z.array(z.object({\r\n entityName: z.string().describe('Entity name to add observations to'),\r\n contents: z.array(z.string()).describe('Observation contents to add'),\r\n })),\r\n },\r\n },\r\n async ({ observations }) => {\r\n const unresolved = requireResolvedProject('add observations to the knowledge graph');\r\n if (unresolved) return unresolved;\r\n const safeObs = coerceObjectArray<{ entityName: string; contents: string[] }>(observations);\r\n const result = await graphManager.addObservations(safeObs);\r\n return {\r\n content: [{ type: 'text' as const, text: JSON.stringify(result, null, 2) }],\r\n };\r\n },\r\n );\r\n\r\n /** delete_entities — MCP Official compatible */\r\n server.registerTool(\r\n 'delete_entities',\r\n {\r\n title: 'Delete Entities',\r\n description: 'Delete multiple entities and their associated relations from the knowledge graph',\r\n inputSchema: {\r\n entityNames: z.array(z.string()).describe('Entity names to delete'),\r\n },\r\n },\r\n async ({ entityNames }) => {\r\n const unresolved = requireResolvedProject('delete entities from the knowledge graph');\r\n if (unresolved) return unresolved;\r\n const safeNames = coerceStringArray(entityNames);\r\n await graphManager.deleteEntities(safeNames);\r\n return {\r\n content: [{ type: 'text' as const, text: 'Entities deleted successfully' }],\r\n };\r\n },\r\n );\r\n\r\n /** delete_observations — MCP Official compatible */\r\n server.registerTool(\r\n 'delete_observations',\r\n {\r\n title: 'Delete Observations',\r\n description: 'Delete specific observations from entities in the knowledge graph',\r\n inputSchema: {\r\n deletions: z.array(z.object({\r\n entityName: z.string().describe('Entity containing the observations'),\r\n observations: z.array(z.string()).describe('Observations to delete'),\r\n })),\r\n },\r\n },\r\n async ({ deletions }) => {\r\n const unresolved = requireResolvedProject('delete observations from the knowledge graph');\r\n if (unresolved) return unresolved;\r\n const safeDeletions = coerceObjectArray<{ entityName: string; observations: string[] }>(deletions);\r\n await graphManager.deleteObservations(safeDeletions);\r\n return {\r\n content: [{ type: 'text' as const, text: 'Observations deleted successfully' }],\r\n };\r\n },\r\n );\r\n\r\n /** delete_relations — MCP Official compatible */\r\n server.registerTool(\r\n 'delete_relations',\r\n {\r\n title: 'Delete Relations',\r\n description: 'Delete multiple relations from the knowledge graph',\r\n inputSchema: {\r\n relations: z.array(z.object({\r\n from: z.string(),\r\n to: z.string(),\r\n relationType: z.string(),\r\n })),\r\n },\r\n },\r\n async ({ relations }) => {\r\n const unresolved = requireResolvedProject('delete relations from the knowledge graph');\r\n if (unresolved) return unresolved;\r\n const safeRelations = coerceObjectArray<{ from: string; to: string; relationType: string }>(relations);\r\n await graphManager.deleteRelations(safeRelations);\r\n return {\r\n content: [{ type: 'text' as const, text: 'Relations deleted successfully' }],\r\n };\r\n },\r\n );\r\n\r\n /** Filter a KnowledgeGraph to only entities referenced by the current project's observations */\r\n async function scopeGraphToProject(graph: { entities: any[]; relations: any[] }) {\r\n const { getAllObservations } = await import('./memory/observations.js');\r\n const allObs = await withFreshIndex(() => getAllObservations());\r\n const projectEntityNames = new Set(\r\n allObs\r\n .filter(o => o.projectId === project.id && (o.status ?? 'active') === 'active' && o.entityName)\r\n .map(o => o.entityName),\r\n );\r\n const entities = graph.entities.filter((e: any) => projectEntityNames.has(e.name));\r\n const entityNameSet = new Set(entities.map((e: any) => e.name));\r\n const relations = graph.relations.filter((r: any) => entityNameSet.has(r.from) && entityNameSet.has(r.to));\r\n return { entities, relations };\r\n }\r\n\r\n /** read_graph — MCP Official compatible */\r\n server.registerTool(\r\n 'read_graph',\r\n {\r\n title: 'Read Graph',\r\n description: 'Read the entire knowledge graph',\r\n inputSchema: {},\r\n },\r\n async () => {\r\n const unresolved = requireResolvedProject('read the knowledge graph');\r\n if (unresolved) return unresolved;\r\n const graph = await graphManager.readGraph();\r\n const scoped = await scopeGraphToProject(graph);\r\n return {\r\n content: [{ type: 'text' as const, text: JSON.stringify(scoped, null, 2) }],\r\n };\r\n },\r\n );\r\n\r\n /** search_nodes — MCP Official compatible (basic string search) */\r\n server.registerTool(\r\n 'search_nodes',\r\n {\r\n title: 'Search Nodes',\r\n description: 'Search for nodes in the knowledge graph based on a query',\r\n inputSchema: {\r\n query: z.string().describe('Search query to match against entity names, types, and observations'),\r\n },\r\n },\r\n async ({ query }) => {\r\n const unresolved = requireResolvedProject('search nodes in the knowledge graph');\r\n if (unresolved) return unresolved;\r\n const graph = await graphManager.searchNodes(query);\r\n const scoped = await scopeGraphToProject(graph);\r\n return {\r\n content: [{ type: 'text' as const, text: JSON.stringify(scoped, null, 2) }],\r\n };\r\n },\r\n );\r\n\r\n /** open_nodes — MCP Official compatible */\r\n server.registerTool(\r\n 'open_nodes',\r\n {\r\n title: 'Open Nodes',\r\n description: 'Open specific nodes in the knowledge graph by their names',\r\n inputSchema: {\r\n names: z.array(z.string()).describe('Entity names to retrieve'),\r\n },\r\n },\r\n async ({ names }) => {\r\n const unresolved = requireResolvedProject('open nodes in the knowledge graph');\r\n if (unresolved) return unresolved;\r\n const safeNames = coerceStringArray(names);\r\n const graph = await graphManager.openNodes(safeNames);\r\n const scoped = await scopeGraphToProject(graph);\r\n return {\r\n content: [{ type: 'text' as const, text: JSON.stringify(scoped, null, 2) }],\r\n };\r\n },\r\n );\r\n\r\n } // end if (enableKG)\r\n\r\n // ============================================================\r\n // Rules Sync Tool (P2 — Memorix differentiator)\r\n // ============================================================\r\n\r\n const RULE_SOURCES: [string, ...string[]] = ['cursor', 'claude-code', 'codex', 'windsurf', 'antigravity', 'copilot', 'kiro', 'opencode', 'trae'];\r\n\r\n /** memorix_rules_sync — scan, dedup, and generate rules across agents */\r\n server.registerTool(\r\n 'memorix_rules_sync',\r\n {\r\n title: 'Rules Sync',\r\n description:\r\n 'Scan project for agent rule files (Cursor, Claude Code, Codex, Windsurf, Antigravity, Copilot, Kiro, OpenCode, Trae), ' +\r\n 'deduplicate, detect conflicts, and optionally generate rules for a target agent format. ' +\r\n 'Without target: returns sync status report. With target: generates converted rule files.',\r\n inputSchema: {\r\n action: z.enum(['status', 'generate']).describe('Action: \"status\" for report, \"generate\" to produce target files'),\r\n target: z.enum(RULE_SOURCES).optional().describe('Target agent format for generation (required when action=generate)'),\r\n },\r\n },\r\n async ({ action, target }) => {\r\n const syncer = new RulesSyncer(project.rootPath);\r\n\r\n if (action === 'status') {\r\n const status = await syncer.syncStatus();\r\n const lines = [\r\n `## Rules Sync Status`,\r\n ``,\r\n `**Sources found:** ${status.sources.join(', ') || 'none'}`,\r\n `**Total rules:** ${status.totalRules}`,\r\n `**Unique rules:** ${status.uniqueRules}`,\r\n `**Conflicts:** ${status.conflicts.length}`,\r\n ];\r\n\r\n if (status.conflicts.length > 0) {\r\n lines.push('', '### Conflicts');\r\n for (const c of status.conflicts) {\r\n lines.push(`- **${c.ruleA.source}** \\`${c.ruleA.id}\\` vs **${c.ruleB.source}** \\`${c.ruleB.id}\\`: ${c.reason}`);\r\n }\r\n }\r\n\r\n return {\r\n content: [{ type: 'text' as const, text: lines.join('\\n') }],\r\n };\r\n }\r\n\r\n // action === 'generate'\r\n if (!target) {\r\n return {\r\n content: [{ type: 'text' as const, text: 'Error: target is required for generate action' }],\r\n isError: true,\r\n };\r\n }\r\n\r\n const rules = await syncer.scanRules();\r\n const deduped = syncer.deduplicateRules(rules);\r\n const effectiveTarget = target === 'opencode' ? 'codex' : target;\r\n const files = syncer.generateForTarget(deduped, effectiveTarget as RuleSource);\r\n\r\n const lines = [\r\n `## Generated ${files.length} file(s) for ${target}`,\r\n '',\r\n ];\r\n for (const f of files) {\r\n lines.push(`### \\`${f.filePath}\\``, '```', f.content, '```', '');\r\n }\r\n lines.push('> Use these contents to create the rule files in your project.');\r\n\r\n return {\r\n content: [{ type: 'text' as const, text: lines.join('\\n') }],\r\n };\r\n },\r\n );\r\n\r\n // ============================================================\r\n // Workspace Sync Tool (P3 — Cross-Agent Workspace Bridge)\r\n // ============================================================\r\n\r\n const AGENT_TARGETS: [string, ...string[]] = ['windsurf', 'cursor', 'claude-code', 'codex', 'copilot', 'antigravity', 'kiro', 'opencode', 'trae'];\r\n\r\n /** memorix_workspace_sync — migrate entire workspace config across agents */\r\n server.registerTool(\r\n 'memorix_workspace_sync',\r\n {\r\n title: 'Workspace Sync',\r\n description:\r\n 'Migrate your entire workspace environment between AI coding agents (Cursor, Windsurf, Claude Code, Codex, Copilot, Kiro, Antigravity, OpenCode, Trae). ' +\r\n 'Syncs MCP server configs, workflows, rules, and skills across IDEs. ' +\r\n 'Action \"scan\": detect all workspace configs. ' +\r\n 'Action \"migrate\": generate configs for target agent (preview only). ' +\r\n 'Action \"apply\": migrate AND write configs to disk with backup/rollback.',\r\n inputSchema: {\r\n action: z.enum(['scan', 'migrate', 'apply']).describe('Action: \"scan\" to detect configs, \"migrate\" to preview, \"apply\" to write to disk'),\r\n target: z.enum(AGENT_TARGETS).optional().describe('Target agent for migration (required for migrate)'),\r\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.'),\r\n },\r\n },\r\n async ({ action, target, items }) => {\r\n const engine = new WorkspaceSyncEngine(project.rootPath);\r\n\r\n if (action === 'scan') {\r\n const scan = await engine.scan();\r\n const lines = [\r\n `## Workspace Scan Report`,\r\n '',\r\n `### MCP Server Configs`,\r\n ];\r\n\r\n for (const [agent, servers] of Object.entries(scan.mcpConfigs)) {\r\n if ((servers as MCPServerEntry[]).length > 0) {\r\n lines.push(`- **${agent}**: ${(servers as MCPServerEntry[]).length} server(s) — ${(servers as MCPServerEntry[]).map((s: MCPServerEntry) => s.name).join(', ')}`);\r\n }\r\n }\r\n\r\n lines.push('', `### Workflows`);\r\n if (scan.workflows.length > 0) {\r\n for (const wf of scan.workflows) {\r\n lines.push(`- **${wf.name}** (${wf.source}): ${wf.description || '(no description)'}`);\r\n }\r\n } else {\r\n lines.push('- No workflows found');\r\n }\r\n\r\n lines.push('', `### Rules`);\r\n lines.push(`- ${scan.rulesCount} rule(s) detected across all agents`);\r\n\r\n lines.push('', `### Skills`);\r\n if (scan.skills.length > 0) {\r\n for (const sk of scan.skills) {\r\n lines.push(`- **${sk.name}** (${sk.sourceAgent}): ${sk.description || '(no description)'}`);\r\n }\r\n } else {\r\n lines.push('- No skills found');\r\n }\r\n\r\n if (scan.skillConflicts.length > 0) {\r\n lines.push('', `### [WARN] Skill Name Conflicts`);\r\n for (const c of scan.skillConflicts) {\r\n lines.push(`- **${c.name}**: kept from ${c.kept.sourceAgent}, duplicate in ${c.skipped.sourceAgent}`);\r\n }\r\n }\r\n\r\n return {\r\n content: [{ type: 'text' as const, text: lines.join('\\n') }],\r\n };\r\n }\r\n\r\n // action === 'migrate' or 'apply' — both need target\r\n if (!target) {\r\n return {\r\n content: [{ type: 'text' as const, text: 'Error: target is required for migrate/apply action' }],\r\n isError: true,\r\n };\r\n }\r\n\r\n if (action === 'apply') {\r\n const applyResult = await engine.apply(target as AgentTarget, items);\r\n return {\r\n content: [{ type: 'text' as const, text: applyResult.migrationSummary }],\r\n ...(applyResult.success ? {} : { isError: true }),\r\n };\r\n }\r\n\r\n // action === 'migrate' (preview only)\r\n const result = await engine.migrate(target as AgentTarget, items);\r\n const lines = [\r\n `## Workspace Migration → ${target}`,\r\n '',\r\n ];\r\n\r\n if (result.mcpServers.generated.length > 0) {\r\n lines.push('### MCP Config');\r\n for (const f of result.mcpServers.generated) {\r\n lines.push(`#### \\`${f.filePath}\\``, '```', f.content, '```', '');\r\n }\r\n }\r\n\r\n if (result.workflows.generated.length > 0) {\r\n lines.push('### Workflows');\r\n for (const f of result.workflows.generated) {\r\n lines.push(`#### \\`${f.filePath}\\``, '```', f.content, '```', '');\r\n }\r\n }\r\n\r\n if (result.rules.generated > 0) {\r\n lines.push(`### Rules`, `- ${result.rules.generated} rule file(s) generated`);\r\n }\r\n\r\n if (result.skills.scanned.length > 0) {\r\n lines.push('### Skills', `- ${result.skills.scanned.length} skill(s) found, ready to copy:`);\r\n for (const sk of result.skills.scanned) {\r\n lines.push(` - **${sk.name}** (from ${sk.sourceAgent})`);\r\n }\r\n }\r\n\r\n lines.push('', '> Review the generated configs above. Use action \"apply\" to write them to disk.');\r\n\r\n return {\r\n content: [{ type: 'text' as const, text: lines.join('\\n') }],\r\n };\r\n },\r\n );\r\n\r\n // ============================================================\r\n // memorix_skills — Memory-driven project skills\r\n // ============================================================\r\n\r\n server.registerTool(\r\n 'memorix_skills',\r\n {\r\n title: 'Project Skills',\r\n description:\r\n 'Memory-driven project skills. ' +\r\n 'Action \"list\": show all available skills from all agents. ' +\r\n 'Action \"generate\": auto-generate project-specific skills from observation patterns (gotchas, decisions, how-it-works). ' +\r\n 'Action \"inject\": return a specific skill\\'s full content for direct use. ' +\r\n 'Generated skills follow the SKILL.md standard and can be synced across Cursor, Windsurf, Claude Code, Codex, Copilot, Kiro, Antigravity, OpenCode, and Trae.',\r\n inputSchema: {\r\n action: z.enum(['list', 'generate', 'inject']).describe('Action: \"list\" to discover skills, \"generate\" to create from memory, \"inject\" to get skill content'),\r\n name: z.string().optional().describe('Skill name (required for \"inject\")'),\r\n target: z.enum(AGENT_TARGETS).optional().describe('Target agent to write generated skills to (optional for \"generate\")'),\r\n write: z.boolean().optional().describe('Whether to write generated skills to disk (default: false, preview only)'),\r\n },\r\n },\r\n async ({ action, name, target, write }) => {\r\n const { SkillsEngine } = await import('./skills/engine.js');\r\n const engine = new SkillsEngine(project.rootPath);\r\n\r\n if (action === 'list') {\r\n const skills = engine.listSkills();\r\n if (skills.length === 0) {\r\n return {\r\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.' }],\r\n };\r\n }\r\n\r\n const lines = [\r\n `## Available Skills (${skills.length})`,\r\n '',\r\n ];\r\n for (const sk of skills) {\r\n lines.push(`- **${sk.name}** (${sk.sourceAgent}): ${sk.description || '(no description)'}`);\r\n }\r\n lines.push('', '> Use `action: \"inject\", name: \"<skill-name>\"` to get full skill content.');\r\n\r\n return {\r\n content: [{ type: 'text' as const, text: lines.join('\\n') }],\r\n };\r\n }\r\n\r\n if (action === 'inject') {\r\n if (!name) {\r\n return {\r\n content: [{ type: 'text' as const, text: 'Error: `name` is required for inject action. Use `action: \"list\"` first to see available skills.' }],\r\n isError: true,\r\n };\r\n }\r\n\r\n const skill = engine.injectSkill(name);\r\n if (!skill) {\r\n return {\r\n content: [{ type: 'text' as const, text: `Skill \"${name}\" not found. Use \\`action: \"list\"\\` to see available skills.` }],\r\n isError: true,\r\n };\r\n }\r\n\r\n return {\r\n content: [{ type: 'text' as const, text: `## Skill: ${skill.name}\\n**Source**: ${skill.sourceAgent}\\n**Path**: ${skill.sourcePath}\\n\\n---\\n\\n${skill.content}` }],\r\n };\r\n }\r\n\r\n // action === 'generate'\r\n const { getObservationStore: getStore } = await import('./store/obs-store.js');\r\n const allObs = await getStore().loadAll() as Array<{\r\n id?: number; entityName?: string; type?: string; title?: string;\r\n narrative?: string; facts?: string[]; concepts?: string[];\r\n filesModified?: string[]; createdAt?: string;\r\n status?: string; source?: 'agent' | 'git' | 'manual';\r\n }>;\r\n\r\n const obsData = allObs.map(o => ({\r\n id: o.id || 0,\r\n entityName: o.entityName || 'unknown',\r\n type: o.type || 'discovery',\r\n title: o.title || '',\r\n narrative: o.narrative || '',\r\n facts: o.facts,\r\n concepts: o.concepts,\r\n filesModified: o.filesModified,\r\n createdAt: o.createdAt,\r\n status: o.status,\r\n source: o.source,\r\n }));\r\n\r\n const generated = engine.generateFromObservations(obsData);\r\n\r\n if (generated.length === 0) {\r\n return {\r\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!' }],\r\n };\r\n }\r\n\r\n const lines = [\r\n `## Generated Skills (${generated.length})`,\r\n '',\r\n 'Based on observation patterns in your project memory:',\r\n '',\r\n ];\r\n\r\n for (const sk of generated) {\r\n lines.push(`### ${sk.name}`);\r\n lines.push(`- **Description**: ${sk.description}`);\r\n lines.push(`- **Observations**: ${sk.content.split('\\n').length} lines of knowledge`);\r\n\r\n if (write && target) {\r\n const path = engine.writeSkill(sk, target as AgentTarget);\r\n if (path) {\r\n lines.push(`- [OK] **Written**: \\`${path}\\``);\r\n } else {\r\n lines.push(`- [ERROR] Failed to write`);\r\n }\r\n }\r\n lines.push('');\r\n }\r\n\r\n if (!write) {\r\n lines.push('> Preview only. Add `write: true, target: \"<agent>\"` to save skills to disk.');\r\n }\r\n\r\n // Show first generated skill as preview\r\n if (generated.length > 0) {\r\n lines.push('', '---', '### Preview: ' + generated[0].name, '', '```markdown', generated[0].content, '```');\r\n }\r\n\r\n return {\r\n content: [{ type: 'text' as const, text: lines.join('\\n') }],\r\n };\r\n },\r\n );\r\n\r\n // ============================================================\r\n // Mini-Skills — Promote memories to permanent skills\r\n // ============================================================\r\n\r\n /**\r\n * memorix_promote — Promote observations to permanent mini-skills\r\n *\r\n * Converts important memories into permanent, never-decaying mini-skills\r\n * that are automatically injected into agent context at session_start.\r\n */\r\n server.registerTool(\r\n 'memorix_promote',\r\n {\r\n title: 'Promote to Mini-Skill',\r\n description:\r\n 'Promote observations to permanent mini-skills that never decay and are auto-injected at session start. ' +\r\n 'Action \"promote\": convert observation(s) to a mini-skill. ' +\r\n 'Action \"list\": show all active mini-skills. ' +\r\n 'Action \"delete\": remove a mini-skill by ID.\\n\\n' +\r\n 'Mini-skills are project-specific specialized knowledge derived from your actual memories — ' +\r\n 'gotchas, decisions, fixes that generic online skills cannot provide.',\r\n inputSchema: {\r\n action: z.enum(['promote', 'list', 'delete']).describe('Action to perform'),\r\n observationIds: z.array(z.number()).optional().describe('Observation IDs to promote (required for \"promote\")'),\r\n skillId: z.number().optional().describe('Mini-skill ID to delete (required for \"delete\")'),\r\n trigger: z.string().optional().describe('Override: when this skill should be applied'),\r\n instruction: z.string().optional().describe('Override: what the agent should do'),\r\n tags: z.array(z.string()).optional().describe('Extra classification tags'),\r\n },\r\n },\r\n async ({ action, observationIds, skillId, trigger, instruction, tags }) => {\r\n const { promoteToMiniSkill, loadAllMiniSkills, deleteMiniSkill, formatMiniSkillsForInjection } = await import('./skills/mini-skills.js');\r\n\r\n if (action === 'list') {\r\n const skills = await loadAllMiniSkills(projectDir);\r\n if (skills.length === 0) {\r\n return {\r\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.' }],\r\n };\r\n }\r\n const formatted = formatMiniSkillsForInjection(skills);\r\n const lines = [\r\n formatted,\r\n '---',\r\n `Total: ${skills.length} mini-skill(s)`,\r\n '',\r\n '> Use `action: \"delete\", skillId: <id>` to remove a mini-skill.',\r\n ];\r\n return { content: [{ type: 'text' as const, text: lines.join('\\n') }] };\r\n }\r\n\r\n if (action === 'delete') {\r\n if (skillId == null) {\r\n return { content: [{ type: 'text' as const, text: 'Error: `skillId` is required for delete action.' }], isError: true };\r\n }\r\n const deleted = await deleteMiniSkill(projectDir, skillId);\r\n if (!deleted) {\r\n return { content: [{ type: 'text' as const, text: `Mini-skill #${skillId} not found.` }], isError: true };\r\n }\r\n return { content: [{ type: 'text' as const, text: `[OK] Deleted mini-skill #${skillId}.` }] };\r\n }\r\n\r\n // action === 'promote'\r\n if (!observationIds || observationIds.length === 0) {\r\n return { content: [{ type: 'text' as const, text: 'Error: `observationIds` is required for promote action. Use `memorix_search` to find observation IDs.' }], isError: true };\r\n }\r\n\r\n // Load observations by ID — only active observations can be promoted\r\n const { getAllObservations } = await import('./memory/observations.js');\r\n const allObs = await withFreshIndex(() => getAllObservations());\r\n const matched = allObs.filter(o => observationIds.includes(o.id));\r\n\r\n if (matched.length === 0) {\r\n return { content: [{ type: 'text' as const, text: `No observations found for IDs: [${observationIds.join(', ')}]. Use \\`memorix_search\\` to find valid IDs.` }], isError: true };\r\n }\r\n\r\n // Fail-fast: ALL matched observations must be active — no silent drop\r\n const nonActive = matched.filter(o => (o.status ?? 'active') !== 'active');\r\n if (nonActive.length > 0) {\r\n return { content: [{ type: 'text' as const, text: `Cannot promote: ${nonActive.length} observation(s) are not active: ${nonActive.map(o => `#${o.id} (${o.status})`).join(', ')}. Only active observations can be promoted to permanent knowledge.` }], isError: true };\r\n }\r\n\r\n const skill = await promoteToMiniSkill(projectDir, project.id, matched, { trigger, instruction, tags });\r\n\r\n const lines = [\r\n `[OK] Created mini-skill #${skill.id}`,\r\n '',\r\n `**${skill.title}**`,\r\n `**Do**: ${skill.instruction}`,\r\n `**When**: ${skill.trigger}`,\r\n ];\r\n if (skill.facts.length > 0) {\r\n lines.push('**Facts**:');\r\n for (const f of skill.facts) lines.push(`- ${f}`);\r\n }\r\n lines.push('', `Source: ${matched.length} observation(s) [${matched.map((o: any) => o.id).join(', ')}]`);\r\n lines.push('', '> This mini-skill will be auto-injected at every `memorix_session_start`.');\r\n\r\n return { content: [{ type: 'text' as const, text: lines.join('\\n') }] };\r\n },\r\n );\r\n\r\n // ============================================================\r\n // Memory Consolidation\r\n // ============================================================\r\n\r\n /**\r\n * memorix_consolidate — Merge similar observations to reduce bloat\r\n */\r\n server.registerTool(\r\n 'memorix_consolidate',\r\n {\r\n title: 'Consolidate Memories',\r\n description:\r\n 'Find and merge similar observations to reduce memory bloat. ' +\r\n 'Uses text similarity to cluster related observations by entity+type, then merges them into single consolidated records. ' +\r\n 'Use action=\"preview\" to see candidates without changing data, action=\"execute\" to merge.\\n\\n' +\r\n 'Example: 10 similar gotchas about Windows paths → 1 consolidated gotcha with all facts preserved.',\r\n inputSchema: {\r\n action: z.enum(['preview', 'execute']).describe('preview = dry run showing candidates, execute = actually merge'),\r\n threshold: z.number().optional().describe('Similarity threshold 0.0-1.0 (default: 0.45). Lower = more aggressive merging'),\r\n },\r\n },\r\n async ({ action, threshold }) => {\r\n const safeThreshold = threshold != null ? coerceNumber(threshold, 0.45) : undefined;\r\n const { findConsolidationCandidates, executeConsolidation } = await import('./memory/consolidation.js');\r\n\r\n if (action === 'preview') {\r\n const clusters = await findConsolidationCandidates(projectDir, project.id, { threshold: safeThreshold });\r\n\r\n if (clusters.length === 0) {\r\n return { content: [{ type: 'text' as const, text: '[OK] No consolidation candidates found. Your memories are already clean!' }] };\r\n }\r\n\r\n const lines = [`## Consolidation Preview`, `Found **${clusters.length}** clusters to merge:`, ''];\r\n for (let i = 0; i < clusters.length; i++) {\r\n const c = clusters[i];\r\n lines.push(`### Cluster ${i + 1} (${c.ids.length} observations, ~${(c.similarity * 100).toFixed(0)}% similar)`);\r\n lines.push(`Entity: \\`${c.entityName}\\` | Type: ${c.type}`);\r\n for (const title of c.titles) lines.push(`- ${title}`);\r\n lines.push('');\r\n }\r\n const totalMergeable = clusters.reduce((sum, c) => sum + c.ids.length - 1, 0);\r\n lines.push(`> Run with \\`action: \"execute\"\\` to merge. This will remove **${totalMergeable}** duplicate observations.`);\r\n\r\n return { content: [{ type: 'text' as const, text: lines.join('\\n') }] };\r\n }\r\n\r\n // Execute\r\n const result = await executeConsolidation(projectDir, project.id, { threshold: safeThreshold });\r\n\r\n if (result.clustersFound === 0) {\r\n return { content: [{ type: 'text' as const, text: '[OK] No consolidation needed. Memories are already clean!' }] };\r\n }\r\n\r\n const lines = [\r\n `## Consolidation Complete`,\r\n `- Clusters merged: **${result.clustersFound}**`,\r\n `- Observations removed: **${result.observationsMerged}**`,\r\n `- Observations remaining: **${result.observationsAfter}**`,\r\n '',\r\n ];\r\n for (const m of result.merges) {\r\n lines.push(`- Merged [${m.mergedIds.join(', ')}] → \"${m.resultTitle}\" (${m.factCount} facts)`);\r\n }\r\n\r\n return { content: [{ type: 'text' as const, text: lines.join('\\n') }] };\r\n },\r\n );\r\n\r\n // ============================================================\r\n // Session Lifecycle Tools (inspired by Engram)\r\n // ============================================================\r\n\r\n /**\r\n * memorix_session_start — Start a new coding session\r\n *\r\n * Creates a session record and returns context from previous sessions.\r\n * This is the entry point for session-aware memory management.\r\n */\r\n server.registerTool(\r\n 'memorix_session_start',\r\n {\r\n title: 'Start Session',\r\n description:\r\n 'Start a new coding session. Returns context from previous sessions so you can resume work seamlessly. ' +\r\n 'Call this at the beginning of a session to track activity and get injected context. ' +\r\n 'Any previous active session for this project will be auto-closed. ' +\r\n 'By default this is lightweight: it binds the project, opens a session, and injects context only. ' +\r\n 'Team identity is opt-in via `joinTeam: true` or a separate `team_manage` join call.\\n\\n' +\r\n 'IMPORTANT for HTTP/control-plane mode: pass `projectRoot` with the absolute path to your ' +\r\n 'workspace root (e.g., the directory open in your IDE). Memorix uses this to detect the git ' +\r\n 'project and bind this session to the correct project context. Without it, project-scoped ' +\r\n 'tools will be disabled.',\r\n inputSchema: {\r\n sessionId: z.string().optional().describe('Custom session ID (auto-generated if omitted)'),\r\n agent: z.string().optional().describe('Agent/IDE name (e.g., \"cursor\", \"windsurf\", \"claude-code\")'),\r\n agentType: z.string().optional().describe('Agent type used for optional Agent Team identity mapping (e.g., \"windsurf\", \"cursor\").'),\r\n instanceId: z.string().optional().describe('Stable instance ID for optional Agent Team identity across restarts. If omitted with joinTeam=true, Memorix derives a deterministic fallback from the project and agent identity.'),\r\n joinTeam: z.boolean().optional().describe('If true, also join the autonomous agent team for this session. Defaults to false.'),\r\n role: z.string().optional().describe('Explicit role override used only when joinTeam=true.'),\r\n projectRoot: z.string().optional().describe(\r\n 'Absolute path to the workspace/project root directory (e.g., the folder open in your IDE). ' +\r\n 'Memorix will detect the git project from this path and bind this session to it. ' +\r\n 'Required for HTTP transport when multiple projects are open simultaneously or when rebinding an existing control-plane session.',\r\n ),\r\n },\r\n },\r\n async ({ sessionId, agent, agentType, instanceId, joinTeam, role, projectRoot: explicitRoot }) => {\r\n // Phase 4a: clear agent identity — must not bleed from prior session_start\r\n currentAgentId = undefined;\r\n\r\n // ── Explicit project binding via projectRoot ──────────────────────\r\n // If the caller provides projectRoot, attempt to switch/bind to that project\r\n // BEFORE checking whether the project is resolved. This is the primary\r\n // mechanism for HTTP/control-plane multi-project support.\r\n if (explicitRoot && typeof explicitRoot === 'string') {\r\n let bound = await switchProject(explicitRoot);\r\n // Fallback: workspace root may contain a git project in a subdirectory\r\n if (!bound) {\r\n const { findGitInSubdirs } = await import('./project/detector.js');\r\n const subGit = findGitInSubdirs(explicitRoot);\r\n if (subGit) {\r\n bound = await switchProject(subGit);\r\n }\r\n }\r\n // switchProject returns false for \"same project, no-op\" — that's still success,\r\n // but ONLY when the canonical projectId matches the currently bound project.\r\n // We must NOT treat \"different valid repo at a different path\" as a no-op success.\r\n if (!bound && projectResolved) {\r\n const { detectProjectWithDiagnostics: diagnose } = await import('./project/detector.js');\r\n const diag = diagnose(explicitRoot);\r\n if (diag.project) {\r\n const { registerAlias: regAlias } = await import('./project/aliases.js');\r\n const resolvedCanonical = await regAlias(diag.project);\r\n if (resolvedCanonical === project.id) {\r\n // Same canonical project — switchProject returned false because it's a no-op.\r\n bound = true;\r\n }\r\n // else: different canonical project — fall through to fail-closed path below\r\n }\r\n }\r\n if (!bound) {\r\n // Explicit projectRoot was provided but no git repo found.\r\n // ALWAYS fail closed — never silently fall back to a previously bound project.\r\n const { detectProjectWithDiagnostics: diagnose } = await import('./project/detector.js');\r\n const diag = diagnose(explicitRoot);\r\n const failureDetail = diag.failure\r\n ? `\\nDiagnostic: [${diag.failure.reason}] ${diag.failure.detail}`\r\n : '';\r\n const hint = projectResolved\r\n ? `The session was previously bound to \"${project.name}\" (${project.id}), but the explicitly requested path has no git repo. Refusing to silently reuse the old binding.`\r\n : 'No project is currently bound to this session.';\r\n return {\r\n content: [{\r\n type: 'text' as const,\r\n text:\r\n `Cannot bind session to project.\\n` +\r\n `No git repository found at \"${explicitRoot}\".${failureDetail}\\n` +\r\n `${hint}\\n\\n` +\r\n 'Ensure the path points to a directory containing a .git folder (or a subdirectory of one). ' +\r\n 'Run \"git init\" in your project root if needed.',\r\n }],\r\n isError: true as const,\r\n };\r\n }\r\n // Bound successfully — mark as explicitly bound so roots won't override\r\n explicitProjectBound = true;\r\n }\r\n\r\n const unresolved = requireResolvedProject('start a project session');\r\n if (unresolved) return unresolved;\r\n\r\n const { startSession } = await import('./memory/session.js');\r\n const result = await startSession(projectDir, project.id, { sessionId, agent });\r\n\r\n const llmStatus = isLLMEnabled()\r\n ? `LLM enhanced mode: ${getLLMConfig()?.provider}/${getLLMConfig()?.model} (fact extraction + auto-dedup active)`\r\n : 'LLM mode: off (set MEMORIX_LLM_API_KEY to enable enhanced memory quality)';\r\n\r\n const shouldJoinTeam = !!joinTeam;\r\n // Phase 4a: Explicit team join only\r\n let registeredAgent: import('./team/team-store.js').TeamAgentRow | null = null;\r\n let watermarkInfo = '';\r\n let rescueInfo = '';\r\n let teamJoinNotice = '';\r\n try {\r\n if (!teamFeaturesEnabled && shouldJoinTeam) {\r\n teamJoinNotice = 'Team join skipped: the current tool profile does not expose Agent Team tools.';\r\n } else if (shouldJoinTeam && typeof teamStore !== 'undefined' && (agent || agentType)) {\r\n // Auto-derive role from agentType using AGENT_TYPE_ROLE_MAP\r\n const { AGENT_TYPE_ROLE_MAP } = await import('./team/team-store.js');\r\n const resolvedAgentType = agentType || agent || 'unknown';\r\n const resolvedRole = role || (resolvedAgentType ? AGENT_TYPE_ROLE_MAP[resolvedAgentType] : undefined) || 'engineer';\r\n const resolvedInstanceId = instanceId || createDeterministicInstanceId(\r\n project.id,\r\n resolvedAgentType,\r\n agent || agentType || undefined,\r\n );\r\n registeredAgent = teamStore.registerAgent({\r\n projectId: project.id,\r\n agentType: resolvedAgentType,\r\n instanceId: resolvedInstanceId,\r\n name: agent || agentType || undefined,\r\n role: resolvedRole,\r\n });\r\n\r\n // Set session-level agent identity for observation attribution\r\n currentAgentId = registeredAgent.agent_id;\r\n\r\n // Watermark: project-scoped count of new observations since last seen\r\n // Uses computeWatermark (extracted to team/poll.ts for reuse by memorix_poll)\r\n // withFreshIndex ensures cross-process writes are visible before counting\r\n const { computeWatermark } = await import('./team/poll.js');\r\n const lastSeen = registeredAgent.last_seen_obs_generation;\r\n const store = getObservationStore();\r\n const currentGen = store.getGeneration();\r\n const projectObs = await withFreshIndex(() => getAllObservations().filter(\r\n o => o.projectId === project.id && (o.writeGeneration ?? 0) > lastSeen,\r\n ));\r\n const wm = computeWatermark(lastSeen, currentGen, projectObs.length);\r\n if (wm.newObservationCount > 0) {\r\n watermarkInfo = `[STATS] ${wm.newObservationCount} new observation(s) in this project since your last session.`;\r\n }\r\n\r\n // Update watermark to current global generation (high-water mark for next session)\r\n teamStore.updateWatermark(registeredAgent.agent_id, currentGen);\r\n\r\n // Phase 4b: Rescue detection — detect stale agents and surface rescued tasks\r\n // detectAndMarkStale releases tasks from agents with stale heartbeats\r\n const STALE_TTL_MS = 5 * 60 * 1000; // 5 minutes without heartbeat = stale\r\n const rescuedAgentIds = teamStore.detectAndMarkStale(project.id, STALE_TTL_MS);\r\n if (rescuedAgentIds.length > 0) {\r\n rescueInfo = `[RESCUE] ${rescuedAgentIds.length} stale agent(s) detected and rescued.`;\r\n }\r\n\r\n // Check for available tasks (including any just-rescued ones)\r\n const availableTasks = teamStore.listTasks(project.id, { available: true });\r\n if (availableTasks.length > 0) {\r\n rescueInfo += rescueInfo ? '\\n' : '';\r\n rescueInfo += `[TASK] ${availableTasks.length} task(s) available to claim. Use memorix_poll for details.`;\r\n }\r\n } else if (shouldJoinTeam) {\r\n teamJoinNotice = 'Team join skipped: pass `agent` or `agentType` to create an Agent Team identity.';\r\n }\r\n } catch { /* team auto-registration is best-effort */ }\r\n\r\n const lines = [\r\n `[OK] Session started: ${result.session.id}`,\r\n `Project: ${project.name} (${project.id})`,\r\n result.session.agent ? `Agent: ${result.session.agent}` : '',\r\n registeredAgent ? `Agent ID: ${registeredAgent.agent_id} (instance: ${registeredAgent.instance_id})` : '',\r\n !registeredAgent ? 'Team identity: not joined (memory/session context only)' : '',\r\n llmStatus,\r\n teamJoinNotice,\r\n registeredAgent ? watermarkInfo : '',\r\n registeredAgent ? rescueInfo : '',\r\n '',\r\n '[TIP] Tips: Use `memorix_resolve` to mark completed tasks. Use `progress` param in `memorix_store` for task tracking. Use `topicKey` to prevent duplicate memories.',\r\n '',\r\n ];\r\n\r\n // Inject mini-skills (permanent, never-decaying project knowledge)\r\n // Filter out demo/test/system-self skills so they don't pollute unrelated projects.\r\n try {\r\n const { loadMiniSkills, formatMiniSkillsForInjection, recordMiniSkillUsage } = await import('./skills/mini-skills.js');\r\n const SKILL_NOISE = [\r\n /\\bdemo\\b/i, /展示/i, /全能力/i, /\\[test\\]/i, /\\[测试\\]/i, /测试/i,\r\n /验证/i, /兼容/i, /compat/i, /memmcp/i, /memorix-demo/i, /sandbox/i,\r\n /playground/i, /benchmark/i, /handoff/i, /交接/i, /for_memmcp/i,\r\n ];\r\n const allSkills = await loadMiniSkills(projectDir, project.id);\r\n const miniSkills = allSkills.filter(s => {\r\n const text = `${s.title}\\n${s.sourceEntity}\\n${s.instruction}`.toLowerCase();\r\n return !SKILL_NOISE.some(p => p.test(text));\r\n });\r\n if (miniSkills.length > 0) {\r\n const formatted = formatMiniSkillsForInjection(miniSkills);\r\n lines.push('---', '', formatted);\r\n // Record usage asynchronously (don't block response)\r\n recordMiniSkillUsage(projectDir, miniSkills.map(s => s.id)).catch(() => {});\r\n }\r\n } catch { /* mini-skills not available yet — skip */ }\r\n\r\n if (result.previousContext) {\r\n lines.push('---', '[TASK] **Context from previous sessions:**', '', result.previousContext);\r\n } else {\r\n lines.push('No previous session context found. This appears to be a fresh project.');\r\n }\r\n\r\n // Inject team context if any agents are active (Phase 4a: SQLite-backed)\r\n try {\r\n if (registeredAgent && teamFeaturesEnabled && typeof teamStore !== 'undefined') {\r\n const activeAgents = teamStore.listAgents(project.id, { status: 'active' });\r\n if (activeAgents.length > 0) {\r\n lines.push('', '---', '[TEAM] **Team Status:**');\r\n for (const a of activeAgents) {\r\n lines.push(`- [CHANGE] ${a.name}${a.role ? ` (${a.role})` : ''}`);\r\n }\r\n\r\n // Show locked files\r\n const locks = teamStore.listLocks(project.id);\r\n if (locks.length > 0) {\r\n lines.push('', '[LOCK] **Locked files:**');\r\n for (const l of locks) {\r\n const owner = teamStore.getAgent(l.locked_by);\r\n lines.push(`- ${l.file} — ${owner?.name ?? l.locked_by.slice(0, 8)}`);\r\n }\r\n }\r\n\r\n lines.push('', '[TIP] Use `team_manage` to register, `team_message` to check inbox, `team_task` to see tasks.');\r\n }\r\n }\r\n } catch { /* team context injection is optional */ }\r\n\r\n return {\r\n content: [{ type: 'text' as const, text: lines.filter(Boolean).join('\\n') }],\r\n };\r\n },\r\n );\r\n\r\n /**\r\n * memorix_session_end — End the current coding session\r\n *\r\n * Marks the session as completed with a structured summary.\r\n */\r\n server.registerTool(\r\n 'memorix_session_end',\r\n {\r\n title: 'End Session',\r\n description:\r\n 'End a coding session with a structured summary. This summary will be injected into the next session ' +\r\n 'so the next agent can resume work seamlessly.\\n\\n' +\r\n 'Recommended summary format:\\n' +\r\n '## Goal\\n[What we were working on]\\n\\n' +\r\n '## Discoveries\\n- [Technical findings, gotchas, learnings]\\n\\n' +\r\n '## Accomplished\\n- [OK] [Completed tasks]\\n- [PENDING] [Pending for next session]\\n\\n' +\r\n '## Relevant Files\\n- path/to/file — [what changed]',\r\n inputSchema: {\r\n sessionId: z.string().describe('Session ID to close (from memorix_session_start)'),\r\n summary: z.string().optional().describe('Structured session summary (Goal/Discoveries/Accomplished/Files format)'),\r\n },\r\n },\r\n async ({ sessionId, summary }) => {\r\n const { endSession } = await import('./memory/session.js');\r\n const session = await endSession(projectDir, sessionId, summary);\r\n\r\n if (!session) {\r\n return {\r\n content: [{ type: 'text' as const, text: `Session \"${sessionId}\" not found.` }],\r\n isError: true,\r\n };\r\n }\r\n\r\n return {\r\n content: [{\r\n type: 'text' as const,\r\n text: `[OK] 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.'}`,\r\n }],\r\n };\r\n },\r\n );\r\n\r\n /**\r\n * memorix_session_context — Get context from previous sessions\r\n *\r\n * Use this for compaction recovery or to manually retrieve session history.\r\n */\r\n server.registerTool(\r\n 'memorix_session_context',\r\n {\r\n title: 'Session Context',\r\n description:\r\n 'Get context from previous coding sessions. Use this after compaction to recover lost context, ' +\r\n 'or to manually review session history. Returns previous session summaries and key observations.',\r\n inputSchema: {\r\n limit: z.number().optional().describe('Number of recent sessions to include (default: 3)'),\r\n },\r\n },\r\n async ({ limit }) => {\r\n const safeLimit = limit != null ? coerceNumber(limit, 3) : 3;\r\n const { getSessionContext, listSessions } = await import('./memory/session.js');\r\n const context = await getSessionContext(projectDir, project.id, safeLimit);\r\n const sessions = await listSessions(projectDir, project.id);\r\n\r\n const activeSessions = sessions.filter(s => s.status === 'active');\r\n const completedSessions = sessions.filter(s => s.status === 'completed');\r\n\r\n const header = [\r\n `## Session Stats`,\r\n `- Active: ${activeSessions.length}`,\r\n `- Completed: ${completedSessions.length}`,\r\n `- Total: ${sessions.length}`,\r\n '',\r\n ];\r\n\r\n if (!context) {\r\n return {\r\n content: [{ type: 'text' as const, text: header.join('\\n') + '\\nNo previous session context available.' }],\r\n };\r\n }\r\n\r\n return {\r\n content: [{ type: 'text' as const, text: header.join('\\n') + context }],\r\n };\r\n },\r\n );\r\n\r\n // ============================================================\r\n // Export / Import\r\n // ============================================================\r\n\r\n /**\r\n * memorix_transfer — Export or import project memories\r\n */\r\n server.registerTool(\r\n 'memorix_transfer',\r\n {\r\n title: 'Transfer Memories',\r\n description:\r\n 'Export or import project memories. ' +\r\n 'Action \"export\": export observations and sessions (JSON or Markdown). ' +\r\n 'Action \"import\": import from a JSON export (re-assigns IDs, skips duplicate topicKeys).',\r\n inputSchema: {\r\n action: z.enum(['export', 'import']).describe('Operation: export or import'),\r\n format: z.enum(['json', 'markdown']).optional().describe('Export format (for export, default: json)'),\r\n data: z.string().optional().describe('JSON string from a previous export (for import)'),\r\n },\r\n },\r\n async ({ action, format, data: jsonStr }) => {\r\n if (action === 'export') {\r\n const { exportAsJson, exportAsMarkdown } = await import('./memory/export-import.js');\r\n if (format === 'markdown') {\r\n const md = await exportAsMarkdown(projectDir, project.id);\r\n return { content: [{ type: 'text' as const, text: md }] };\r\n }\r\n const data = await exportAsJson(projectDir, project.id);\r\n const json = JSON.stringify(data, null, 2);\r\n return {\r\n content: [{\r\n type: 'text' as const,\r\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.`,\r\n }],\r\n };\r\n }\r\n // import\r\n if (!jsonStr) return { content: [{ type: 'text' as const, text: '[ERROR] data is required for import' }], isError: true };\r\n const { importFromJson } = await import('./memory/export-import.js');\r\n let parsed;\r\n try { parsed = JSON.parse(jsonStr); } catch {\r\n return { content: [{ type: 'text' as const, text: 'Invalid JSON. Provide the exact output from export.' }], isError: true };\r\n }\r\n const result = await importFromJson(projectDir, parsed);\r\n return {\r\n content: [{\r\n type: 'text' as const,\r\n text: `Import complete — ${result.observationsImported} observations, ${result.sessionsImported} sessions imported, ${result.skipped} skipped`,\r\n }],\r\n };\r\n },\r\n );\r\n\r\n // ============================================================\r\n // memorix_dashboard — Launch the web dashboard\r\n // ============================================================\r\n\r\n let dashboardRunning = false;\r\n\r\n server.registerTool(\r\n 'memorix_dashboard',\r\n {\r\n title: 'Launch Dashboard',\r\n description:\r\n 'Launch the Memorix Web Dashboard in the browser. ' +\r\n 'In HTTP control-plane mode, this reuses the current control-plane dashboard. ' +\r\n 'In stdio/standalone mode, it starts the standalone dashboard server.',\r\n inputSchema: {\r\n port: z.number().optional().describe('Optional port override for standalone mode. In HTTP control-plane mode, the active dashboard port is reused.'),\r\n },\r\n },\r\n async ({ port: dashboardPort }) => {\r\n const inControlPlane = dashboardMode === 'control-plane';\r\n const portNum = inControlPlane\r\n ? configuredDashboardPort\r\n : (dashboardPort != null ? coerceNumber(dashboardPort, configuredDashboardPort) : configuredDashboardPort);\r\n const url = `http://localhost:${portNum}`;\r\n\r\n if (inControlPlane) {\r\n const http = await import('node:http');\r\n const postData = JSON.stringify({ projectId: project.id, projectName: project.name });\r\n await new Promise<void>(resolve => {\r\n const req = http.request({\r\n hostname: '127.0.0.1',\r\n port: portNum,\r\n path: '/api/set-current-project',\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(postData) },\r\n }, () => resolve());\r\n req.on('error', () => resolve());\r\n req.write(postData);\r\n req.end();\r\n });\r\n\r\n const projectUrl = `${url}?project=${encodeURIComponent(project.id)}`;\r\n const { exec } = await import('node:child_process');\r\n const cmd =\r\n process.platform === 'win32' ? `start \"\" \"${projectUrl}\"` :\r\n process.platform === 'darwin' ? `open \"${projectUrl}\"` :\r\n `xdg-open \"${projectUrl}\"`;\r\n exec(cmd, () => { });\r\n\r\n return {\r\n content: [{\r\n type: 'text' as const,\r\n text: [\r\n `Memorix Dashboard opened on the current control plane.`,\r\n ``,\r\n `URL: ${url}`,\r\n `Project: ${project.name} (${project.id})`,\r\n ``,\r\n `This MCP session is already running in HTTP control-plane mode, so no standalone 3210 dashboard was started.`,\r\n ].join('\\n'),\r\n }],\r\n };\r\n }\r\n\r\n if (dashboardRunning) {\r\n // Verify the dashboard is actually still listening (process may have been killed externally)\r\n const { createConnection } = await import('node:net');\r\n const isAlive = await new Promise<boolean>(resolve => {\r\n const sock = createConnection(portNum, '127.0.0.1');\r\n sock.once('connect', () => { sock.destroy(); resolve(true); });\r\n sock.once('error', () => { sock.destroy(); resolve(false); });\r\n setTimeout(() => { sock.destroy(); resolve(false); }, 1000);\r\n });\r\n\r\n if (isAlive) {\r\n // Update the dashboard server's current project via API\r\n const http = await import('node:http');\r\n const postData = JSON.stringify({ projectId: project.id, projectName: project.name });\r\n await new Promise<void>(resolve => {\r\n const req = http.request({\r\n hostname: '127.0.0.1', port: portNum,\r\n path: '/api/set-current-project', method: 'POST',\r\n headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(postData) },\r\n }, () => resolve());\r\n req.on('error', () => resolve()); // ignore errors\r\n req.write(postData);\r\n req.end();\r\n });\r\n\r\n // Open browser — the dashboard now serves this project as current\r\n const projectUrl = `${url}?project=${encodeURIComponent(project.id)}`;\r\n const { exec } = await import('node:child_process');\r\n const cmd =\r\n process.platform === 'win32' ? `start \"\" \"${projectUrl}\"` :\r\n process.platform === 'darwin' ? `open \"${projectUrl}\"` :\r\n `xdg-open \"${projectUrl}\"`;\r\n exec(cmd, () => { });\r\n return {\r\n content: [{ type: 'text' as const, text: `Dashboard is already running at ${url}. Switched to project: ${project.name} (${project.id}).` }],\r\n };\r\n }\r\n\r\n // Dashboard process was killed externally — reset flag and fall through to restart\r\n console.error('[memorix] Dashboard process no longer running, restarting...');\r\n dashboardRunning = false;\r\n }\r\n\r\n try {\r\n const pathMod = await import('node:path');\r\n const fsMod = await import('node:fs');\r\n const { fileURLToPath } = await import('node:url');\r\n const { startDashboard } = await import('./dashboard/server.js');\r\n\r\n // Try multiple strategies to find the static files directory\r\n // When running from CLI (dist/cli/index.js), __dirname = dist/cli/, need to go up\r\n const candidates = [\r\n pathMod.default.join(__dirname, '..', 'dashboard', 'static'),\r\n pathMod.default.join(__dirname, 'dashboard', 'static'),\r\n pathMod.default.join(pathMod.default.dirname(fileURLToPath(import.meta.url)), '..', 'dashboard', 'static'),\r\n pathMod.default.join(pathMod.default.dirname(fileURLToPath(import.meta.url)), 'dashboard', 'static'),\r\n ];\r\n\r\n // Log all candidates for debugging\r\n for (const [i, c] of candidates.entries()) {\r\n const hasIndex = fsMod.existsSync(pathMod.default.join(c, 'index.html'));\r\n console.error(`[memorix] candidate[${i}]: ${c} (has index.html: ${hasIndex})`);\r\n }\r\n\r\n let staticDir = candidates[0];\r\n for (const c of candidates) {\r\n if (fsMod.existsSync(pathMod.default.join(c, 'index.html'))) {\r\n staticDir = c;\r\n break;\r\n }\r\n }\r\n console.error(`[memorix] Dashboard staticDir: ${staticDir}`);\r\n\r\n // Start in background (non-blocking), disable auto-open (we'll open it ourselves)\r\n startDashboard(projectDir, portNum, staticDir, project.id, project.name, false, undefined, project.rootPath, projectResolved)\r\n .then(() => { dashboardRunning = true; })\r\n .catch((err) => { console.error('[memorix] Dashboard error:', err); dashboardRunning = false; });\r\n\r\n // Poll until the server is actually listening (up to 5s)\r\n const { createConnection } = await import('node:net');\r\n await new Promise<void>(resolve => {\r\n const deadline = Date.now() + 5000;\r\n const tryConnect = () => {\r\n const sock = createConnection(portNum, '127.0.0.1');\r\n sock.once('connect', () => { sock.destroy(); resolve(); });\r\n sock.once('error', () => {\r\n sock.destroy();\r\n if (Date.now() < deadline) setTimeout(tryConnect, 100);\r\n else resolve(); // give up, return anyway\r\n });\r\n };\r\n tryConnect();\r\n });\r\n dashboardRunning = true;\r\n\r\n // Open browser from MCP side\r\n const { exec: execCmd } = await import('node:child_process');\r\n const openCmd =\r\n process.platform === 'win32' ? `start \"\" \"${url}\"` :\r\n process.platform === 'darwin' ? `open \"${url}\"` :\r\n `xdg-open \"${url}\"`;\r\n execCmd(openCmd, () => { });\r\n\r\n return {\r\n content: [{\r\n type: 'text' as const,\r\n text: [\r\n `Memorix Dashboard started!`,\r\n ``,\r\n `URL: ${url}`,\r\n `Project: ${project.name} (${project.id})`,\r\n `Static: ${staticDir}`,\r\n ``,\r\n `The dashboard has been opened in your default browser.`,\r\n `It shows your knowledge graph, observations, retention scores, and project stats.`,\r\n ].join('\\n'),\r\n }],\r\n };\r\n } catch (err) {\r\n return {\r\n content: [{ type: 'text' as const, text: `Failed to start dashboard: ${err instanceof Error ? err.message : String(err)}` }],\r\n };\r\n }\r\n },\r\n );\r\n\r\n // ================================================================\r\n // Autonomous Agent Team Tools (Multi-Agent) - SQLite-backed\r\n // ================================================================\r\n\r\n // Use shared TeamStore (from HTTP server) or create new one (stdio mode).\r\n // All team state is canonical in SQLite — no JSON persistence, no sync/flush.\r\n let teamStore!: import('./team/team-store.js').TeamStore;\r\n let initTeamStoreForProject: ((dataDir: string) => Promise<import('./team/team-store.js').TeamStore>) | undefined;\r\n if (teamFeaturesEnabled) {\r\n const { initTeamStore } = await import('./team/team-store.js');\r\n initTeamStoreForProject = initTeamStore;\r\n if (sharedTeam?.teamStore) {\r\n teamStore = sharedTeam.teamStore;\r\n } else {\r\n teamStore = await initTeamStore(projectDir);\r\n }\r\n\r\n // Phase 4b: Wire EventBus for same-process lifecycle notifications.\r\n // EventBus is process-local only — NOT a cross-process mechanism.\r\n if (!teamStore.getEventBus()) {\r\n const { TeamEventBus } = await import('./team/event-bus.js');\r\n teamStore.setEventBus(new TeamEventBus());\r\n }\r\n }\r\n\r\n // ── team_manage (join / leave / status / listRoles / addRole / removeRole) ──\r\n server.registerTool(\r\n 'team_manage',\r\n {\r\n title: 'Team Management',\r\n description:\r\n 'Register, unregister, or list agents in the team. ' +\r\n 'Action \"join\": register this agent (returns agent ID and instance ID for reactivation). ' +\r\n 'Action \"leave\": mark agent inactive, release locks. ' +\r\n 'Action \"status\": list all agents with roles and capabilities, plus role occupancy. ' +\r\n 'Action \"listRoles\": show defined roles for this project. ' +\r\n 'Action \"addRole\": define a new role for this project. ' +\r\n 'Action \"removeRole\": remove a role definition.',\r\n inputSchema: {\r\n action: z.enum(['join', 'leave', 'status', 'listRoles', 'addRole', 'removeRole']).describe('Operation to perform'),\r\n name: z.string().optional().describe('Agent display name for join (e.g., \"cursor-frontend\")'),\r\n agentType: z.string().optional().describe('Agent type for join (e.g., \"windsurf\", \"cursor\", \"claude-code\")'),\r\n instanceId: z.string().optional().describe('Stable instance ID for join (preserves identity across restarts)'),\r\n role: z.string().optional().describe('Agent role for join (defaults by agentType if omitted)'),\r\n capabilities: z.array(z.string()).optional().describe('Agent capabilities for join'),\r\n agentId: z.string().optional().describe('Agent ID for leave'),\r\n // Role management params\r\n roleId: z.string().optional().describe('Role ID (for addRole/removeRole)'),\r\n label: z.string().optional().describe('Role label (for addRole)'),\r\n roleDescription: z.string().optional().describe('Role description (for addRole)'),\r\n preferredAgentTypes: z.array(z.string()).optional().describe('Preferred agent types for this role (for addRole)'),\r\n maxConcurrent: z.number().optional().describe('Max concurrent agents for this role (for addRole, default 1)'),\r\n },\r\n },\r\n async ({ action, name, agentType, instanceId, role, capabilities, agentId, roleId, label, roleDescription, preferredAgentTypes, maxConcurrent }) => {\r\n if (action === 'join') {\r\n // Auto-derive role from agentType if not provided\r\n const { AGENT_TYPE_ROLE_MAP } = await import('./team/team-store.js');\r\n const resolvedRole = role || (agentType ? AGENT_TYPE_ROLE_MAP[agentType] : undefined) || 'engineer';\r\n const agent = teamStore.registerAgent({\r\n projectId: project.id,\r\n agentType: agentType || 'unknown',\r\n instanceId: instanceId || undefined,\r\n name: (name || '').trim() || undefined,\r\n role: resolvedRole,\r\n capabilities: capabilities ? coerceStringArray(capabilities) : undefined,\r\n });\r\n currentAgentId = agent.agent_id;\r\n const caps = agent.capabilities ? JSON.parse(agent.capabilities) : [];\r\n return {\r\n content: [{\r\n type: 'text' as const,\r\n text: `Joined Agent Team as \"${agent.name}\" (ID: ${agent.agent_id})\\nInstance ID: ${agent.instance_id}\\nRole: ${agent.role}\\nThis session now attributes Agent Team activity to that identity.\\nActive agents: ${teamStore.getActiveCount(project.id)}`,\r\n }],\r\n };\r\n }\r\n if (action === 'leave') {\r\n if (!agentId) return { content: [{ type: 'text' as const, text: 'agentId is required for leave' }], isError: true };\r\n const left = teamStore.leaveAgent(agentId);\r\n if (currentAgentId === agentId) currentAgentId = undefined;\r\n if (!left) return { content: [{ type: 'text' as const, text: 'Agent not found' }] };\r\n const releasedLocks = teamStore.releaseAllLocks(agentId);\r\n const releasedTasks = teamStore.releaseTasksByAgent(agentId);\r\n const parts: string[] = [];\r\n if (releasedLocks > 0) parts.push(`released ${releasedLocks} lock(s)`);\r\n if (releasedTasks > 0) parts.push(`released ${releasedTasks} task(s)`);\r\n return {\r\n content: [{\r\n type: 'text' as const,\r\n text: `Left team.${parts.length > 0 ? ' ' + parts.join(', ') + '.' : ''}\\nActive agents: ${teamStore.getActiveCount(project.id)}`,\r\n }],\r\n };\r\n }\r\n if (action === 'listRoles') {\r\n const roles = teamStore.listRoles(project.id);\r\n if (roles.length === 0) {\r\n return { content: [{ type: 'text' as const, text: 'No roles defined for this project.' }] };\r\n }\r\n const occupancy = teamStore.getRoleOccupancy(project.id);\r\n const lines = occupancy.map(({ role, activeAgents, vacant }) => {\r\n const agentTypes = JSON.parse(role.preferred_agent_types);\r\n const agentNames = activeAgents.map(a => a.name).join(', ') || 'vacant';\r\n return `${role.label} (${role.role_id.split(':').pop()}) - ${activeAgents.length}/${role.max_concurrent} filled, ${vacant} vacant\\n Agents: ${agentNames}\\n Preferred types: ${agentTypes.join(', ') || 'any'}${role.description ? '\\n ' + role.description : ''}`;\r\n });\r\n return { content: [{ type: 'text' as const, text: `Roles (${roles.length}):\\n\\n${lines.join('\\n\\n')}` }] };\r\n }\r\n if (action === 'addRole') {\r\n if (!roleId || !label) return { content: [{ type: 'text' as const, text: 'roleId and label are required for addRole' }], isError: true };\r\n const newRole = teamStore.addRole(project.id, {\r\n roleId,\r\n label,\r\n description: roleDescription,\r\n preferredAgentTypes: preferredAgentTypes ? coerceStringArray(preferredAgentTypes) : undefined,\r\n maxConcurrent,\r\n });\r\n return { content: [{ type: 'text' as const, text: `Role added: ${newRole.label} (${newRole.role_id})` }] };\r\n }\r\n if (action === 'removeRole') {\r\n if (!roleId) return { content: [{ type: 'text' as const, text: 'roleId is required for removeRole' }], isError: true };\r\n const removed = teamStore.removeRole(project.id, roleId);\r\n if (!removed) return { content: [{ type: 'text' as const, text: 'Role not found' }] };\r\n return { content: [{ type: 'text' as const, text: `Role removed: ${roleId}` }] };\r\n }\r\n // status - now includes role occupancy\r\n const agents = teamStore.listAgents(project.id);\r\n const occupancy = teamStore.getRoleOccupancy(project.id);\r\n if (agents.length === 0 && occupancy.length === 0) {\r\n return { content: [{ type: 'text' as const, text: 'No agents registered. Use action \"join\" to register.' }] };\r\n }\r\n const roleLines = occupancy.map(({ role, activeAgents, vacant }) => {\r\n const agentNames = activeAgents.map(a => a.name).join(', ') || 'vacant';\r\n return `${role.label}: ${activeAgents.length}/${role.max_concurrent} - ${agentNames}${vacant > 0 ? ` (${vacant} slot${vacant > 1 ? 's' : ''} open)` : ''}`;\r\n });\r\n const agentLines = agents.map((a: import('./team/team-store.js').TeamAgentRow) => {\r\n const caps = a.capabilities ? JSON.parse(a.capabilities) : [];\r\n return `${a.status === 'active' ? '[active]' : '[inactive]'} ${a.name} (${a.agent_id.slice(0, 8)}) - ${a.role ?? 'no role'} [${caps.join(', ') || '-'}]`;\r\n });\r\n return {\r\n content: [{\r\n type: 'text' as const,\r\n text: `Team: ${teamStore.getActiveCount(project.id)} active / ${agents.length} total\\n\\nRole Occupancy:\\n${roleLines.join('\\n')}\\n\\nAgents:\\n${agentLines.join('\\n')}`,\r\n }],\r\n };\r\n },\r\n );\r\n\r\n // ── team_file_lock (lock / unlock / status) ───────────────────\r\n server.registerTool(\r\n 'team_file_lock',\r\n {\r\n title: 'File Lock Management',\r\n description:\r\n 'Advisory file locks to prevent conflicting edits. Auto-releases after 10 min TTL. ' +\r\n 'Action \"lock\": acquire lock. Action \"unlock\": release lock. Action \"status\": check lock status.',\r\n inputSchema: {\r\n action: z.enum(['lock', 'unlock', 'status']).describe('Operation to perform'),\r\n file: z.string().optional().describe('File path (required for lock/unlock, optional for status — omit to list all)'),\r\n agentId: z.string().optional().describe('Agent ID (required for lock/unlock)'),\r\n },\r\n },\r\n async ({ action, file, agentId }) => {\r\n if (action === 'lock') {\r\n if (!file || !agentId) return { content: [{ type: 'text' as const, text: '[ERROR] file and agentId are required for lock' }], isError: true };\r\n const agent = teamStore.getAgent(agentId);\r\n if (!agent || agent.status !== 'active') {\r\n return { content: [{ type: 'text' as const, text: `[ERROR] Unknown or inactive agent: ${agentId.slice(0, 8)}…` }], isError: true };\r\n }\r\n const result = teamStore.acquireLock(project.id, file, agentId);\r\n if (result.success) return { content: [{ type: 'text' as const, text: `Locked: ${file}` }] };\r\n const owner = teamStore.getAgent(result.lockedBy);\r\n return { content: [{ type: 'text' as const, text: `Denied — locked by ${owner?.name ?? result.lockedBy.slice(0, 8)}` }], isError: true };\r\n }\r\n if (action === 'unlock') {\r\n if (!file || !agentId) return { content: [{ type: 'text' as const, text: '[ERROR] file and agentId are required for unlock' }], isError: true };\r\n const released = teamStore.releaseLock(project.id, file, agentId);\r\n return { content: [{ type: 'text' as const, text: released ? `Unlocked: ${file}` : `Cannot unlock: not owner or not locked` }] };\r\n }\r\n // status\r\n if (file) {\r\n const lockStatus = teamStore.getLockStatus(project.id, file);\r\n if (!lockStatus) return { content: [{ type: 'text' as const, text: `${file} — unlocked` }] };\r\n const owner = teamStore.getAgent(lockStatus.locked_by);\r\n return { content: [{ type: 'text' as const, text: `${file} — locked by ${owner?.name ?? lockStatus.locked_by.slice(0, 8)} (expires ${new Date(lockStatus.expires_at).toISOString()})` }] };\r\n }\r\n const all = teamStore.listLocks(project.id);\r\n if (all.length === 0) return { content: [{ type: 'text' as const, text: 'No files locked' }] };\r\n const lines = all.map((l: import('./team/team-store.js').TeamLockRow) => {\r\n const owner = teamStore.getAgent(l.locked_by);\r\n return `${l.file} — ${owner?.name ?? l.locked_by.slice(0, 8)}`;\r\n });\r\n return { content: [{ type: 'text' as const, text: `Locked files (${all.length}):\\n${lines.join('\\n')}` }] };\r\n },\r\n );\r\n\r\n // ── team_task (create / claim / complete / list) ──────────────\r\n server.registerTool(\r\n 'team_task',\r\n {\r\n title: 'Task Board',\r\n description:\r\n 'Create, claim, complete, or list tasks in the team task board. Supports dependencies. ' +\r\n 'Action \"create\": create a task. Action \"claim\": assign to yourself (atomic, race-safe). ' +\r\n 'Action \"complete\": mark done with result. Action \"list\": show tasks.',\r\n inputSchema: {\r\n action: z.enum(['create', 'claim', 'complete', 'list']).describe('Operation to perform'),\r\n description: z.string().optional().describe('Task description (for create)'),\r\n deps: z.array(z.string()).optional().describe('Dependency task IDs (for create)'),\r\n taskId: z.string().optional().describe('Task ID (for claim/complete)'),\r\n agentId: z.string().optional().describe('Agent ID (for claim/complete)'),\r\n result: z.string().optional().describe('Result summary (for complete)'),\r\n status: z.enum(['pending', 'in_progress', 'completed', 'failed']).optional().describe('Filter by status (for list)'),\r\n available: z.boolean().optional().describe('Show only claimable tasks (for list)'),\r\n metadata: z.string().optional().describe('JSON metadata for the task (for create). Used by planner/review tasks for autonomous mode.'),\r\n requiredRole: z.string().optional().describe('Required role for this task (for create). Agents without this role cannot claim.'),\r\n preferredRole: z.string().optional().describe('Preferred role for this task (for create). Agents with this role are prioritized.'),\r\n },\r\n },\r\n async ({ action, description: desc, deps, taskId, agentId, result, status, available, metadata, requiredRole, preferredRole }) => {\r\n try {\r\n if (action === 'create') {\r\n if (!desc) return { content: [{ type: 'text' as const, text: '[ERROR] description is required for create' }], isError: true };\r\n let parsedMeta: Record<string, unknown> | undefined;\r\n if (metadata) {\r\n try { parsedMeta = JSON.parse(metadata); } catch { /* ignore invalid JSON */ }\r\n }\r\n\r\n // Phase 5: enforce autonomous-pipeline hard guards\r\n const { checkPipelineGuards } = await import('./orchestrate/planner.js');\r\n const existingTasks = teamStore.listTasks(project.id);\r\n const guard = checkPipelineGuards({ existingTasks, newTaskMeta: parsedMeta });\r\n if (!guard.allowed) {\r\n return { content: [{ type: 'text' as const, text: `[ERROR] ${guard.reason}` }], isError: true };\r\n }\r\n\r\n const task = teamStore.createTask({\r\n projectId: project.id,\r\n description: desc,\r\n deps: deps ? coerceStringArray(deps) : undefined,\r\n metadata: parsedMeta,\r\n createdBy: agentId || undefined,\r\n requiredRole: requiredRole || undefined,\r\n preferredRole: preferredRole || undefined,\r\n });\r\n const taskDeps = teamStore.getTaskDeps(task.task_id);\r\n const roleInfo = task.required_role ? ` [role: ${task.required_role}${task.preferred_role && task.preferred_role !== task.required_role ? '/' + task.preferred_role : ''}]` : '';\r\n return { content: [{ type: 'text' as const, text: `Task created: ${task.task_id.slice(0, 8)}… \"${desc}\"${taskDeps.length > 0 ? ` (depends on ${taskDeps.length})` : ''}${roleInfo}` }] };\r\n }\r\n if (action === 'claim') {\r\n if (!taskId || !agentId) return { content: [{ type: 'text' as const, text: '[ERROR] taskId and agentId required for claim' }], isError: true };\r\n const agent = teamStore.getAgent(agentId);\r\n if (!agent || agent.status !== 'active') return { content: [{ type: 'text' as const, text: `[ERROR] Unknown or inactive agent` }], isError: true };\r\n const claimResult = teamStore.claimTask(taskId, agentId);\r\n if (!claimResult.success) return { content: [{ type: 'text' as const, text: `[ERROR] ${claimResult.reason}` }], isError: true };\r\n const hintSuffix = claimResult.hint ? `\\n[WARN] ${claimResult.hint}` : '';\r\n return { content: [{ type: 'text' as const, text: `Task claimed by ${agent.name}: \"${claimResult.task!.description}\"${hintSuffix}` }] };\r\n }\r\n if (action === 'complete') {\r\n if (!taskId || !agentId || !result) return { content: [{ type: 'text' as const, text: '[ERROR] taskId, agentId, and result required for complete' }], isError: true };\r\n const completeResult = teamStore.completeTask(taskId, agentId, result);\r\n if (!completeResult.success) return { content: [{ type: 'text' as const, text: `[ERROR] ${completeResult.reason}` }], isError: true };\r\n const completedTask = teamStore.getTask(taskId);\r\n return { content: [{ type: 'text' as const, text: `Task completed: \"${completedTask?.description ?? taskId}\"\\nResult: ${result}` }] };\r\n }\r\n // list\r\n const list = (available && agentId)\r\n ? teamStore.listTasksForAgent(project.id, agentId)\r\n : teamStore.listTasks(project.id, available ? { available: true } : (status ? { status } : undefined));\r\n if (list.length === 0) return { content: [{ type: 'text' as const, text: available ? 'No tasks available to claim' : 'No tasks found' }] };\r\n const statusIcon: Record<string, string> = { pending: '[ ]', in_progress: '[~]', completed: '[x]', failed: '[!]' };\r\n const lines = list.map((t: import('./team/team-store.js').TeamTaskRow) => {\r\n const assignee = t.assignee_agent_id ? teamStore.getAgent(t.assignee_agent_id)?.name ?? t.assignee_agent_id.slice(0, 8) : 'unassigned';\r\n const taskDeps = teamStore.getTaskDeps(t.task_id);\r\n const roleTag = t.required_role ? ` [${t.required_role}${t.preferred_role && t.preferred_role !== t.required_role ? '→' + t.preferred_role : ''}]` : (t.preferred_role ? ` [~${t.preferred_role}]` : '');\r\n return `${statusIcon[t.status] ?? '[ ]'} ${t.task_id.slice(0, 8)}… \"${t.description}\" — ${assignee}${roleTag}${taskDeps.length > 0 ? ` [deps: ${taskDeps.length}]` : ''}`;\r\n });\r\n return { content: [{ type: 'text' as const, text: `Tasks (${list.length}):\\n${lines.join('\\n')}` }] };\r\n } catch (err) {\r\n return { content: [{ type: 'text' as const, text: `[ERROR] ${(err as Error).message}` }], isError: true };\r\n }\r\n },\r\n );\r\n\r\n // ── team_message (send / broadcast / inbox) ───────────────────\r\n server.registerTool(\r\n 'team_message',\r\n {\r\n title: 'Team Messaging',\r\n description:\r\n 'Send, broadcast, or read messages between agents. Durable: messages survive restarts and reach inactive recipients. ' +\r\n 'Action \"send\": direct message to one agent. Action \"broadcast\": message all agents. ' +\r\n 'Action \"inbox\": read this agent\\'s inbox.',\r\n inputSchema: {\r\n action: z.enum(['send', 'broadcast', 'inbox']).describe('Operation to perform'),\r\n from: z.string().optional().describe('Sender agent ID (for send/broadcast)'),\r\n to: z.string().optional().describe('Receiver agent ID (for send)'),\r\n type: z.enum(['request', 'response', 'info', 'announcement', 'contract', 'error', 'handoff']).optional().describe('Message type (for send/broadcast)'),\r\n content: z.string().optional().describe('Message content (for send/broadcast)'),\r\n agentId: z.string().optional().describe('Agent ID (for inbox)'),\r\n markRead: z.boolean().optional().default(false).describe('Mark messages as read (for inbox)'),\r\n toRole: z.string().optional().describe('Target role for role-based messaging/handoff (for send)'),\r\n handoffStatus: z.enum(['open', 'claimed', 'completed', 'archived']).optional().describe('Handoff status (for send with type=handoff)'),\r\n },\r\n },\r\n async ({ action, from, to, type: msgType, content, agentId, markRead, toRole, handoffStatus }) => {\r\n if (action === 'send') {\r\n if (!from || !msgType || !content) return { content: [{ type: 'text' as const, text: '[ERROR] from, type, and content required for send' }], isError: true };\r\n if (!to && !toRole) return { content: [{ type: 'text' as const, text: '[ERROR] either to (agent ID) or toRole is required for send' }], isError: true };\r\n if (content.length > 10_000) return { content: [{ type: 'text' as const, text: '[ERROR] Message too large (max 10KB)' }], isError: true };\r\n const msg = teamStore.sendMessage({\r\n projectId: project.id,\r\n senderAgentId: from,\r\n recipientAgentId: to ?? null,\r\n type: msgType,\r\n content,\r\n toRole: toRole ?? null,\r\n handoffStatus: handoffStatus ?? (msgType === 'handoff' ? 'open' : null),\r\n });\r\n if ('error' in msg) return { content: [{ type: 'text' as const, text: `[ERROR] ${msg.error}` }], isError: true };\r\n const target = to ? `agent ${to.slice(0, 8)}…` : `role ${toRole}`;\r\n return { content: [{ type: 'text' as const, text: `Message sent (${msgType}) to ${target} | ID: ${msg.id.slice(0, 8)}…${toRole ? ` [role: ${toRole}]` : ''}` }] };\r\n }\r\n if (action === 'broadcast') {\r\n if (!from || !msgType || !content) return { content: [{ type: 'text' as const, text: '[ERROR] from, type, and content required for broadcast' }], isError: true };\r\n if (content.length > 10_000) return { content: [{ type: 'text' as const, text: '[ERROR] Message too large (max 10KB)' }], isError: true };\r\n const msg = teamStore.sendMessage({\r\n projectId: project.id,\r\n senderAgentId: from,\r\n recipientAgentId: null,\r\n type: msgType,\r\n content,\r\n });\r\n if ('error' in msg) return { content: [{ type: 'text' as const, text: `[ERROR] ${msg.error}` }], isError: true };\r\n return { content: [{ type: 'text' as const, text: `Broadcast (${msgType}) | ID: ${msg.id.slice(0, 8)}…` }] };\r\n }\r\n // inbox\r\n const inboxId = agentId || from || '';\r\n if (!inboxId) return { content: [{ type: 'text' as const, text: '[ERROR] agentId required for inbox' }], isError: true };\r\n const inbox = teamStore.getInbox(project.id, inboxId);\r\n const unread = teamStore.getUnreadCount(project.id, inboxId);\r\n if (inbox.length === 0) return { content: [{ type: 'text' as const, text: 'Inbox empty' }] };\r\n if (markRead) {\r\n teamStore.markAllRead(project.id, inboxId);\r\n }\r\n const lines = inbox.slice(-10).map((m: import('./team/team-store.js').TeamMessageRow) => {\r\n const sender = teamStore.getAgent(m.sender_agent_id);\r\n return `${m.read_at ? ' ' : '*'} [${m.type}] from ${sender?.name ?? m.sender_agent_id.slice(0, 8)}: ${m.content.slice(0, 100)}`;\r\n });\r\n return { content: [{ type: 'text' as const, text: `Inbox: ${unread} unread / ${inbox.length} total\\n\\n${lines.join('\\n')}` }] };\r\n },\r\n );\r\n\r\n // ── memorix_poll (Phase 4b: situational awareness) ────────────────\r\n server.registerTool(\r\n 'memorix_poll',\r\n {\r\n title: 'Team Poll — Situational Awareness',\r\n description:\r\n 'Get a full snapshot of your team coordination state in one call. ' +\r\n 'Returns: your agent info, watermark (new observations since last session), ' +\r\n 'inbox (unread messages), tasks (your in-progress, available to claim, completed, failed), ' +\r\n 'and team roster (active agents). Use this to decide what to work on next.',\r\n inputSchema: {\r\n agentId: z.string().optional().describe('Your agent ID (from team_manage join or session_start with joinTeam=true). If omitted, returns project-level overview only.'),\r\n markInboxRead: z.boolean().optional().describe('If true, mark all inbox messages as read after returning them.'),\r\n },\r\n },\r\n async ({ agentId, markInboxRead }) => {\r\n const { computeWatermark, computePoll } = await import('./team/poll.js');\r\n\r\n // Compute watermark — requires observation store access\r\n let watermark = computeWatermark(0, 0, 0);\r\n if (agentId) {\r\n const agent = teamStore.getAgent(agentId);\r\n if (agent) {\r\n const lastSeen = agent.last_seen_obs_generation;\r\n const store = getObservationStore();\r\n const currentGen = store.getGeneration();\r\n const projectObs = await withFreshIndex(() => getAllObservations().filter(\r\n o => o.projectId === project.id && (o.writeGeneration ?? 0) > lastSeen,\r\n ));\r\n watermark = computeWatermark(lastSeen, currentGen, projectObs.length);\r\n\r\n // Advance watermark so next poll sees only truly new observations\r\n teamStore.updateWatermark(agentId, currentGen);\r\n // Heartbeat — proves this agent is alive\r\n teamStore.heartbeat(agentId);\r\n }\r\n }\r\n\r\n const poll = computePoll(teamStore, project.id, agentId ?? null, watermark);\r\n\r\n // Optionally mark inbox as read\r\n if (markInboxRead && agentId) {\r\n teamStore.markAllRead(project.id, agentId);\r\n }\r\n\r\n // Format as readable text\r\n const lines: string[] = [];\r\n\r\n // Agent\r\n if (poll.agent) {\r\n lines.push(`[AGENT] You: ${poll.agent.agentId.slice(0, 8)}… (${poll.agent.status})`);\r\n }\r\n\r\n // Watermark\r\n if (poll.watermark.newObservationCount > 0) {\r\n lines.push(`[STATS] ${poll.watermark.newObservationCount} new observation(s) since your last session`);\r\n }\r\n\r\n // Inbox\r\n if (poll.inbox.unreadCount > 0) {\r\n lines.push(`[INBOX] ${poll.inbox.unreadCount} unread message(s)`);\r\n for (const m of poll.inbox.messages.slice(-5)) {\r\n const sender = teamStore.getAgent(m.sender_agent_id);\r\n lines.push(` ${m.read_at ? ' ' : '*'} [${m.type}] from ${sender?.name ?? m.sender_agent_id.slice(0, 8)}: ${m.content.slice(0, 80)}`);\r\n }\r\n }\r\n\r\n // Tasks\r\n if (poll.tasks.myInProgress.length > 0) {\r\n lines.push(`\\n[TOOL] Your in-progress tasks (${poll.tasks.myInProgress.length}):`);\r\n for (const t of poll.tasks.myInProgress) {\r\n lines.push(` [~] ${t.task_id.slice(0, 8)}… \"${t.description}\"`);\r\n }\r\n }\r\n if (poll.tasks.availableToClaim.length > 0) {\r\n lines.push(`\\n[TASK] Available to claim (${poll.tasks.availableToClaim.length}):`);\r\n for (const t of poll.tasks.availableToClaim) {\r\n lines.push(` [ ] ${t.task_id.slice(0, 8)}… \"${t.description}\"`);\r\n }\r\n }\r\n if (poll.tasks.recentlyCompleted.length > 0) {\r\n lines.push(`\\n[OK] Completed (${poll.tasks.recentlyCompleted.length}):`);\r\n for (const t of poll.tasks.recentlyCompleted.slice(-5)) {\r\n const who = t.assignee_agent_id ? teamStore.getAgent(t.assignee_agent_id)?.name ?? t.assignee_agent_id.slice(0, 8) : '?';\r\n lines.push(` [x] ${t.task_id.slice(0, 8)}… \"${t.description}\" — by ${who}`);\r\n }\r\n }\r\n if (poll.tasks.recentlyFailed.length > 0) {\r\n lines.push(`\\n[ERROR] Failed (${poll.tasks.recentlyFailed.length}):`);\r\n for (const t of poll.tasks.recentlyFailed.slice(-3)) {\r\n lines.push(` [!] ${t.task_id.slice(0, 8)}… \"${t.description}\" — ${t.result?.slice(0, 80) ?? 'no reason'}`);\r\n }\r\n }\r\n\r\n // Team\r\n lines.push(`\\n[TEAM] Team: ${poll.team.activeAgents.length} active / ${poll.team.totalAgents} total`);\r\n for (const a of poll.team.activeAgents) {\r\n lines.push(` - ${a.name} (${a.agent_type}) — ${a.role ?? 'no role'}`);\r\n }\r\n\r\n if (lines.length === 0) {\r\n lines.push('No team activity yet. Use team_manage action=\"join\" to register, then team_task to create tasks.');\r\n }\r\n\r\n return { content: [{ type: 'text' as const, text: lines.join('\\n') }] };\r\n },\r\n );\r\n\r\n // ── memorix_handoff (Phase 4b: structured agent-to-agent context transfer) ──\r\n server.registerTool(\r\n 'memorix_handoff',\r\n {\r\n title: 'Team Handoff — Agent Context Transfer',\r\n description:\r\n 'Create a structured handoff artifact when passing work to another agent. ' +\r\n 'The handoff is stored as a durable observation (searchable, immune to archival) ' +\r\n 'and a notification message is sent to the recipient. ' +\r\n 'Use this when completing a task and another agent should continue, ' +\r\n 'or when you want to leave context for whoever works on this next.',\r\n inputSchema: {\r\n fromAgentId: z.string().describe('Your agent ID (from team_manage join or session_start with joinTeam=true)'),\r\n summary: z.string().describe('Human-readable summary of what you did and what needs to happen next'),\r\n context: z.string().describe('Detailed context for the next agent: what was done, current state, known issues, next steps'),\r\n toAgentId: z.string().optional().describe('Specific recipient agent ID. Omit to broadcast to all.'),\r\n taskId: z.string().optional().describe('Link to a specific team_task ID'),\r\n filesModified: z.array(z.string()).optional().describe('Files you modified during this work'),\r\n concepts: z.array(z.string()).optional().describe('Key concepts for search discoverability'),\r\n },\r\n },\r\n async ({ fromAgentId, summary, context, toAgentId, taskId, filesModified, concepts }) => {\r\n const { createHandoffArtifact } = await import('./team/handoff.js');\r\n\r\n const result = await createHandoffArtifact(\r\n {\r\n projectId: project.id,\r\n fromAgentId,\r\n toAgentId,\r\n taskId,\r\n summary,\r\n context,\r\n filesModified: filesModified ? coerceStringArray(filesModified) : undefined,\r\n concepts: concepts ? coerceStringArray(concepts) : undefined,\r\n },\r\n storeObservation,\r\n teamStore,\r\n );\r\n\r\n const lines = [\r\n `[OK] Handoff created`,\r\n `Observation: #${result.observationId}`,\r\n `From: ${result.fromAgentId.slice(0, 8)}…`,\r\n result.toAgentId ? `To: ${result.toAgentId.slice(0, 8)}…` : 'To: broadcast (any agent)',\r\n result.taskId ? `Task: ${result.taskId.slice(0, 8)}…` : '',\r\n `Summary: ${result.summary}`,\r\n '',\r\n 'The handoff context is now stored as a durable observation (searchable via memorix_search).',\r\n result.toAgentId\r\n ? 'A notification message has been sent to the recipient.'\r\n : 'A broadcast notification has been sent to all agents.',\r\n ];\r\n\r\n return { content: [{ type: 'text' as const, text: lines.filter(Boolean).join('\\n') }] };\r\n },\r\n );\r\n server.registerTool(\r\n 'memorix_ingest_image',\r\n {\r\n title: 'Ingest Image',\r\n description:\r\n 'Analyze an image via Vision LLM and store the analysis as a memory observation. ' +\r\n 'Returns description, tags, and entities extracted from the image.',\r\n inputSchema: {\r\n base64: z.string().describe('Base64-encoded image data'),\r\n mimeType: z.string().optional().describe('Image MIME type (e.g. image/png, image/jpeg)'),\r\n filename: z.string().optional().describe('Original filename'),\r\n prompt: z.string().optional().describe('Custom analysis prompt'),\r\n },\r\n },\r\n async (args) => {\r\n try {\r\n const { analyzeImage } = await import('./multimodal/image-loader.js');\r\n const analysis = await analyzeImage(args);\r\n const entityName = args.filename?.replace(/\\.[^.]+$/, '') ?? `image-${Date.now()}`;\r\n markInternalWrite();\r\n const { observation } = await storeObservation({\r\n entityName,\r\n type: 'discovery',\r\n title: `Image analysis: ${entityName}`,\r\n narrative: analysis.description,\r\n concepts: analysis.tags,\r\n facts: analysis.entities,\r\n projectId: project.id,\r\n });\r\n return {\r\n content: [{\r\n type: 'text' as const,\r\n text: `\\uD83D\\uDDBC\\uFE0F Image analyzed\\n` +\r\n `Observation #${observation.id}\\n` +\r\n `Tags: ${analysis.tags.join(', ') || 'none'}\\n` +\r\n `Preview: ${analysis.description.slice(0, 300)}${analysis.description.length > 300 ? '\\u2026' : ''}`,\r\n }],\r\n };\r\n } catch (err: unknown) {\r\n return {\r\n content: [{\r\n type: 'text' as const,\r\n text: `[ERROR] Image ingestion failed: ${err instanceof Error ? err.message : String(err)}`,\r\n }],\r\n isError: true,\r\n };\r\n }\r\n },\r\n );\r\n // Deferred initialization — runs AFTER transport connect so MCP handshake isn't blocked.\r\n // Sync advisory scan and file watcher are non-essential for tool functionality.\r\n const deferredInit = async () => {\r\n // Check hook installation status and guide user\r\n try {\r\n const { getHookStatus } = await import('./hooks/installers/index.js');\r\n const workDir = cwd ?? process.cwd();\r\n const statuses = await getHookStatus(workDir);\r\n const installedAgents = statuses.filter((s) => s.installed).map((s) => s.agent);\r\n\r\n if (installedAgents.length === 0) {\r\n console.error('[memorix] No hooks installed. Run \"memorix hooks install\" to set up auto-capture.');\r\n } else {\r\n console.error(`[memorix] Hooks active: ${installedAgents.join(', ')}`);\r\n }\r\n } catch { /* skip */ }\r\n\r\n // Git auto-hook: install post-commit hook if memorix.yml has git.autoHook: true\r\n // Uses worktree-safe hook path resolution (.git may be a file in worktree setups)\r\n try {\r\n const { getGitConfig } = await import('./config.js');\r\n const gitCfg = getGitConfig();\r\n if (gitCfg.autoHook && project.rootPath) {\r\n const { ensureHooksDir } = await import('./git/hooks-path.js');\r\n const resolved = ensureHooksDir(project.rootPath);\r\n if (resolved) {\r\n const { existsSync, readFileSync, writeFileSync, chmodSync } = await import('node:fs');\r\n const { hookPath } = resolved;\r\n const HOOK_MARKER = '# [memorix-git-hook]';\r\n const needsInstall = !existsSync(hookPath) || !readFileSync(hookPath, 'utf-8').includes(HOOK_MARKER);\r\n if (needsInstall) {\r\n const hookScript = `#!/bin/sh\\n${HOOK_MARKER}\\n# Memorix: Auto-ingest git commits as memories\\nif command -v memorix >/dev/null 2>&1; then\\n memorix ingest commit --auto >/dev/null 2>&1 &\\nfi\\n`;\r\n if (existsSync(hookPath)) {\r\n const existing = readFileSync(hookPath, 'utf-8');\r\n writeFileSync(hookPath, existing.trimEnd() + '\\n\\n' + `${HOOK_MARKER}\\nif command -v memorix >/dev/null 2>&1; then\\n memorix ingest commit --auto >/dev/null 2>&1 &\\nfi\\n`, 'utf-8');\r\n } else {\r\n writeFileSync(hookPath, hookScript, 'utf-8');\r\n }\r\n try { chmodSync(hookPath, 0o755); } catch { /* Windows */ }\r\n console.error('[memorix] Auto-installed git post-commit hook (git.autoHook: true)');\r\n }\r\n }\r\n }\r\n } catch { /* git auto-hook is best-effort */ }\r\n\r\n // Read behavior config\r\n let behaviorConfig: { syncAdvisory: boolean; autoCleanup: boolean } = { syncAdvisory: true, autoCleanup: true };\r\n try {\r\n const { getBehaviorConfig } = await import('./config/behavior.js');\r\n behaviorConfig = getBehaviorConfig();\r\n } catch { /* defaults */ }\r\n\r\n // Sync advisory: compute once, show on first memorix_search\r\n if (!behaviorConfig.syncAdvisory) {\r\n console.error('[memorix] Sync advisory disabled via config.');\r\n } else try {\r\n const engine = new WorkspaceSyncEngine(project.rootPath);\r\n const scan = await engine.scan();\r\n const lines: string[] = [];\r\n\r\n const totalMCP = Object.values(scan.mcpConfigs).reduce((sum, arr) => sum + arr.length, 0);\r\n const totalSkills = scan.skills.length;\r\n const totalRules = scan.rulesCount;\r\n const totalWorkflows = scan.workflows.length;\r\n\r\n if (totalMCP > 0 || totalSkills > 0 || totalRules > 0 || totalWorkflows > 0) {\r\n lines.push('', '---', '[UPDATED] **Cross-Agent Sync Available**');\r\n for (const [agent, servers] of Object.entries(scan.mcpConfigs)) {\r\n const list = servers as MCPServerEntry[];\r\n if (list.length > 0) {\r\n lines.push(`- **${agent}** MCP: ${list.map(s => s.name).join(', ')}`);\r\n }\r\n }\r\n if (totalSkills > 0) {\r\n const byAgent = new Map<string, string[]>();\r\n for (const sk of scan.skills) {\r\n const arr = byAgent.get(sk.sourceAgent) || [];\r\n arr.push(sk.name);\r\n byAgent.set(sk.sourceAgent, arr);\r\n }\r\n for (const [agent, names] of byAgent) {\r\n lines.push(`- **${agent}** skills: ${names.join(', ')}`);\r\n }\r\n }\r\n if (scan.skillConflicts.length > 0) lines.push(` [WARN] ${scan.skillConflicts.length} name conflict(s)`);\r\n if (totalRules > 0) lines.push(`- **${totalRules} rule(s)** found`);\r\n if (totalWorkflows > 0) lines.push(`- **${totalWorkflows} workflow(s)** found`);\r\n lines.push('');\r\n lines.push('[WARN] IMPORTANT INSTRUCTIONS FOR AI AGENT:');\r\n lines.push('1. Tell the user what configs/skills are available from other agents (list them).');\r\n lines.push('2. Ask which ones they want to sync.');\r\n lines.push('3. DO NOT manually copy files or run shell commands to sync.');\r\n lines.push('4. ONLY use `memorix_workspace_sync action=\"apply\" target=\"<agent>\"` to sync all,');\r\n lines.push(' or add `items=[\"name1\",\"name2\"]` to sync specific items selectively.');\r\n syncAdvisory = lines.join('\\n');\r\n }\r\n console.error(`[memorix] Sync advisory: ${syncAdvisory ? 'available' : 'nothing to sync'}`);\r\n } catch { /* sync scan is optional */ }\r\n\r\n // ── Background retention cleanup ────────────────────────────────\r\n // Archive expired memories automatically so users never need to run it manually.\r\n // Respects behavior.autoCleanup config (defaults to true).\r\n if (!behaviorConfig.autoCleanup) {\r\n console.error('[memorix] Auto-cleanup disabled via config.');\r\n } else {\r\n try {\r\n const { archiveExpired } = await import('./memory/retention.js');\r\n const archiveResult = await archiveExpired(projectDir);\r\n if (archiveResult.archived > 0) {\r\n console.error(`[memorix] Auto-archived ${archiveResult.archived} expired observation(s)`);\r\n }\r\n } catch { /* retention cleanup is optional */ }\r\n\r\n // ── Background consolidation ─────────────────────────────────────\r\n // With LLM: semantic dedup (higher quality). Without: Jaccard similarity.\r\n // Users who configure an API key want quality — each call is only ~500 tokens.\r\n try {\r\n if (isLLMEnabled()) {\r\n const { getAllObservations, resolveObservations } = await import('./memory/observations.js');\r\n const { deduplicateMemory } = await import('./llm/memory-manager.js');\r\n const allObs = await withFreshIndex(() => getAllObservations().filter(o => (o.status ?? 'active') === 'active' && o.projectId === project.id));\r\n if (allObs.length > 10) {\r\n const grouped = new Map<string, typeof allObs>();\r\n for (const obs of allObs) {\r\n const key = `${obs.entityName}::${obs.type}`;\r\n if (!grouped.has(key)) grouped.set(key, []);\r\n grouped.get(key)!.push(obs);\r\n }\r\n const toResolve: number[] = [];\r\n // Cap total LLM dedup calls per session to avoid runaway API usage\r\n const MAX_DEDUP_CALLS = 15;\r\n let dedupCalls = 0;\r\n for (const [, group] of grouped) {\r\n if (group.length < 2 || dedupCalls >= MAX_DEDUP_CALLS) continue;\r\n group.sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime());\r\n for (let i = 0; i < group.length - 1 && i < 3 && dedupCalls < MAX_DEDUP_CALLS; i++) {\r\n try {\r\n dedupCalls++;\r\n const older = group[i], newer = group[i + 1];\r\n const decision = await withTimeout(\r\n deduplicateMemory(\r\n { title: newer.title, narrative: newer.narrative, facts: newer.facts },\r\n [{ id: older.id, title: older.title, narrative: older.narrative, facts: older.facts.join('\\n') }],\r\n ),\r\n DEDUP_PER_PAIR_TIMEOUT_MS,\r\n `Dedup pair #${older.id}↔#${newer.id}`,\r\n );\r\n if (decision && (decision.action === 'UPDATE' || decision.action === 'NONE')) {\r\n toResolve.push(decision.action === 'UPDATE' ? older.id : newer.id);\r\n } else if (decision?.action === 'DELETE' && decision.targetId) {\r\n toResolve.push(decision.targetId);\r\n }\r\n } catch { /* skip individual comparison errors or timeouts */ }\r\n }\r\n }\r\n if (toResolve.length > 0) {\r\n await resolveObservations([...new Set(toResolve)], 'resolved');\r\n console.error(`[memorix] Auto-dedup (LLM): resolved ${toResolve.length} redundant observation(s)`);\r\n }\r\n }\r\n } else {\r\n const { executeConsolidation } = await import('./memory/consolidation.js');\r\n const result = await executeConsolidation(projectDir, project.id, { threshold: 0.55 });\r\n if (result.observationsMerged > 0) {\r\n console.error(`[memorix] Auto-consolidated: merged ${result.observationsMerged} duplicate(s) across ${result.clustersFound} cluster(s)`);\r\n }\r\n }\r\n } catch { /* consolidation is optional */ }\r\n } // end autoCleanup\r\n\r\n // ── Vector-missing observability & background backfill ──────────\r\n // Log how many observations are missing embeddings (search quality degradation).\r\n // If any are missing and embedding is available, attempt background backfill.\r\n // A periodic timer retries every 60s so provider recovery actually helps.\r\n try {\r\n const { getVectorStatus, backfillVectorEmbeddings } = await import('./memory/observations.js');\r\n const { isEmbeddingExplicitlyDisabled } = await import('./embedding/provider.js');\r\n\r\n const runBackfill = async (label: string) => {\r\n const vs = getVectorStatus();\r\n if (vs.missing === 0 || isEmbeddingExplicitlyDisabled()) return;\r\n if (label === 'init') {\r\n console.error(`[memorix] Vector status: ${vs.missing}/${vs.total} observations missing embeddings`);\r\n }\r\n try {\r\n const result = await backfillVectorEmbeddings();\r\n if (result.succeeded > 0) {\r\n console.error(`[memorix] Vector backfill (${label}): ${result.succeeded}/${result.attempted} embeddings recovered`);\r\n }\r\n if (result.failed > 0 && label === 'init') {\r\n console.error(`[memorix] Vector backfill: ${result.failed} failed (periodic retry active)`);\r\n }\r\n } catch { /* best-effort */ }\r\n };\r\n\r\n // Initial backfill attempt (non-blocking)\r\n runBackfill('init');\r\n\r\n // Periodic retry: every 60s, check if there are still missing vectors\r\n // Stops automatically when all vectors are backfilled or embedding is disabled\r\n const BACKFILL_INTERVAL_MS = 60_000;\r\n const backfillTimer = setInterval(async () => {\r\n const vs = getVectorStatus();\r\n if (vs.missing === 0 || isEmbeddingExplicitlyDisabled()) {\r\n clearInterval(backfillTimer);\r\n return;\r\n }\r\n await runBackfill('periodic');\r\n }, BACKFILL_INTERVAL_MS);\r\n // Don't keep the process alive just for backfill\r\n if (backfillTimer.unref) backfillTimer.unref();\r\n } catch { /* vector observability is optional */ }\r\n\r\n // Watch for external writes (e.g., from hook processes) and hot-reload.\r\n // Uses watchFile (polling) instead of watch because atomicWriteFile uses\r\n // rename(), which changes the file inode — fs.watch loses track on Windows.\r\n const observationsFile = projectDir + '/observations.json';\r\n let reloadDebounce: ReturnType<typeof setTimeout> | null = null;\r\n let reloading = false; // guard: skip if a reload is already in progress\r\n // lastInternalWriteMs + markInternalWrite are module-level (see top of file)\r\n try {\r\n watchFile(observationsFile, { interval: 5000 }, (curr, prev) => {\r\n if (curr.mtimeMs === prev.mtimeMs) return; // no actual change\r\n // Skip reload if a MCP tool wrote recently — data is already in memory\r\n if (Date.now() - lastInternalWriteMs < 10_000) return;\r\n if (reloading) return; // skip — previous reload still running\r\n if (reloadDebounce) clearTimeout(reloadDebounce);\r\n reloadDebounce = setTimeout(async () => {\r\n if (reloading) return;\r\n reloading = true;\r\n try {\r\n await resetDb();\r\n await initObservationStore(projectDir);\r\n await initObservations(projectDir);\r\n const count = await prepareSearchIndex();\r\n if (count > 0) {\r\n console.error(`[memorix] Hot-reloaded search index for ${count} observations (external write detected)`);\r\n }\r\n } catch { /* silent */ }\r\n reloading = false;\r\n }, 3000);\r\n });\r\n console.error(`[memorix] Watching for external writes (hooks hot-reload enabled)`);\r\n } catch {\r\n console.error(`[memorix] Warning: could not watch observations file for hot-reload`);\r\n }\r\n };\r\n\r\n // Runtime project switch — called when MCP roots change, projectRoot binding, or new workspace detected.\r\n // Updates all mutable state; tool closures automatically pick up new values.\r\n const switchProject = async (newCwd: string): Promise<boolean> => {\r\n const { detectProjectWithDiagnostics } = await import('./project/detector.js');\r\n const result = detectProjectWithDiagnostics(newCwd);\r\n if (!result.project) {\r\n if (result.failure) {\r\n console.error(`[memorix] Project detection failed for \"${newCwd}\": [${result.failure.reason}] ${result.failure.detail}`);\r\n }\r\n return false;\r\n }\r\n const newDetected = result.project;\r\n\r\n // Resolve data dir FIRST (was buggy: used before declaration)\r\n const newProjectDir = await getProjectDataDir(newDetected.id);\r\n initAliasRegistry(newProjectDir);\r\n const newCanonicalId = await registerAlias(newDetected);\r\n\r\n // Allow switch if: different project OR current project is unresolved (__unresolved__)\r\n if (newCanonicalId === project.id && projectResolved) return false; // same project, no-op\r\n\r\n console.error(`[memorix] Switching project: ${project.id} → ${newCanonicalId}`);\r\n\r\n // Phase 4a: clear agent identity — old project's agent is not valid in new project\r\n currentAgentId = undefined;\r\n\r\n // Re-resolve data dir with canonical ID (may differ from raw detected ID)\r\n const canonicalProjectDir = newCanonicalId !== newDetected.id\r\n ? await getProjectDataDir(newCanonicalId)\r\n : newProjectDir;\r\n\r\n // Update mutable state — all tool closures reference these by closure\r\n projectResolved = true;\r\n projectResolutionError = null;\r\n project = { ...newDetected, id: newCanonicalId };\r\n projectDir = canonicalProjectDir;\r\n\r\n // Update YAML config root and reload .env for the new project\r\n try {\r\n const { initProjectRoot } = await import('./config/yaml-loader.js');\r\n initProjectRoot(project.rootPath);\r\n const { resetDotenv, loadDotenv } = await import('./config/dotenv-loader.js');\r\n resetDotenv();\r\n loadDotenv(project.rootPath);\r\n } catch { /* best-effort */ }\r\n\r\n // Reinitialize TeamStore for the new project (per-project isolation)\r\n // In HTTP mode, the shared TeamStore from serve-http is replaced with\r\n // a project-specific one. In stdio mode, a fresh one is created.\r\n try {\r\n if (!initTeamStoreForProject) throw new Error('Team store init unavailable');\r\n if (sharedTeam?.teamStore) {\r\n // HTTP mode: check if the new projectDir already has a cached TeamStore\r\n // For now, reinitialize since the sharedTeam was for the original project\r\n teamStore = await initTeamStoreForProject(canonicalProjectDir);\r\n // Re-attach EventBus if available\r\n if (!teamStore.getEventBus()) {\r\n const { TeamEventBus } = await import('./team/event-bus.js');\r\n teamStore.setEventBus(new TeamEventBus());\r\n }\r\n } else {\r\n // Stdio mode: always reinitialize\r\n teamStore = await initTeamStoreForProject(canonicalProjectDir);\r\n }\r\n } catch { /* best-effort - Agent Team features degrade gracefully */ }\r\n\r\n await initializeProjectRuntime('switch');\r\n return true;\r\n };\r\n\r\n const handleTransportClose = (): void => {\r\n const agentId = currentAgentId;\r\n currentAgentId = undefined;\r\n if (!teamFeaturesEnabled || !agentId) return;\r\n\r\n try {\r\n teamStore.leaveAgent(agentId);\r\n teamStore.releaseAllLocks(agentId);\r\n teamStore.releaseTasksByAgent(agentId);\r\n } catch { /* best-effort cleanup on transport close */ }\r\n };\r\n\r\n return {\r\n server, graphManager, projectId: project.id, deferredInit, switchProject,\r\n isExplicitlyBound: () => explicitProjectBound,\r\n handleTransportClose,\r\n };\r\n}\r\n","/**\r\n * Attribution Guard\r\n *\r\n * Detects when a write's entityName is better known in a different project than\r\n * the currently bound session project. Used to:\r\n *\r\n * 1. Emit a passive warning on memorix_store / memorix_store_reasoning when a\r\n * suspicious attribution is detected (Goal A — prevent new wrong-bucket writes).\r\n * 2. Scan an existing project for already-misattributed observations so an\r\n * operator can archive/move them (Goal B — legacy cleanup audit).\r\n *\r\n * Both functions are alias-aware: projectIds are normalised to their canonical\r\n * form via the alias registry before any comparison, so the same physical repo\r\n * seen under multiple aliases is never mis-counted as two separate projects.\r\n *\r\n * Detection heuristic (low false-positive):\r\n * suspicious = entityName appears 0× in currentProject AND ≥ threshold× in\r\n * exactly one other canonical project.\r\n */\r\n\r\nimport type { Observation } from '../types.js';\r\nimport { getCanonicalId, resolveAliases } from '../project/aliases.js';\r\n\r\n/** Default minimum occurrence count in another project to trigger suspicion. */\r\nconst DEFAULT_THRESHOLD = 2;\r\n\r\n// ── Shared helpers ─────────────────────────────────────────────────────────\r\n\r\n/**\r\n * Resolve every unique projectId found in the observation list to its canonical\r\n * form. Returns a Map<rawProjectId, canonicalId>.\r\n * Best-effort: if alias registry is unavailable for a given ID, falls back to\r\n * the raw projectId so the guard degrades gracefully.\r\n */\r\nasync function buildCanonicalMap(\r\n obs: Observation[],\r\n): Promise<Map<string, string>> {\r\n const uniqueIds = [...new Set(obs.map((o) => o.projectId).filter(Boolean))];\r\n const map = new Map<string, string>();\r\n await Promise.all(\r\n uniqueIds.map(async (pid) => {\r\n try {\r\n map.set(pid, await getCanonicalId(pid));\r\n } catch {\r\n map.set(pid, pid);\r\n }\r\n }),\r\n );\r\n return map;\r\n}\r\n\r\n/**\r\n * Build a two-level count map:\r\n * canonical projectId → entityName → occurrence count\r\n * Only active observations are counted.\r\n */\r\nfunction buildEntityCountMap(\r\n obs: Observation[],\r\n canonicalMap: Map<string, string>,\r\n): Map<string, Map<string, number>> {\r\n const result = new Map<string, Map<string, number>>();\r\n for (const o of obs) {\r\n if ((o.status ?? 'active') !== 'active') continue;\r\n if (!o.entityName) continue;\r\n const canonical = canonicalMap.get(o.projectId) ?? o.projectId;\r\n if (!result.has(canonical)) result.set(canonical, new Map());\r\n const inner = result.get(canonical)!;\r\n inner.set(o.entityName, (inner.get(o.entityName) ?? 0) + 1);\r\n }\r\n return result;\r\n}\r\n\r\n// ── Goal A: write-time passive check ──────────────────────────────────────\r\n\r\nexport interface AttributionResult {\r\n /** True when the entity is unseen in the current project but well-known in another. */\r\n suspicious: boolean;\r\n /** Canonical projectId where the entity actually lives (present when suspicious). */\r\n knownIn?: string;\r\n /** How many times the entity appears in knownIn (present when suspicious). */\r\n count?: number;\r\n /** 'high' when count ≥ 5, otherwise 'low'. */\r\n confidence?: 'high' | 'low';\r\n /** Human-readable explanation (present when suspicious). */\r\n reason?: string;\r\n}\r\n\r\n/**\r\n * Check whether entityName is anomalous for the current session's project.\r\n *\r\n * Alias-aware: both currentProjectId and the projectIds stored in observations\r\n * are resolved to canonical IDs before comparison.\r\n *\r\n * @param entityName The entity being written.\r\n * @param currentProjectId The session's bound project (may be a raw/alias ID).\r\n * @param allObservations Snapshot from getAllObservations() (passed in to avoid\r\n * circular imports and to allow easy unit testing).\r\n * @param threshold Minimum occurrences in another project to flag (default 2).\r\n */\r\nexport async function checkProjectAttribution(\r\n entityName: string,\r\n currentProjectId: string,\r\n allObservations: Observation[],\r\n threshold = DEFAULT_THRESHOLD,\r\n): Promise<AttributionResult> {\r\n let currentCanonical: string;\r\n try {\r\n currentCanonical = await getCanonicalId(currentProjectId);\r\n } catch {\r\n currentCanonical = currentProjectId;\r\n }\r\n\r\n const canonicalMap = await buildCanonicalMap(allObservations);\r\n const entityCounts = buildEntityCountMap(allObservations, canonicalMap);\r\n\r\n const currentCount =\r\n entityCounts.get(currentCanonical)?.get(entityName) ?? 0;\r\n\r\n if (currentCount > 0) {\r\n return { suspicious: false };\r\n }\r\n\r\n // Only flag when there is a unique alternative project above threshold.\r\n // If multiple other projects qualify, attribution is ambiguous and we avoid\r\n // emitting a misleading warning.\r\n const qualifyingTargets: Array<{ canonical: string; count: number }> = [];\r\n for (const [canonical, inner] of entityCounts) {\r\n if (canonical === currentCanonical) continue;\r\n const count = inner.get(entityName) ?? 0;\r\n if (count >= threshold) {\r\n qualifyingTargets.push({ canonical, count });\r\n }\r\n }\r\n\r\n if (qualifyingTargets.length !== 1) {\r\n return { suspicious: false };\r\n }\r\n\r\n const [{ canonical: targetCanonical, count: targetCount }] = qualifyingTargets;\r\n\r\n return {\r\n suspicious: true,\r\n knownIn: targetCanonical,\r\n count: targetCount,\r\n confidence: targetCount >= 5 ? 'high' : 'low',\r\n reason:\r\n `Entity \"${entityName}\" has 0 observations in \"${currentCanonical}\" ` +\r\n `but ${targetCount} in \"${targetCanonical}\"`,\r\n };\r\n}\r\n\r\n// ── Goal B: legacy audit scan ─────────────────────────────────────────────\r\n\r\nexport interface AuditEntry {\r\n /** Observation ID. */\r\n id: number;\r\n /** Raw projectId stored on the observation (may differ from canonical). */\r\n projectId: string;\r\n entityName: string;\r\n title: string;\r\n /** Memory source: 'agent' | 'git' | 'manual'. */\r\n source: string;\r\n /** Provenance detail: 'explicit' | 'hook' | 'git-ingest' | undefined. */\r\n sourceDetail: string | undefined;\r\n /** Canonical projectId where this entity is better known. */\r\n likelyBelongsTo: string;\r\n /** Occurrence count of entityName in likelyBelongsTo. */\r\n count: number;\r\n confidence: 'high' | 'low';\r\n}\r\n\r\n/**\r\n * Scan all active observations belonging to currentProjectId (including aliases)\r\n * and return those whose entityName is suspicious — i.e., not seen elsewhere in\r\n * the same project but well-known in a different canonical project.\r\n *\r\n * @param currentProjectId The session's bound project (may be raw/alias ID).\r\n * @param allObservations Full observation list from getAllObservations().\r\n * @param threshold Minimum occurrences in another project to flag (default 2).\r\n */\r\nexport async function auditProjectObservations(\r\n currentProjectId: string,\r\n allObservations: Observation[],\r\n threshold = DEFAULT_THRESHOLD,\r\n): Promise<AuditEntry[]> {\r\n // Resolve current project aliases — we scan obs stored under ANY alias\r\n let currentAliases: string[];\r\n let currentCanonical: string;\r\n try {\r\n currentAliases = await resolveAliases(currentProjectId);\r\n currentCanonical = await getCanonicalId(currentProjectId);\r\n } catch {\r\n currentAliases = [currentProjectId];\r\n currentCanonical = currentProjectId;\r\n }\r\n const aliasSet = new Set(currentAliases);\r\n\r\n const activeObs = allObservations.filter(\r\n (o) => (o.status ?? 'active') === 'active',\r\n );\r\n\r\n // Build global canonical map and entity count map once\r\n const canonicalMap = await buildCanonicalMap(activeObs);\r\n const entityCounts = buildEntityCountMap(activeObs, canonicalMap);\r\n\r\n // Observations belonging to the current project (any alias)\r\n const projectObs = activeObs.filter((o) => aliasSet.has(o.projectId));\r\n\r\n const entries: AuditEntry[] = [];\r\n\r\n for (const obs of projectObs) {\r\n if (!obs.entityName) continue;\r\n\r\n const currentCount =\r\n entityCounts.get(currentCanonical)?.get(obs.entityName) ?? 0;\r\n\r\n if (currentCount > 1) continue; // entity is meaningfully present → skip\r\n\r\n // Only emit an audit entry when there is a unique alternative target.\r\n // Multiple qualifying projects is ambiguous and should not become a\r\n // misleading \"likely belongs to\" suggestion.\r\n const qualifyingTargets: Array<{ canonical: string; count: number }> = [];\r\n for (const [canonical, inner] of entityCounts) {\r\n if (canonical === currentCanonical) continue;\r\n const count = inner.get(obs.entityName) ?? 0;\r\n if (count >= threshold) {\r\n qualifyingTargets.push({ canonical, count });\r\n }\r\n }\r\n\r\n if (qualifyingTargets.length !== 1) continue;\r\n\r\n const [{ canonical: targetCanonical, count: targetCount }] = qualifyingTargets;\r\n\r\n entries.push({\r\n id: obs.id,\r\n projectId: obs.projectId,\r\n entityName: obs.entityName,\r\n title: obs.title,\r\n source: obs.source ?? 'agent',\r\n sourceDetail: obs.sourceDetail,\r\n likelyBelongsTo: targetCanonical,\r\n count: targetCount,\r\n confidence: targetCount >= 5 ? 'high' : 'low',\r\n });\r\n }\r\n\r\n return entries;\r\n}\r\n","/**\r\n * Auto-Relation Creator\r\n *\r\n * Automatically creates Knowledge Graph relations from entity extraction.\r\n * Inspired by mcp-memory-service's typed relationships and MemCP's MAGMA 4-graph.\r\n *\r\n * When an observation is stored:\r\n * 1. Extract entities from narrative (files, modules, CamelCase)\r\n * 2. Find matching existing entities in the graph\r\n * 3. Auto-create relations: \"references\", \"modifies\", or \"causes\" (if causal)\r\n *\r\n * This is \"implicit memory\" — the agent doesn't need to call create_relations.\r\n */\r\n\r\nimport type { Observation, Relation } from '../types.js';\r\nimport type { KnowledgeGraphManager } from './graph.js';\r\nimport type { ExtractedEntities } from './entity-extractor.js';\r\n\r\n/**\r\n * Infer relation type based on observation type and causal language.\r\n */\r\nfunction inferRelationType(obs: Observation): string {\r\n if (obs.hasCausalLanguage) return 'causes';\r\n\r\n switch (obs.type) {\r\n case 'problem-solution':\r\n return 'fixes';\r\n case 'decision':\r\n case 'trade-off':\r\n return 'decides';\r\n case 'what-changed':\r\n return 'modifies';\r\n case 'gotcha':\r\n return 'warns_about';\r\n default:\r\n return 'references';\r\n }\r\n}\r\n\r\n/**\r\n * Auto-create relations from a stored observation.\r\n *\r\n * Scans the knowledge graph for entities matching extracted file names,\r\n * modules, and identifiers, then creates typed relations.\r\n *\r\n * Returns the number of relations created.\r\n */\r\nexport async function createAutoRelations(\r\n obs: Observation,\r\n extracted: ExtractedEntities,\r\n graphManager: KnowledgeGraphManager,\r\n): Promise<number> {\r\n const relationType = inferRelationType(obs);\r\n const relations: Relation[] = [];\r\n\r\n // Skip self-references\r\n const selfName = obs.entityName.toLowerCase();\r\n\r\n // Check extracted identifiers against existing entities (O(1) lookups via index)\r\n const candidates = [\r\n ...extracted.identifiers,\r\n ...extracted.files.map((f) => f.split('/').pop()?.replace(/\\.\\w+$/, '') ?? ''),\r\n ...extracted.modules.map((m) => m.split(/[./]/).pop() ?? ''),\r\n ].filter((c) => c.length >= 3);\r\n\r\n for (const candidate of candidates) {\r\n const lower = candidate.toLowerCase();\r\n if (lower === selfName) continue;\r\n\r\n const matchedEntity = graphManager.findEntityByName(candidate);\r\n if (matchedEntity) {\r\n relations.push({\r\n from: obs.entityName,\r\n to: matchedEntity.name,\r\n relationType,\r\n });\r\n }\r\n }\r\n\r\n // Also create relations from explicit filesModified → existing entities\r\n for (const file of obs.filesModified) {\r\n const basename = file.split('/').pop()?.replace(/\\.\\w+$/, '') ?? '';\r\n if (basename.length < 3 || basename.toLowerCase() === selfName) continue;\r\n\r\n const matchedEntity = graphManager.findEntityByName(basename);\r\n if (matchedEntity) {\r\n relations.push({\r\n from: obs.entityName,\r\n to: matchedEntity.name,\r\n relationType: 'modifies',\r\n });\r\n }\r\n }\r\n\r\n if (relations.length === 0) return 0;\r\n\r\n // Deduplicate\r\n const unique = relations.filter(\r\n (r, i, arr) =>\r\n arr.findIndex(\r\n (o) => o.from === r.from && o.to === r.to && o.relationType === r.relationType,\r\n ) === i,\r\n );\r\n\r\n const created = await graphManager.createRelations(unique);\r\n return created.length;\r\n}\r\n","/**\r\n * Compact Engine\r\n *\r\n * Orchestrates the 3-layer Progressive Disclosure workflow.\r\n * Source: claude-mem's proven architecture (27K stars, ~10x token savings).\r\n *\r\n * Layer 1 (search) → Compact index with IDs (~50-100 tokens/result)\r\n * Layer 2 (timeline) → Chronological context around an observation\r\n * Layer 3 (detail) → Full observation content (~500-1000 tokens/result)\r\n */\r\n\r\nimport type { SearchOptions, IndexEntry, TimelineContext, MemorixDocument, ObservationRef, MemoryRef, MiniSkill, SourceSnapshot } from '../types.js';\r\nimport { searchObservations, getTimeline, getObservationsByIds, makeOramaObservationId } from '../store/orama-store.js';\r\nimport { getObservation, getAllObservations } from '../memory/observations.js';\r\nimport { ensureFreshIndex } from '../memory/freshness.js';\r\nimport { formatIndexTable, formatTimeline, formatObservationDetail } from './index-format.js';\r\nimport { countTextTokens } from './token-budget.js';\r\nimport { resolveAliases } from '../project/aliases.js';\r\nimport { parseMemoryRef } from '../memory/refs.js';\r\nimport { getMiniSkillStore } from '../store/mini-skill-store.js';\r\nimport { miniSkillToDocument, resolveProvenanceStatus, type ProvenanceStatus } from '../skills/mini-skills.js';\r\nimport { redactCredentials } from '../memory/secret-filter.js';\r\n\r\n/**\r\n * Layer 1: Search and return a compact index.\r\n * Agent scans this to decide which observations to fetch in detail.\r\n */\r\nexport async function compactSearch(options: SearchOptions): Promise<{\r\n entries: IndexEntry[];\r\n formatted: string;\r\n totalTokens: number;\r\n}> {\r\n const entries = await searchObservations(options);\r\n const formatted = formatIndexTable(entries, options.query, !options.projectId);\r\n const totalTokens = countTextTokens(formatted);\r\n\r\n return { entries, formatted, totalTokens };\r\n}\r\n\r\n/**\r\n * Layer 2: Get timeline context around an anchor observation.\r\n * Shows what happened before and after for temporal understanding.\r\n */\r\nexport async function compactTimeline(\r\n anchorId: number,\r\n projectId?: string,\r\n depthBefore = 3,\r\n depthAfter = 3,\r\n): Promise<{\r\n timeline: TimelineContext;\r\n formatted: string;\r\n totalTokens: number;\r\n}> {\r\n const result = await getTimeline(anchorId, projectId, depthBefore, depthAfter);\r\n\r\n const timeline: TimelineContext = {\r\n anchorId,\r\n anchorEntry: result.anchor,\r\n before: result.before,\r\n after: result.after,\r\n };\r\n\r\n const formatted = formatTimeline(timeline);\r\n const totalTokens = countTextTokens(formatted);\r\n\r\n return { timeline, formatted, totalTokens };\r\n}\r\n\r\n/**\r\n * Layer 3: Get full observation or mini-skill details by IDs or typed refs.\r\n * Only called after the agent has filtered via L1/L2.\r\n *\r\n * Phase 3a: Accepts typed MemoryRef inputs (obs:42, skill:3) alongside\r\n * legacy bare numbers and ObservationRef objects.\r\n */\r\nexport async function compactDetail(\r\n idsOrRefs: number[] | ObservationRef[] | string[],\r\n): Promise<{\r\n documents: MemorixDocument[];\r\n formatted: string;\r\n totalTokens: number;\r\n}> {\r\n // Parse all inputs into typed MemoryRefs — fail-fast on invalid refs\r\n const invalidRefs: string[] = [];\r\n const parsedRefs: MemoryRef[] = [];\r\n for (let i = 0; i < (idsOrRefs as any[]).length; i++) {\r\n const item = (idsOrRefs as any[])[i];\r\n if (typeof item === 'number') {\r\n parsedRefs.push({ kind: 'obs' as const, id: item });\r\n } else if (typeof item === 'string') {\r\n try { parsedRefs.push(parseMemoryRef(item)); } catch { invalidRefs.push(item); }\r\n } else if (item && typeof item === 'object' && 'id' in item && typeof item.id === 'number') {\r\n parsedRefs.push({ kind: 'obs' as const, id: item.id, projectId: item.projectId });\r\n } else {\r\n invalidRefs.push(String(item));\r\n }\r\n }\r\n if (invalidRefs.length > 0) {\r\n throw new Error(\r\n `Invalid memory ref(s): ${invalidRefs.map(r => `\"${r}\"`).join(', ')}. ` +\r\n `Expected: obs:<id>, skill:<id>, obs:<id>@<projectId>, or a bare number.`,\r\n );\r\n }\r\n\r\n // Tag each ref with its original position so we can reassemble in order\r\n const obsRefsIndexed = parsedRefs\r\n .map((r, i) => ({ ref: r, idx: i }))\r\n .filter((x) => x.ref.kind === 'obs');\r\n const skillRefsIndexed = parsedRefs\r\n .map((r, i) => ({ ref: r, idx: i }))\r\n .filter((x) => x.ref.kind === 'skill');\r\n\r\n // Per-slot results — keyed by original parsedRefs index\r\n const slotDoc = new Map<number, MemorixDocument>();\r\n const slotFormatted = new Map<number, string>();\r\n\r\n // --- Resolve mini-skill refs ---\r\n if (skillRefsIndexed.length > 0) {\r\n try {\r\n const store = getMiniSkillStore();\r\n const allSkills = await store.loadAll();\r\n const skillMap = new Map(allSkills.map((s) => [s.id, s]));\r\n for (const { ref, idx } of skillRefsIndexed) {\r\n const skill = skillMap.get(ref.id);\r\n if (skill) {\r\n slotDoc.set(idx, miniSkillToDocument(skill));\r\n const obsLookup = (id: number) => getObservation(id);\r\n const status = resolveProvenanceStatus(skill, obsLookup);\r\n slotFormatted.set(idx, formatMiniSkillDetail(skill, status));\r\n } else {\r\n slotFormatted.set(idx, `Mini-skill S${ref.id} not found.`);\r\n }\r\n }\r\n } catch {\r\n for (const { ref, idx } of skillRefsIndexed) {\r\n slotFormatted.set(idx, `Mini-skill S${ref.id}: store unavailable.`);\r\n }\r\n }\r\n }\r\n\r\n // --- Resolve observation refs (existing path) ---\r\n const refs: ObservationRef[] = obsRefsIndexed.map((x) => ({ id: x.ref.id, projectId: x.ref.projectId }));\r\n\r\n // Prefer in-memory observations for current-project reliability, but fall back\r\n // to the global Orama index so cross-project search results can still open.\r\n // Security: refs WITHOUT projectId are treated as ambiguous — the in-memory\r\n // lookup may return a wrong-project observation. Callers (memorix_detail tool)\r\n // should always inject projectId for bare numeric IDs.\r\n await ensureFreshIndex(); // unified freshness gate: observations + mini-skills\r\n const toRefKey = (ref: ObservationRef) => `${ref.projectId ?? ''}::${ref.id}`;\r\n const documentMap = new Map<string, MemorixDocument>();\r\n const missingRefs: ObservationRef[] = [];\r\n for (const ref of refs) {\r\n const obs = getObservation(ref.id, ref.projectId);\r\n if (obs && (ref.projectId ? obs.projectId === ref.projectId : true)) {\r\n documentMap.set(toRefKey(ref), {\r\n id: makeOramaObservationId(obs.projectId, obs.id),\r\n observationId: obs.id,\r\n entityName: obs.entityName,\r\n type: obs.type,\r\n title: obs.title,\r\n narrative: obs.narrative,\r\n facts: obs.facts.join('\\n'),\r\n filesModified: obs.filesModified.join('\\n'),\r\n concepts: obs.concepts.join(', '),\r\n tokens: obs.tokens,\r\n createdAt: obs.createdAt,\r\n projectId: obs.projectId,\r\n accessCount: 0,\r\n lastAccessedAt: '',\r\n status: obs.status ?? 'active',\r\n source: obs.source ?? 'agent',\r\n sourceDetail: obs.sourceDetail ?? '',\r\n valueCategory: obs.valueCategory ?? '',\r\n });\r\n } else {\r\n missingRefs.push(ref);\r\n }\r\n }\r\n\r\n if (missingRefs.length > 0) {\r\n for (const ref of missingRefs) {\r\n const fallbackDocs = await getObservationsByIds([ref.id], ref.projectId);\r\n const doc = fallbackDocs[0];\r\n if (doc) {\r\n documentMap.set(toRefKey(ref), doc);\r\n }\r\n }\r\n }\r\n\r\n // Build cross-reference map for all requested observations\r\n const allObs = getAllObservations();\r\n const crossRefMap = new Map<string, string[]>();\r\n for (const ref of refs) {\r\n const obs = getObservation(ref.id, ref.projectId);\r\n const doc = documentMap.get(toRefKey(ref));\r\n if (!obs && !doc) continue;\r\n const refs: string[] = [];\r\n const projectIds = obs\r\n ? new Set(await resolveAliases(obs.projectId).catch(() => [obs.projectId]))\r\n : new Set<string>(doc?.projectId ? [doc.projectId] : []);\r\n\r\n // Repository / source line\r\n if (obs?.source === 'git' && obs.commitHash) {\r\n refs.push(`Repository: commit ${obs.commitHash.substring(0, 7)}`);\r\n } else if (obs?.source && obs.source !== 'agent') {\r\n refs.push(`Source: ${obs.source}`);\r\n } else if (doc?.source && doc.source !== 'agent') {\r\n refs.push(`Source: ${doc.source}`);\r\n }\r\n\r\n if (!obs) {\r\n if (refs.length > 0 && doc) crossRefMap.set(doc.id, refs);\r\n continue;\r\n }\r\n\r\n // Cited commits (explicit relatedCommits cross-references)\r\n if (obs.relatedCommits && obs.relatedCommits.length > 0) {\r\n refs.push(`Cited commits: ${obs.relatedCommits.map(h => h.substring(0, 7)).join(', ')}`);\r\n // Auto-find git memories for those commits\r\n const gitMems = allObs.filter(o =>\r\n o.source === 'git' &&\r\n projectIds.has(o.projectId) &&\r\n o.commitHash &&\r\n obs.relatedCommits!.includes(o.commitHash),\r\n );\r\n for (const gm of gitMems) {\r\n refs.push(` → #${gm.id} [CHANGE] ${gm.title}`);\r\n }\r\n }\r\n\r\n // Explicit relatedEntities\r\n if (obs.relatedEntities && obs.relatedEntities.length > 0) {\r\n refs.push(`Related entities: ${obs.relatedEntities.join(', ')}`);\r\n }\r\n\r\n // Auto: if this is a git memory, find analysis (reasoning/decision) for same entity\r\n if (obs.source === 'git') {\r\n const analysis = allObs.filter(o =>\r\n (o.type === 'reasoning' || o.type === 'decision') &&\r\n projectIds.has(o.projectId) &&\r\n o.entityName === obs.entityName && o.id !== obs.id && o.status !== 'archived',\r\n ).slice(0, 3);\r\n if (analysis.length > 0) {\r\n refs.push('Analysis:');\r\n for (const r of analysis) {\r\n refs.push(` → #${r.id} ${r.type === 'reasoning' ? '[REASONING]' : '[DECISION]'} ${r.title}`);\r\n }\r\n }\r\n }\r\n\r\n // Auto: if this is a reasoning/decision memory, find git evidence for same entity\r\n if (obs.type === 'reasoning' || obs.type === 'decision') {\r\n const gitMems = allObs.filter(o =>\r\n o.source === 'git' &&\r\n projectIds.has(o.projectId) &&\r\n o.entityName === obs.entityName &&\r\n o.id !== obs.id &&\r\n o.status !== 'archived',\r\n ).slice(0, 3);\r\n if (gitMems.length > 0) {\r\n refs.push('Repository evidence:');\r\n for (const g of gitMems) {\r\n refs.push(` → #${g.id} [CHANGE] ${g.title}`);\r\n }\r\n }\r\n }\r\n\r\n if (refs.length > 0) crossRefMap.set(makeOramaObservationId(obs.projectId, obs.id), refs);\r\n }\r\n\r\n // Store observation results into slots by original index\r\n for (let i = 0; i < obsRefsIndexed.length; i++) {\r\n const { idx } = obsRefsIndexed[i];\r\n const ref = refs[i];\r\n const doc = documentMap.get(toRefKey(ref));\r\n if (doc) {\r\n slotDoc.set(idx, doc);\r\n const obs = getObservation(doc.observationId, doc.projectId);\r\n let detail = formatObservationDetail({\r\n ...doc,\r\n commitHash: obs?.commitHash,\r\n relatedCommits: obs?.relatedCommits,\r\n });\r\n const xrefs = crossRefMap.get(doc.id);\r\n if (xrefs && xrefs.length > 0) {\r\n detail += '\\n\\nEvidence support:\\n' + xrefs.join('\\n');\r\n }\r\n slotFormatted.set(idx, detail);\r\n }\r\n }\r\n\r\n // Reassemble in original parsedRefs order\r\n const allDocuments: MemorixDocument[] = [];\r\n const allFormattedParts: string[] = [];\r\n for (let i = 0; i < parsedRefs.length; i++) {\r\n const doc = slotDoc.get(i);\r\n const fmt = slotFormatted.get(i);\r\n if (doc) allDocuments.push(doc);\r\n if (fmt) allFormattedParts.push(fmt);\r\n }\r\n\r\n const formatted = allFormattedParts.join('\\n\\n' + '═'.repeat(50) + '\\n\\n');\r\n const totalTokens = countTextTokens(formatted);\r\n\r\n return { documents: allDocuments, formatted, totalTokens };\r\n}\r\n\r\n/**\r\n * Format a mini-skill detail view with provenance status.\r\n */\r\nfunction formatMiniSkillDetail(skill: MiniSkill, provenanceStatus: ProvenanceStatus): string {\r\n const lines: string[] = [];\r\n\r\n lines.push(`S${skill.id} core ${skill.title}`);\r\n lines.push('='.repeat(50));\r\n lines.push(`Type: promoted knowledge (mini-skill)`);\r\n lines.push(`Entity: ${skill.sourceEntity}`);\r\n lines.push(`Project: ${skill.projectId}`);\r\n lines.push(`Created: ${new Date(skill.createdAt).toLocaleString()}`);\r\n lines.push(`Used: ${skill.usedCount} time(s)`);\r\n lines.push(`Provenance: ${provenanceStatus}`);\r\n lines.push('');\r\n lines.push(`Instruction: ${redactCredentials(skill.instruction)}`);\r\n lines.push(`Trigger: ${skill.trigger}`);\r\n\r\n if (skill.facts.length > 0) {\r\n lines.push('');\r\n lines.push('Facts:');\r\n for (const fact of skill.facts) {\r\n lines.push(`- ${redactCredentials(fact)}`);\r\n }\r\n }\r\n\r\n if (skill.tags.length > 0) {\r\n lines.push('');\r\n lines.push(`Tags: ${skill.tags.join(', ')}`);\r\n }\r\n\r\n // Show source observation IDs with status\r\n if (skill.sourceObservationIds.length > 0) {\r\n lines.push('');\r\n lines.push(`Source observations: ${skill.sourceObservationIds.map(id => `#${id}`).join(', ')}`);\r\n }\r\n\r\n // Show snapshot summary if available\r\n if (skill.sourceSnapshot) {\r\n try {\r\n const snapshot: SourceSnapshot = JSON.parse(skill.sourceSnapshot);\r\n if (snapshot.observations && snapshot.observations.length > 0) {\r\n lines.push(`Snapshot: ${snapshot.observations.length} observation(s), frozen at ${new Date(snapshot.promotedAt).toLocaleString()}`);\r\n }\r\n } catch { /* malformed snapshot — skip */ }\r\n }\r\n\r\n return lines.join('\\n');\r\n}\r\n","/**\r\n * Index Formatter\r\n *\r\n * Formats search, timeline, and detail outputs for the compact engine.\r\n */\r\n\r\nimport type { IndexEntry, TimelineContext, DocumentType } from '../types.js';\r\nimport { sourceBadge, resolveSourceDetail, resolveEvidenceBasis, evidenceBasisLine } from '../memory/disclosure-policy.js';\r\nimport { redactCredentials } from '../memory/secret-filter.js';\r\n\r\n/**\r\n * Format a list of IndexEntries as a compact markdown table.\r\n */\r\nexport function formatIndexTable(entries: IndexEntry[], query?: string, forceProjectColumn = false): string {\r\n if (entries.length === 0) {\r\n return query\r\n ? `No memories found matching \"${query}\".`\r\n : 'No memories found.';\r\n }\r\n\r\n const lines: string[] = [];\r\n\r\n // Tier summary: shown when entries have mixed provenance\r\n const badges = entries.map((e) => sourceBadge(e.sourceDetail, e.source));\r\n const distinctBadges = new Set(badges.filter(Boolean));\r\n if (distinctBadges.size > 1 || (distinctBadges.size === 1 && badges.some((b) => !b))) {\r\n const exCount = badges.filter((b) => b === 'ex').length;\r\n const hkCount = badges.filter((b) => b === 'hk').length;\r\n const gitCount = badges.filter((b) => b === 'git').length;\r\n const unknownCount = badges.filter((b) => !b).length;\r\n const parts: string[] = [];\r\n if (exCount > 0) parts.push(`${exCount} explicit`);\r\n if (unknownCount > 0) parts.push(`${unknownCount} legacy`);\r\n if (hkCount > 0) parts.push(`${hkCount} hook`);\r\n if (gitCount > 0) parts.push(`${gitCount} git`);\r\n lines.push(`Sources: ${parts.join(' · ')}`);\r\n lines.push('');\r\n }\r\n\r\n if (query) {\r\n lines.push(`Found ${entries.length} observation(s) matching \"${query}\":`);\r\n lines.push('');\r\n }\r\n\r\n const distinctProjects = [...new Set(entries.map((entry) => entry.projectId).filter(Boolean))];\r\n const hasProject = forceProjectColumn || distinctProjects.length > 1;\r\n const hasExplanation = entries.some((entry) => (entry.matchedFields?.length ?? 0) > 0);\r\n // Show Src column when at least one entry has provenance (sourceDetail or legacy source='git')\r\n const hasSrc = entries.some((e) => !!e.sourceDetail || e.source === 'git');\r\n // Show Layer column when results contain mixed document types (observations + mini-skills)\r\n const distinctDocTypes = new Set(entries.map((e) => e.documentType || 'observation'));\r\n const hasLayer = distinctDocTypes.size > 1;\r\n\r\n const header = ['Ref', 'Time', 'T', 'Title', 'Tokens'];\r\n const divider = ['-----', '------', '---', '-------', '--------'];\r\n if (hasLayer) {\r\n header.push('Layer');\r\n divider.push('--------');\r\n }\r\n if (hasSrc) {\r\n header.push('Src');\r\n divider.push('---');\r\n }\r\n if (hasProject) {\r\n header.push('Project');\r\n divider.push('---------');\r\n }\r\n if (hasExplanation) {\r\n header.push('Matched');\r\n divider.push('---------');\r\n }\r\n\r\n lines.push(`| ${header.join(' | ')} |`);\r\n lines.push(`|${divider.map((part) => ` ${part} `).join('|')}|`);\r\n\r\n for (const entry of entries) {\r\n const ref = formatEntryRef(entry);\r\n const row = [ref, entry.time, entry.icon, redactCredentials(entry.title), `~${entry.tokens}`];\r\n if (hasLayer) row.push(formatLayerBadge(entry.knowledgeLayer));\r\n if (hasSrc) row.push(sourceBadge(entry.sourceDetail, entry.source) || '-');\r\n if (hasProject) row.push(entry.projectId ?? '-');\r\n if (hasExplanation) row.push(entry.matchedFields?.join(', ') ?? '-');\r\n lines.push(`| ${row.join(' | ')} |`);\r\n }\r\n\r\n lines.push('');\r\n lines.push(getProgressiveDisclosureHint(hasProject));\r\n\r\n return lines.join('\\n');\r\n}\r\n\r\n/**\r\n * Format a timeline context around an anchor observation.\r\n * When any entry carries sourceDetail provenance, adds a Src column and\r\n * annotates the anchor with its evidence kind. Falls back to the original\r\n * table format when no provenance is present (backward-compat).\r\n */\r\nexport function formatTimeline(timeline: TimelineContext): string {\r\n if (!timeline.anchorEntry) {\r\n return `Observation #${timeline.anchorId} not found.`;\r\n }\r\n\r\n const anchor = timeline.anchorEntry;\r\n\r\n // Detect provenance across all entries — conditional Src column\r\n // Includes legacy source='git' fallback.\r\n const allEntries = [...timeline.before, anchor, ...timeline.after];\r\n const hasSrc = allEntries.some((e) => !!e.sourceDetail || e.source === 'git');\r\n\r\n const tableHeader = hasSrc ? '| ID | Time | T | Title | Tokens | Src |' : '| ID | Time | T | Title | Tokens |';\r\n const tableDivider = hasSrc ? '|----|------|---|-------|--------|-----|' : '|----|------|---|-------|--------|';\r\n\r\n const entryRow = (e: IndexEntry): string => {\r\n const base = `| #${e.id} | ${e.time} | ${e.icon} | ${redactCredentials(e.title)} | ~${e.tokens} |`;\r\n return hasSrc ? `${base} ${sourceBadge(e.sourceDetail, e.source) || '-'} |` : base;\r\n };\r\n\r\n const lines: string[] = [];\r\n lines.push(`Timeline around #${timeline.anchorId}:`);\r\n\r\n // Anchor kind annotation — shown when provenance is available (sourceDetail or legacy source='git')\r\n const anchorEffectiveSource = resolveSourceDetail(anchor.sourceDetail, anchor.source);\r\n if (hasSrc && anchorEffectiveSource) {\r\n const anchorBasis = resolveEvidenceBasis({ sourceDetail: anchor.sourceDetail, source: anchor.source });\r\n const basisSuffix =\r\n anchorBasis === 'repository' ? ' — [OK] repository-backed' :\r\n anchorBasis === 'synthesized' ? ' — [SYNTHESIZED] synthesized' :\n '';\r\n lines.push(`*Expanding: ${sourceKindLabel(anchorEffectiveSource)}${basisSuffix}*`);\r\n }\r\n lines.push('');\r\n\r\n if (timeline.before.length > 0) {\r\n lines.push('**Before:**');\r\n lines.push(tableHeader);\r\n lines.push(tableDivider);\r\n for (const entry of timeline.before) {\r\n lines.push(entryRow(entry));\r\n }\r\n lines.push('');\r\n }\r\n\r\n lines.push('**Anchor:**');\r\n lines.push(tableHeader);\r\n lines.push(tableDivider);\r\n lines.push(entryRow(anchor));\r\n lines.push('');\r\n\r\n if (timeline.after.length > 0) {\r\n lines.push('**After:**');\r\n lines.push(tableHeader);\r\n lines.push(tableDivider);\r\n for (const entry of timeline.after) {\r\n lines.push(entryRow(entry));\r\n }\r\n lines.push('');\r\n }\r\n\r\n lines.push(getProgressiveDisclosureHint(false));\r\n return lines.join('\\n');\r\n}\r\n\r\n/**\r\n * Format full observation details (Layer 3).\r\n * When sourceDetail/valueCategory are present, prepends a provenance header\r\n * that clearly identifies the evidence kind before the main #ID block.\r\n * Backward-compatible: if neither field is set, output is identical to before.\r\n */\r\nexport function formatObservationDetail(doc: {\r\n observationId: number;\r\n type: string;\r\n title: string;\r\n narrative: string;\r\n facts: string;\r\n filesModified: string;\r\n concepts: string;\r\n createdAt: string;\r\n projectId: string;\r\n entityName: string;\r\n sourceDetail?: string;\r\n valueCategory?: string;\r\n source?: string;\r\n commitHash?: string;\r\n relatedCommits?: string[];\r\n}): string {\r\n const icon = getTypeIcon(doc.type);\r\n const lines: string[] = [];\r\n\r\n // Provenance header — shown before #ID when sourceDetail (or legacy source='git') is set\r\n const header = buildProvenanceHeader(doc.sourceDetail, doc.valueCategory, doc.source, doc.commitHash, doc.relatedCommits);\r\n if (header) {\r\n lines.push(header);\r\n lines.push('');\r\n }\r\n\r\n lines.push(`#${doc.observationId} ${icon} ${doc.title}`);\r\n lines.push('='.repeat(50));\r\n lines.push(`Date: ${new Date(doc.createdAt).toLocaleString()}`);\r\n lines.push(`Type: ${doc.type}`);\r\n lines.push(`Entity: ${doc.entityName}`);\r\n lines.push(`Project: ${doc.projectId}`);\r\n lines.push('');\r\n lines.push(`Narrative: ${redactCredentials(doc.narrative)}`);\r\n\r\n const facts = doc.facts ? doc.facts.split('\\n').filter(Boolean).map(redactCredentials) : [];\r\n if (facts.length > 0) {\r\n lines.push('');\r\n lines.push('Facts:');\r\n for (const fact of facts) {\r\n lines.push(`- ${fact}`);\r\n }\r\n }\r\n\r\n const files = doc.filesModified ? doc.filesModified.split('\\n').filter(Boolean) : [];\r\n if (files.length > 0) {\r\n lines.push('');\r\n lines.push('Files Modified:');\r\n for (const file of files) {\r\n lines.push(`- ${file}`);\r\n }\r\n }\r\n\r\n if (doc.concepts) {\r\n lines.push('');\r\n lines.push(`Concepts: ${doc.concepts}`);\r\n }\r\n\r\n return lines.join('\\n');\r\n}\r\n\r\n/**\r\n * Build a compact provenance header for detail output.\r\n * Returns empty string when no provenance can be resolved (backward-compat).\r\n * Supports legacy source='git' via resolveSourceDetail fallback.\r\n */\r\nfunction buildProvenanceHeader(\r\n sourceDetail?: string,\r\n valueCategory?: string,\r\n source?: string,\r\n commitHash?: string,\r\n relatedCommits?: string[],\r\n): string {\r\n const sd = resolveSourceDetail(sourceDetail, source);\r\n if (!sd) return '';\r\n\r\n const label = sourceKindLabel(sd);\r\n const layer = sd === 'git-ingest' ? 'L3 — evidence'\r\n : sd === 'hook' ? 'L1 — activity routing signal'\r\n : 'L2 — durable working context';\r\n\r\n const lines = [`${label} [${layer}]`];\r\n\r\n // Verification line — shown only for repository-backed memories\r\n const basis = resolveEvidenceBasis({ sourceDetail, source, commitHash, relatedCommits });\r\n const verificationLine = evidenceBasisLine(basis, commitHash);\r\n if (verificationLine) {\r\n lines.push(verificationLine);\r\n }\r\n\r\n if (valueCategory === 'core') {\r\n lines.push('[CORE] Core — immune to decay');\n } else if (valueCategory === 'ephemeral') {\r\n lines.push('[WARN] Ephemeral — short-lived signal');\r\n }\r\n\r\n return lines.join('\\n');\r\n}\r\n\r\n/** Short label for a resolved sourceDetail value, used in headers and timeline annotations. */\r\nfunction sourceKindLabel(sd: string): string {\r\n if (sd === 'git-ingest') return '[PIN] Git Repository Evidence';\r\n if (sd === 'hook') return '[HOOK] Hook Trace';\r\n return '[STORE] Explicit Working Memory';\r\n}\r\n\r\nfunction getTypeIcon(type: string): string {\r\n const icons: Record<string, string> = {\r\n 'session-request': '[SESSION]',\r\n 'gotcha': '[GOTCHA]',\r\n 'problem-solution': '[FIX]',\r\n 'how-it-works': '[INFO]',\r\n 'what-changed': '[CHANGE]',\r\n 'discovery': '[DISCOVERY]',\r\n 'why-it-exists': '[WHY]',\r\n 'decision': '[DECISION]',\r\n 'trade-off': '[TRADEOFF]',\r\n 'reasoning': '[REASONING]',\r\n };\r\n return icons[type] ?? '[UNKNOWN]';\r\n}\r\n\r\nfunction getProgressiveDisclosureHint(hasProject: boolean): string {\r\n const lines = [\r\n '[TIP] **Progressive Disclosure:** This index shows WHAT exists and retrieval COST.',\r\n '- Use `memorix_detail` with typed refs (obs:42, skill:3) to fetch full details',\r\n '- Use `memorix_timeline` to see chronological context around an observation',\r\n '- Critical types ([GOTCHA] gotcha, [DECISION] decision, [TRADEOFF] trade-off) are often worth fetching immediately',\r\n ];\r\n\r\n if (hasProject) {\r\n lines.push('- For global results, prefer `memorix_detail refs=[{ id, projectId }]` to avoid cross-project ID ambiguity');\r\n }\r\n\r\n return lines.join('\\n');\r\n}\r\n\r\n// ── Phase 3a display helpers ──────────────────────────────────────\r\n\r\n/** Format an entry reference as a canonical typed ref usable in memorix_detail */\r\nfunction formatEntryRef(entry: IndexEntry): string {\r\n return (entry.documentType === 'mini-skill') ? `skill:${entry.id}` : `obs:${entry.id}`;\r\n}\r\n\r\n/** Short badge for knowledge layer */\r\nfunction formatLayerBadge(layer?: string): string {\r\n if (layer === 'promoted') return 'core';\r\n if (layer === 'evidence') return 'ev';\r\n return '-';\r\n}\r\n","/**\r\n * Typed Memory Reference Protocol (Phase 3a)\r\n *\r\n * Provides a formal, unambiguous way to reference memory objects\r\n * (observations and mini-skills) across internal code and the MCP API.\r\n *\r\n * String format:\r\n * obs:42 — observation #42\r\n * skill:3 — mini-skill #3\r\n * obs:42@org/proj — observation #42 in project org/proj\r\n *\r\n * Legacy support:\r\n * 42 (bare number) → obs:42\r\n * \"42\" (bare string) → obs:42\r\n *\r\n * Display short forms (presentation only):\r\n * #42 — observation\r\n * S3 — mini-skill\r\n */\r\n\r\nimport type { MemoryRef } from '../types.js';\r\n\r\n// ── Parsing ──────────────────────────────────────────────────────\r\n\r\nconst TYPED_REF_RE = /^(obs|skill):(\\d+)(?:@(.+))?$/;\r\n\r\n/**\r\n * Parse a typed memory reference from a string or number.\r\n *\r\n * Accepts:\r\n * - \"obs:42\", \"skill:3\", \"obs:42@org/proj\"\r\n * - 42 (bare number → obs:42)\r\n * - \"42\" (bare numeric string → obs:42)\r\n *\r\n * Throws on invalid input.\r\n */\r\nexport function parseMemoryRef(input: string | number): MemoryRef {\r\n // Bare number → legacy observation ref\r\n if (typeof input === 'number') {\r\n if (!Number.isInteger(input) || input < 0) {\r\n throw new Error(`Invalid memory ref: ${input} (must be a non-negative integer)`);\r\n }\r\n return { kind: 'obs', id: input };\r\n }\r\n\r\n const trimmed = input.trim();\r\n\r\n // Bare numeric string → legacy observation ref\r\n if (/^\\d+$/.test(trimmed)) {\r\n return { kind: 'obs', id: parseInt(trimmed, 10) };\r\n }\r\n\r\n // Typed ref: obs:42 or skill:3 or obs:42@org/proj\r\n const match = trimmed.match(TYPED_REF_RE);\r\n if (!match) {\r\n throw new Error(\r\n `Invalid memory ref: \"${input}\". Expected format: obs:<id>, skill:<id>, obs:<id>@<projectId>, or a bare number.`,\r\n );\r\n }\r\n\r\n const kind = match[1] as 'obs' | 'skill';\r\n const id = parseInt(match[2], 10);\r\n const projectId = match[3] || undefined;\r\n\r\n return { kind, id, projectId };\r\n}\r\n\r\n// ── Serialization ────────────────────────────────────────────────\r\n\r\n/**\r\n * Serialize a MemoryRef to its canonical string form.\r\n *\r\n * Examples:\r\n * { kind: 'obs', id: 42 } → \"obs:42\"\r\n * { kind: 'skill', id: 3 } → \"skill:3\"\r\n * { kind: 'obs', id: 42, projectId: 'o/p' } → \"obs:42@o/p\"\r\n */\r\nexport function serializeMemoryRef(ref: MemoryRef): string {\r\n const base = `${ref.kind}:${ref.id}`;\r\n return ref.projectId ? `${base}@${ref.projectId}` : base;\r\n}\r\n\r\n// ── Display ──────────────────────────────────────────────────────\r\n\r\n/**\r\n * Format a MemoryRef for human-readable display.\r\n *\r\n * Short forms:\r\n * obs:42 → \"#42\"\r\n * skill:3 → \"S3\"\r\n */\r\nexport function displayRef(ref: MemoryRef): string {\r\n return ref.kind === 'obs' ? `#${ref.id}` : `S${ref.id}`;\r\n}\r\n","/**\r\n * Rules Syncer\r\n *\r\n * Core sync engine for cross-agent rule synchronization.\r\n * Scans project for rule files from all supported agents,\r\n * deduplicates by content hash, detects conflicts, and\r\n * generates output in any target agent format.\r\n *\r\n * This is the ~15% original logic in Memorix — dedup and\r\n * conflict detection are not found in any existing tool.\r\n */\r\n\r\nimport { promises as fs } from 'node:fs';\r\nimport path from 'node:path';\r\nimport type { UnifiedRule, RuleSource, RuleFormatAdapter } from '../types.js';\r\nimport { CursorAdapter } from './adapters/cursor.js';\r\nimport { ClaudeCodeAdapter } from './adapters/claude-code.js';\r\nimport { CodexAdapter } from './adapters/codex.js';\r\nimport { WindsurfAdapter } from './adapters/windsurf.js';\r\nimport { AntigravityAdapter } from './adapters/antigravity.js';\r\nimport { GeminiCLIAdapter } from './adapters/gemini-cli.js';\r\nimport { CopilotAdapter } from './adapters/copilot.js';\r\nimport { KiroAdapter } from './adapters/kiro.js';\r\nimport { TraeAdapter } from './adapters/trae.js';\r\n\r\n/** A detected conflict between two rules */\r\nexport interface RuleConflict {\r\n ruleA: UnifiedRule;\r\n ruleB: UnifiedRule;\r\n reason: string;\r\n}\r\n\r\n/** Sync status report */\r\nexport interface SyncStatus {\r\n totalRules: number;\r\n uniqueRules: number;\r\n sources: RuleSource[];\r\n conflicts: RuleConflict[];\r\n}\r\n\r\n/** File scan patterns for each adapter */\r\ninterface ScanEntry {\r\n adapter: RuleFormatAdapter;\r\n paths: string[];\r\n}\r\n\r\nexport class RulesSyncer {\r\n private readonly projectRoot: string;\r\n private readonly adapters: Map<RuleSource, RuleFormatAdapter>;\r\n\r\n constructor(projectRoot: string) {\r\n this.projectRoot = projectRoot;\r\n this.adapters = new Map();\r\n\r\n const all: RuleFormatAdapter[] = [\r\n new CursorAdapter(),\r\n new ClaudeCodeAdapter(),\r\n new CodexAdapter(),\r\n new WindsurfAdapter(),\r\n new AntigravityAdapter(),\r\n new GeminiCLIAdapter(),\r\n new CopilotAdapter(),\r\n new KiroAdapter(),\r\n new TraeAdapter(),\r\n ];\r\n for (const a of all) {\r\n this.adapters.set(a.source, a);\r\n }\r\n }\r\n\r\n /** Scan the project root for all known rule files and parse them */\r\n async scanRules(): Promise<UnifiedRule[]> {\r\n const rules: UnifiedRule[] = [];\r\n\r\n const scanEntries = this.buildScanEntries();\r\n\r\n for (const entry of scanEntries) {\r\n for (const scanPath of entry.paths) {\r\n const found = await this.findFiles(scanPath);\r\n for (const filePath of found) {\r\n try {\r\n const content = await fs.readFile(filePath, 'utf-8');\r\n const relativePath = path.relative(this.projectRoot, filePath).replace(/\\\\/g, '/');\r\n const parsed = entry.adapter.parse(relativePath, content);\r\n rules.push(...parsed);\r\n } catch {\r\n // Skip unreadable files\r\n }\r\n }\r\n }\r\n }\r\n\r\n return rules;\r\n }\r\n\r\n /** Remove duplicate rules by content hash, keeping highest priority */\r\n deduplicateRules(rules: UnifiedRule[]): UnifiedRule[] {\r\n const byHash = new Map<string, UnifiedRule>();\r\n\r\n for (const rule of rules) {\r\n const existing = byHash.get(rule.hash);\r\n if (!existing || rule.priority > existing.priority) {\r\n byHash.set(rule.hash, rule);\r\n }\r\n }\r\n\r\n return Array.from(byHash.values());\r\n }\r\n\r\n /** Detect conflicts: rules with overlapping paths but different content */\r\n detectConflicts(rules: UnifiedRule[]): RuleConflict[] {\r\n const conflicts: RuleConflict[] = [];\r\n\r\n for (let i = 0; i < rules.length; i++) {\r\n for (let j = i + 1; j < rules.length; j++) {\r\n const a = rules[i];\r\n const b = rules[j];\r\n\r\n // Only compare rules from different sources\r\n if (a.source === b.source) continue;\r\n // Only compare if both have overlapping paths\r\n if (a.scope === 'path-specific' && b.scope === 'path-specific') {\r\n if (this.pathsOverlap(a.paths || [], b.paths || [])) {\r\n conflicts.push({\r\n ruleA: a,\r\n ruleB: b,\r\n reason: `Overlapping paths: ${a.source} vs ${b.source}`,\r\n });\r\n }\r\n }\r\n }\r\n }\r\n\r\n return conflicts;\r\n }\r\n\r\n /** Generate rule files for a target agent format */\r\n generateForTarget(\r\n rules: UnifiedRule[],\r\n target: RuleSource,\r\n ): { filePath: string; content: string }[] {\r\n const adapter = this.adapters.get(target);\r\n if (!adapter) {\r\n throw new Error(`No adapter for target: ${target}`);\r\n }\r\n return adapter.generate(rules);\r\n }\r\n\r\n /** Get a full sync status report */\r\n async syncStatus(): Promise<SyncStatus> {\r\n const rules = await this.scanRules();\r\n const deduped = this.deduplicateRules(rules);\r\n const conflicts = this.detectConflicts(deduped);\r\n const sources = [...new Set(rules.map(r => r.source))];\r\n\r\n return {\r\n totalRules: rules.length,\r\n uniqueRules: deduped.length,\r\n sources,\r\n conflicts,\r\n };\r\n }\r\n\r\n /** Build scan entries mapping adapters to their file search paths */\r\n private buildScanEntries(): ScanEntry[] {\r\n const entries: ScanEntry[] = [];\r\n\r\n for (const adapter of this.adapters.values()) {\r\n const absolutePaths = adapter.filePatterns.map(p =>\r\n path.join(this.projectRoot, p),\r\n );\r\n entries.push({ adapter, paths: absolutePaths });\r\n }\r\n\r\n return entries;\r\n }\r\n\r\n /** Find files matching a glob-like path (simple implementation) */\r\n private async findFiles(pattern: string): Promise<string[]> {\r\n const dir = path.dirname(pattern);\r\n const fileGlob = path.basename(pattern);\r\n\r\n try {\r\n const stat = await fs.stat(dir);\r\n if (!stat.isDirectory()) {\r\n // It's a direct file path\r\n try {\r\n await fs.access(pattern);\r\n return [pattern];\r\n } catch {\r\n return [];\r\n }\r\n }\r\n } catch {\r\n // If dir doesn't exist, check if pattern itself is a file\r\n try {\r\n await fs.access(pattern);\r\n return [pattern];\r\n } catch {\r\n return [];\r\n }\r\n }\r\n\r\n // If it's a glob pattern (contains *), list dir and filter\r\n if (fileGlob.includes('*')) {\r\n try {\r\n const files = await fs.readdir(dir);\r\n const ext = fileGlob.replace('*', '');\r\n return files\r\n .filter(f => ext ? f.endsWith(ext) : true)\r\n .map(f => path.join(dir, f));\r\n } catch {\r\n return [];\r\n }\r\n }\r\n\r\n // Direct file\r\n try {\r\n await fs.access(path.join(dir, fileGlob));\r\n return [path.join(dir, fileGlob)];\r\n } catch {\r\n return [];\r\n }\r\n }\r\n\r\n /** Check if two sets of glob paths overlap (simplified: exact match) */\r\n private pathsOverlap(a: string[], b: string[]): boolean {\r\n for (const pa of a) {\r\n for (const pb of b) {\r\n if (pa === pb) return true;\r\n }\r\n }\r\n return false;\r\n }\r\n}\r\n","/**\r\n * Cursor Rule Format Adapter\r\n *\r\n * Parses and generates rules in Cursor's formats:\r\n * - .cursor/rules/*.mdc (Markdown + frontmatter with description, alwaysApply, globs)\r\n * - .cursorrules (legacy plain text)\r\n * - AGENTS.md (pure Markdown)\r\n *\r\n * Source: Cursor official documentation on Project Rules.\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 CursorAdapter implements RuleFormatAdapter {\r\n readonly source: RuleSource = 'cursor';\r\n\r\n readonly filePatterns = [\r\n '.cursor/rules/*.mdc',\r\n '.cursorrules',\r\n 'AGENTS.md',\r\n ];\r\n\r\n parse(filePath: string, content: string): UnifiedRule[] {\r\n if (filePath.endsWith('.mdc')) {\r\n return this.parseMdc(filePath, content);\r\n }\r\n if (filePath === '.cursorrules' || filePath.endsWith('/.cursorrules')) {\r\n return this.parseLegacy(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 if (rule.alwaysApply !== undefined) fm.alwaysApply = rule.alwaysApply;\r\n if (rule.paths && rule.paths.length > 0) fm.globs = rule.paths;\r\n\r\n const fileName = rule.id\r\n .replace(/^cursor:/, '')\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: `.cursor/rules/${fileName}.mdc`,\r\n content: body,\r\n };\r\n });\r\n }\r\n\r\n private parseMdc(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 globs = data.globs as string[] | undefined;\r\n const hasGlobs = Array.isArray(globs) && globs.length > 0;\r\n const alwaysApply = data.alwaysApply === true;\r\n\r\n let scope: UnifiedRule['scope'] = 'project';\r\n if (alwaysApply) scope = 'global';\r\n else if (hasGlobs) scope = 'path-specific';\r\n\r\n return [{\r\n id: generateRuleId('cursor', filePath),\r\n content: trimmed,\r\n description: data.description as string | undefined,\r\n source: 'cursor',\r\n scope,\r\n paths: hasGlobs ? globs : undefined,\r\n alwaysApply,\r\n priority: alwaysApply ? 10 : 5,\r\n hash: hashContent(trimmed),\r\n }];\r\n }\r\n\r\n private parseLegacy(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('cursor', filePath),\r\n content: trimmed,\r\n source: 'cursor',\r\n scope: 'project',\r\n priority: 3,\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('cursor', filePath),\r\n content: trimmed,\r\n source: 'cursor',\r\n scope: 'project',\r\n priority: 5,\r\n hash: hashContent(trimmed),\r\n }];\r\n }\r\n}\r\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","/**\r\n * Claude Code Rule Format Adapter\r\n *\r\n * Parses and generates rules in Claude Code's formats:\r\n * - CLAUDE.md / .claude/CLAUDE.md (project-level Markdown)\r\n * - .claude/rules/*.md (Markdown with optional `paths` frontmatter)\r\n *\r\n * Source: Claude Code official documentation.\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 ClaudeCodeAdapter implements RuleFormatAdapter {\r\n readonly source: RuleSource = 'claude-code';\r\n\r\n readonly filePatterns = [\r\n 'CLAUDE.md',\r\n '.claude/CLAUDE.md',\r\n '.claude/rules/*.md',\r\n ];\r\n\r\n parse(filePath: string, content: string): UnifiedRule[] {\r\n // .claude/rules/*.md may have `paths` frontmatter\r\n if (filePath.includes('.claude/rules/')) {\r\n return this.parseModularRule(filePath, content);\r\n }\r\n // CLAUDE.md — project-level\r\n return this.parseClaudeMd(filePath, content);\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 if (projectRules.length > 0) {\r\n files.push({\r\n filePath: 'CLAUDE.md',\r\n content: projectRules.map(r => r.content).join('\\n\\n'),\r\n });\r\n }\r\n\r\n for (const rule of pathRules) {\r\n const fm: Record<string, unknown> = {};\r\n if (rule.paths && rule.paths.length > 0) fm.paths = rule.paths;\r\n\r\n const fileName = rule.id\r\n .replace(/^claude-code:/, '')\r\n .replace(/[^a-zA-Z0-9-_]/g, '-')\r\n || 'rule';\r\n\r\n files.push({\r\n filePath: `.claude/rules/${fileName}.md`,\r\n content: Object.keys(fm).length > 0\r\n ? matter.stringify(rule.content, fm)\r\n : rule.content,\r\n });\r\n }\r\n\r\n return files;\r\n }\r\n\r\n private parseClaudeMd(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('claude-code', filePath),\r\n content: trimmed,\r\n source: 'claude-code',\r\n scope: 'project',\r\n priority: 5,\r\n hash: hashContent(trimmed),\r\n }];\r\n }\r\n\r\n private parseModularRule(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 paths = data.paths as string[] | undefined;\r\n const hasPaths = Array.isArray(paths) && paths.length > 0;\r\n\r\n return [{\r\n id: generateRuleId('claude-code', filePath),\r\n content: trimmed,\r\n description: data.description as string | undefined,\r\n source: 'claude-code',\r\n scope: hasPaths ? 'path-specific' : 'project',\r\n paths: hasPaths ? paths : undefined,\r\n priority: 5,\r\n hash: hashContent(trimmed),\r\n }];\r\n }\r\n}\r\n","/**\r\n * OpenAI Codex Rule Format Adapter\r\n *\r\n * Parses and generates rules in Codex's formats:\r\n * - .agents/skills/[name]/SKILL.md (Markdown + frontmatter with name, description)\r\n * - AGENTS.md (pure Markdown)\r\n *\r\n * Source: OpenAI Codex Skills documentation.\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 CodexAdapter implements RuleFormatAdapter {\r\n readonly source: RuleSource = 'codex';\r\n\r\n readonly filePatterns = [\r\n '.agents/skills/*/SKILL.md',\r\n 'AGENTS.md',\r\n ];\r\n\r\n parse(filePath: string, content: string): UnifiedRule[] {\r\n if (filePath.includes('SKILL.md')) {\r\n return this.parseSkillMd(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 skillName = rule.id\r\n .replace(/^codex:/, '')\r\n .replace(/[^a-zA-Z0-9-_]/g, '-')\r\n || `skill-${i}`;\r\n\r\n const fm: Record<string, unknown> = {\r\n name: skillName,\r\n };\r\n\r\n // Codex needs description to know WHEN to trigger the skill.\r\n // If no description exists, auto-generate from content (first 120 chars).\r\n if (rule.description) {\r\n fm.description = rule.description;\r\n } else {\r\n fm.description = this.autoDescription(rule.content);\r\n }\r\n\r\n return {\r\n filePath: `.agents/skills/${skillName}/SKILL.md`,\r\n content: matter.stringify(rule.content, fm),\r\n };\r\n });\r\n }\r\n\r\n /** Extract a short description from rule content for Codex skill triggering */\r\n private autoDescription(content: string): string {\r\n // Take first meaningful line, strip markdown formatting\r\n const lines = content.split('\\n').map(l => l.trim()).filter(Boolean);\r\n const first = lines[0]?.replace(/^#+\\s*/, '').replace(/^[-*]\\s*/, '') || 'Project rules';\r\n if (first.length <= 120) return first;\r\n return first.substring(0, 117) + '...';\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('codex', filePath),\r\n content: trimmed,\r\n description: (data.description as string) || undefined,\r\n source: 'codex',\r\n scope: 'project',\r\n priority: 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('codex', filePath),\r\n content: trimmed,\r\n source: 'codex',\r\n scope: 'project',\r\n priority: 5,\r\n hash: hashContent(trimmed),\r\n }];\r\n }\r\n}\r\n","/**\r\n * Windsurf Rule Format Adapter\r\n *\r\n * Parses and generates rules in Windsurf's formats:\r\n * - .windsurfrules (legacy plain text)\r\n * - .windsurf/rules/*.md (Markdown with optional frontmatter)\r\n *\r\n * Source: Windsurf/Codeium documentation.\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 WindsurfAdapter implements RuleFormatAdapter {\r\n readonly source: RuleSource = 'windsurf';\r\n\r\n readonly filePatterns = [\r\n '.windsurfrules',\r\n '.windsurf/rules/*.md',\r\n ];\r\n\r\n parse(filePath: string, content: string): UnifiedRule[] {\r\n if (filePath === '.windsurfrules' || filePath.endsWith('/.windsurfrules')) {\r\n return this.parseLegacy(filePath, content);\r\n }\r\n if (filePath.includes('.windsurf/rules/')) {\r\n return this.parseModularRule(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 const fileName = rule.id\r\n .replace(/^windsurf:/, '')\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: `.windsurf/rules/${fileName}.md`,\r\n content: body,\r\n };\r\n });\r\n }\r\n\r\n private parseLegacy(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('windsurf', filePath),\r\n content: trimmed,\r\n source: 'windsurf',\r\n scope: 'project',\r\n priority: 3,\r\n hash: hashContent(trimmed),\r\n }];\r\n }\r\n\r\n private parseModularRule(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('windsurf', filePath),\r\n content: trimmed,\r\n description: data.description as string | undefined,\r\n source: 'windsurf',\r\n scope: 'project',\r\n priority: 5,\r\n hash: hashContent(trimmed),\r\n }];\r\n }\r\n}\r\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 * Gemini CLI Rule Format Adapter\r\n *\r\n * Parses and generates rules for Google's standalone Gemini CLI tool.\r\n *\r\n * Gemini CLI reads context/rules from:\r\n * - GEMINI.md (project-level context file, shared with Antigravity)\r\n * - .gemini/rules/*.md (workspace rules, Gemini CLI specific path)\r\n *\r\n * Distinction from Antigravity:\r\n * - Antigravity uses `.agent/rules/*.md` for workspace rules\r\n * - Gemini CLI uses `.gemini/rules/*.md` for workspace rules\r\n * - Both share `GEMINI.md` as the top-level context file\r\n *\r\n * Source: https://googlegemini.wiki/gemini-cli/configuration\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 GeminiCLIAdapter implements RuleFormatAdapter {\r\n readonly source: RuleSource = 'gemini-cli';\r\n\r\n readonly filePatterns = [\r\n 'GEMINI.md',\r\n '.gemini/rules/*.md',\r\n ];\r\n\r\n parse(filePath: string, content: string): UnifiedRule[] {\r\n // .gemini/rules/*.md — workspace rules\r\n if (filePath.includes('.gemini/rules/')) {\r\n return this.parseGeminiRule(filePath, content);\r\n }\r\n // GEMINI.md — global project-level context\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 files: { filePath: string; content: string }[] = [];\r\n\r\n for (const rule of rules) {\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(/^gemini-cli:/, '')\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: `.gemini/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('gemini-cli', filePath),\r\n content: trimmed,\r\n source: 'gemini-cli',\r\n scope: 'global',\r\n priority: 10,\r\n hash: hashContent(trimmed),\r\n }];\r\n }\r\n\r\n private parseGeminiRule(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('gemini-cli', filePath),\r\n content: trimmed,\r\n description: data.description as string | undefined,\r\n source: 'gemini-cli',\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","/**\r\n * Trae IDE Rule Format Adapter\r\n *\r\n * Parses and generates rules in Trae's format:\r\n * - .trae/rules/project_rules.md (project-level rules, plain Markdown)\r\n *\r\n * Trae also supports user-level rules (user_rules.md) created via the UI,\r\n * but those are managed by Trae itself and not project-scoped.\r\n *\r\n * Rules are plain Markdown — no frontmatter, no special syntax.\r\n * Project rules override personal rules when there are conflicts.\r\n *\r\n * Source: https://docs.trae.ai/ide/rules\r\n */\r\n\r\nimport type { RuleFormatAdapter, UnifiedRule, RuleSource } from '../../types.js';\r\nimport { hashContent, generateRuleId } from '../utils.js';\r\n\r\nexport class TraeAdapter implements RuleFormatAdapter {\r\n readonly source: RuleSource = 'trae';\r\n\r\n readonly filePatterns = [\r\n '.trae/rules/project_rules.md',\r\n '.trae/rules/*.md',\r\n ];\r\n\r\n parse(filePath: string, content: string): UnifiedRule[] {\r\n const trimmed = content.trim();\r\n if (!trimmed) return [];\r\n\r\n const isProjectRules = filePath.includes('project_rules.md');\r\n\r\n return [{\r\n id: generateRuleId('trae', filePath),\r\n content: trimmed,\r\n description: isProjectRules ? 'Trae project rules' : undefined,\r\n source: 'trae',\r\n scope: 'project',\r\n alwaysApply: true,\r\n priority: isProjectRules ? 10 : 5,\r\n hash: hashContent(trimmed),\r\n }];\r\n }\r\n\r\n generate(rules: UnifiedRule[]): { filePath: string; content: string }[] {\r\n if (rules.length === 0) return [];\r\n\r\n // Trae uses a single project_rules.md file — merge all rules into one\r\n const combined = rules.map(r => r.content).join('\\n\\n---\\n\\n');\r\n\r\n return [{\r\n filePath: '.trae/rules/project_rules.md',\r\n content: combined,\r\n }];\r\n }\r\n}\r\n","import { readFileSync, readdirSync, existsSync, cpSync, mkdirSync } from 'node:fs';\r\nimport { join, basename } from 'node:path';\r\nimport { homedir } from 'node:os';\r\nimport type {\r\n AgentTarget,\r\n MCPServerEntry,\r\n MCPConfigAdapter,\r\n WorkflowEntry,\r\n WorkspaceSyncResult,\r\n RuleSource,\r\n SkillEntry,\r\n SkillConflict,\r\n} from '../types.js';\r\nimport { WindsurfMCPAdapter } from './mcp-adapters/windsurf.js';\r\nimport { CursorMCPAdapter } from './mcp-adapters/cursor.js';\r\nimport { CodexMCPAdapter } from './mcp-adapters/codex.js';\r\nimport { ClaudeCodeMCPAdapter } from './mcp-adapters/claude-code.js';\r\nimport { CopilotMCPAdapter } from './mcp-adapters/copilot.js';\r\nimport { AntigravityMCPAdapter } from './mcp-adapters/antigravity.js';\r\nimport { GeminiCLIMCPAdapter } from './mcp-adapters/gemini-cli.js';\r\nimport { KiroMCPAdapter } from './mcp-adapters/kiro.js';\r\nimport { OpenCodeMCPAdapter } from './mcp-adapters/opencode.js';\r\nimport { TraeMCPAdapter } from './mcp-adapters/trae.js';\r\nimport { WorkflowSyncer } from './workflow-sync.js';\r\nimport { RulesSyncer } from '../rules/syncer.js';\r\nimport { sanitize } from './sanitizer.js';\r\nimport { WorkspaceSyncApplier, type ApplyResult } from './applier.js';\r\n\r\n/** Scan result from workspace analysis */\r\nexport interface WorkspaceScanResult {\r\n mcpConfigs: Record<AgentTarget, MCPServerEntry[]>;\r\n workflows: WorkflowEntry[];\r\n rulesCount: number;\r\n skills: SkillEntry[];\r\n skillConflicts: SkillConflict[];\r\n}\r\n\r\n/**\r\n * WorkspaceSyncEngine — orchestrates cross-agent workspace migration.\r\n *\r\n * Capabilities:\r\n * 1. MCP config sync (JSON ↔ TOML across 4 agents)\r\n * 2. Workflow sync (Windsurf workflows → Codex skills / Cursor rules / CLAUDE.md)\r\n * 3. Rules sync (via existing RulesSyncer)\r\n */\r\nexport class WorkspaceSyncEngine {\r\n private adapters: Map<AgentTarget, MCPConfigAdapter>;\r\n private workflowSyncer: WorkflowSyncer;\r\n private rulesSyncer: RulesSyncer;\r\n\r\n constructor(private projectRoot: string) {\r\n this.adapters = new Map<AgentTarget, MCPConfigAdapter>([\r\n ['windsurf', new WindsurfMCPAdapter()],\r\n ['cursor', new CursorMCPAdapter()],\r\n ['codex', new CodexMCPAdapter()],\r\n ['claude-code', new ClaudeCodeMCPAdapter()],\r\n ['copilot', new CopilotMCPAdapter()],\r\n ['antigravity', new AntigravityMCPAdapter()],\r\n ['gemini-cli', new GeminiCLIMCPAdapter()],\r\n ['kiro', new KiroMCPAdapter()],\r\n ['opencode', new OpenCodeMCPAdapter()],\r\n ['trae', new TraeMCPAdapter()],\r\n ]);\r\n this.workflowSyncer = new WorkflowSyncer();\r\n this.rulesSyncer = new RulesSyncer(projectRoot);\r\n }\r\n\r\n /**\r\n * Scan the workspace for all agent configs, workflows, and rules.\r\n */\r\n async scan(): Promise<WorkspaceScanResult> {\r\n const mcpConfigs: Record<AgentTarget, MCPServerEntry[]> = {\r\n windsurf: [],\r\n cursor: [],\r\n codex: [],\r\n 'claude-code': [],\r\n copilot: [],\r\n antigravity: [],\r\n 'gemini-cli': [],\r\n kiro: [],\r\n opencode: [],\r\n trae: [],\r\n };\r\n\r\n // Scan MCP configs from each agent (merge all paths, dedup by name)\r\n for (const [target, adapter] of this.adapters) {\r\n const configPath = adapter.getConfigPath(this.projectRoot);\r\n const globalPath = adapter.getConfigPath();\r\n\r\n const pathsToCheck = [configPath, globalPath];\r\n\r\n // Antigravity has an additional config at ~/.gemini/antigravity/mcp_config.json\r\n if (target === 'antigravity') {\r\n pathsToCheck.push(join(homedir(), '.gemini', 'antigravity', 'mcp_config.json'));\r\n }\r\n\r\n const merged = new Map<string, MCPServerEntry>();\r\n for (const path of pathsToCheck) {\r\n if (existsSync(path)) {\r\n try {\r\n const content = readFileSync(path, 'utf-8');\r\n const servers = adapter.parse(content);\r\n for (const s of servers) {\r\n if (!merged.has(s.name)) merged.set(s.name, s);\r\n }\r\n } catch {\r\n // Skip unreadable configs\r\n }\r\n }\r\n }\r\n if (merged.size > 0) {\r\n mcpConfigs[target] = Array.from(merged.values());\r\n }\r\n }\r\n\r\n // Scan Windsurf workflows\r\n const workflows = this.scanWorkflows();\r\n\r\n // Scan rules\r\n let rulesCount = 0;\r\n try {\r\n const rules = await this.rulesSyncer.scanRules();\r\n rulesCount = rules.length;\r\n } catch {\r\n // Rules scan may fail if no rules exist\r\n }\r\n\r\n // Scan skills across all agents\r\n const { skills, conflicts: skillConflicts } = this.scanSkills();\r\n\r\n return { mcpConfigs, workflows, rulesCount, skills, skillConflicts };\r\n }\r\n\r\n /**\r\n * Migrate workspace configs to a target agent format.\r\n * @param items — optional list of specific item names (MCP servers / skills) to sync.\r\n * When provided, only matching items are included. Omit to sync all.\r\n */\r\n async migrate(target: AgentTarget, items?: string[]): Promise<WorkspaceSyncResult> {\r\n const scan = await this.scan();\r\n const result: WorkspaceSyncResult = {\r\n mcpServers: { scanned: [], generated: [] },\r\n workflows: { scanned: [], generated: [] },\r\n rules: { scanned: 0, generated: 0 },\r\n skills: { scanned: [], conflicts: [], copied: [], skipped: [] },\r\n };\r\n\r\n const itemFilter = items && items.length > 0\r\n ? new Set(items.map(i => i.toLowerCase()))\r\n : null;\r\n\r\n // 1. Merge all MCP servers from all sources (dedup by name)\r\n const allServers = new Map<string, MCPServerEntry>();\r\n for (const servers of Object.values(scan.mcpConfigs)) {\r\n for (const s of servers) {\r\n if (!allServers.has(s.name)) {\r\n if (!itemFilter || itemFilter.has(s.name.toLowerCase())) {\r\n allServers.set(s.name, s);\r\n }\r\n }\r\n }\r\n }\r\n result.mcpServers.scanned = Array.from(allServers.values());\r\n\r\n // Generate target MCP config (sanitize sensitive values in output)\r\n if (result.mcpServers.scanned.length > 0) {\r\n const adapter = this.adapters.get(target)!;\r\n const configPath = adapter.getConfigPath(this.projectRoot);\r\n let configContent: string;\r\n\r\n // For agents whose config file is shared (e.g. .gemini/settings.json\r\n // contains both hooks and mcpServers), merge instead of overwrite.\r\n if (target === 'antigravity' && existsSync(configPath)) {\r\n try {\r\n const existing = JSON.parse(readFileSync(configPath, 'utf-8'));\r\n const generated = JSON.parse(adapter.generate(result.mcpServers.scanned));\r\n existing.mcpServers = { ...(existing.mcpServers ?? {}), ...generated.mcpServers };\r\n configContent = JSON.stringify(existing, null, 2);\r\n } catch {\r\n configContent = adapter.generate(result.mcpServers.scanned);\r\n }\r\n } else {\r\n configContent = adapter.generate(result.mcpServers.scanned);\r\n }\r\n\r\n result.mcpServers.generated.push({\r\n filePath: configPath,\r\n content: sanitize(configContent),\r\n });\r\n }\r\n\r\n // 2. Convert workflows to target format\r\n result.workflows.scanned = scan.workflows;\r\n if (scan.workflows.length > 0) {\r\n result.workflows.generated = this.workflowSyncer.convertAll(scan.workflows, target);\r\n }\r\n\r\n // 3. Rules sync\r\n try {\r\n const rules = await this.rulesSyncer.scanRules();\r\n result.rules.scanned = rules.length;\r\n if (rules.length > 0) {\r\n const deduped = this.rulesSyncer.deduplicateRules(rules);\r\n const ruleSource = this.agentToRuleSource(target);\r\n if (ruleSource) {\r\n const files = this.rulesSyncer.generateForTarget(deduped, ruleSource);\r\n result.rules.generated = files.length;\r\n }\r\n }\r\n } catch {\r\n // Rules may not exist\r\n }\r\n\r\n // 4. Skills sync (no format conversion, just copy folders)\r\n result.skills.scanned = itemFilter\r\n ? scan.skills.filter(sk => itemFilter.has(sk.name.toLowerCase()))\r\n : scan.skills;\r\n result.skills.conflicts = scan.skillConflicts;\r\n\r\n return result;\r\n }\r\n\r\n // ---- Private helpers ----\r\n\r\n /** Skills directories per agent */\r\n private static 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 'gemini-cli': [],\r\n kiro: ['.kiro/skills'],\r\n opencode: ['.opencode/skills'],\r\n trae: ['.trae/skills'],\r\n };\r\n\r\n /** Get the target skills directory for an agent (null if agent has no skills support) */\r\n private getTargetSkillsDir(target: AgentTarget): string | null {\r\n const dirs = WorkspaceSyncEngine.SKILLS_DIRS[target];\r\n if (!dirs || dirs.length === 0) return null;\r\n return join(this.projectRoot, dirs[0]);\r\n }\r\n\r\n /**\r\n * Scan all agent skills directories and collect unique skills.\r\n */\r\n private scanSkills(): { skills: SkillEntry[]; conflicts: SkillConflict[] } {\r\n const skills: SkillEntry[] = [];\r\n const conflicts: SkillConflict[] = [];\r\n const seen = new Map<string, SkillEntry>();\r\n const home = homedir();\r\n\r\n for (const [agent, dirs] of Object.entries(WorkspaceSyncEngine.SKILLS_DIRS)) {\r\n for (const dir of dirs) {\r\n // Check project-level and global\r\n const paths = [\r\n join(this.projectRoot, dir),\r\n 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\r\n const skillMd = join(skillsRoot, entry.name, 'SKILL.md');\r\n if (!existsSync(skillMd)) continue;\r\n\r\n // Parse description from frontmatter\r\n let description = '';\r\n try {\r\n const content = readFileSync(skillMd, 'utf-8');\r\n const match = content.match(/^---[\\s\\S]*?description:\\s*[\"']?(.+?)[\"']?\\s*$/m);\r\n if (match) description = match[1];\r\n } catch { /* skip */ }\r\n\r\n const newEntry: SkillEntry = {\r\n name: entry.name,\r\n description,\r\n sourcePath: join(skillsRoot, entry.name),\r\n sourceAgent: agent as AgentTarget,\r\n };\r\n\r\n const existing = seen.get(entry.name);\r\n if (existing) {\r\n // Conflict: same name from different agent\r\n if (existing.sourceAgent !== agent) {\r\n conflicts.push({\r\n name: entry.name,\r\n kept: existing,\r\n skipped: newEntry,\r\n });\r\n }\r\n continue;\r\n }\r\n\r\n seen.set(entry.name, newEntry);\r\n skills.push(newEntry);\r\n }\r\n } catch { /* skip unreadable dirs */ }\r\n }\r\n }\r\n }\r\n\r\n return { skills, conflicts };\r\n }\r\n\r\n /**\r\n * Copy skills to a target agent's skills directory.\r\n * Returns list of copied skill names.\r\n */\r\n copySkills(skills: SkillEntry[], target: AgentTarget): { copied: string[]; skipped: string[] } {\r\n const targetDir = this.getTargetSkillsDir(target);\r\n const copied: string[] = [];\r\n const skipped: string[] = [];\r\n\r\n // Agent has no skills directory support (e.g. copilot)\r\n if (!targetDir) {\r\n return { copied, skipped };\r\n }\r\n\r\n for (const skill of skills) {\r\n // Don't copy a skill back to its own agent\r\n if (skill.sourceAgent === target) continue;\r\n\r\n const dest = join(targetDir, skill.name);\r\n if (existsSync(dest)) {\r\n skipped.push(`${skill.name} (already exists in ${target})`);\r\n continue;\r\n }\r\n\r\n try {\r\n mkdirSync(targetDir, { recursive: true });\r\n cpSync(skill.sourcePath, dest, { recursive: true });\r\n copied.push(skill.name);\r\n } catch { /* skip on error */ }\r\n }\r\n\r\n return { copied, skipped };\r\n }\r\n\r\n private scanWorkflows(): WorkflowEntry[] {\r\n const workflows: WorkflowEntry[] = [];\r\n const wfDir = join(this.projectRoot, '.windsurf', 'workflows');\r\n\r\n if (!existsSync(wfDir)) return workflows;\r\n\r\n try {\r\n const files = readdirSync(wfDir).filter((f) => f.endsWith('.md'));\r\n for (const file of files) {\r\n try {\r\n const content = readFileSync(join(wfDir, file), 'utf-8');\r\n workflows.push(this.workflowSyncer.parseWindsurfWorkflow(file, content));\r\n } catch {\r\n // Skip unreadable files\r\n }\r\n }\r\n } catch {\r\n // Directory read error\r\n }\r\n\r\n return workflows;\r\n }\r\n\r\n /**\r\n * Apply migration results to disk with backup and rollback.\r\n *\r\n * Safety features:\r\n * - Backs up every existing file before overwriting\r\n * - Atomic writes (temp → rename)\r\n * - Auto-rollback on any failure\r\n * - Returns backup paths for manual rollback if needed\r\n */\r\n async apply(target: AgentTarget, items?: string[]): Promise<ApplyResult & { migrationSummary: string }> {\r\n const syncResult = await this.migrate(target, items);\r\n const applier = new WorkspaceSyncApplier();\r\n\r\n // Collect all files to write\r\n const filesToWrite = [\r\n ...syncResult.mcpServers.generated,\r\n ...syncResult.workflows.generated,\r\n ];\r\n\r\n const applyResult = await applier.apply(filesToWrite);\r\n\r\n // Copy skills (no format conversion needed)\r\n let skillResult = { copied: [] as string[], skipped: [] as string[] };\r\n if (syncResult.skills.scanned.length > 0) {\r\n skillResult = this.copySkills(syncResult.skills.scanned, target);\r\n }\r\n\r\n // Build summary\r\n const lines: string[] = [];\r\n if (applyResult.success) {\r\n lines.push(`[OK] Applied ${applyResult.filesWritten.length} file(s) for ${target}`);\r\n for (const f of applyResult.filesWritten) {\r\n lines.push(` → ${f}`);\r\n }\r\n if (skillResult.copied.length > 0) {\r\n lines.push(`\\n[SKILL] Copied ${skillResult.copied.length} skill(s):`);\r\n for (const sk of skillResult.copied) {\r\n lines.push(` → ${sk}`);\r\n }\r\n }\r\n if (skillResult.skipped.length > 0) {\r\n lines.push(`\\n[SKIP] Skipped ${skillResult.skipped.length} skill(s):`);\n for (const sk of skillResult.skipped) {\r\n lines.push(` → ${sk}`);\r\n }\r\n }\r\n if (syncResult.skills.conflicts.length > 0) {\r\n lines.push(`\\n[WARN] Name conflicts (${syncResult.skills.conflicts.length}):`);\r\n for (const c of syncResult.skills.conflicts) {\r\n lines.push(` → \"${c.name}\": kept ${c.kept.sourceAgent}, skipped ${c.skipped.sourceAgent}`);\r\n }\r\n }\r\n if (applyResult.backups.length > 0) {\r\n lines.push(`\\n[PACKAGE] Backups created (${applyResult.backups.length}):`);\r\n for (const b of applyResult.backups) {\r\n lines.push(` ${b.originalPath} → ${b.backupPath}`);\r\n }\r\n }\r\n // Clean up backups after successful apply\r\n applier.cleanBackups(applyResult.backups);\r\n } else {\r\n lines.push(`[ERROR] Apply failed for ${target}`);\r\n for (const e of applyResult.errors) {\r\n lines.push(` Error: ${e}`);\r\n }\r\n if (applyResult.backups.length > 0) {\r\n lines.push(`\\n[UPDATED] Rolled back ${applyResult.backups.length} file(s)`);\r\n }\r\n }\r\n\r\n return {\r\n ...applyResult,\r\n migrationSummary: lines.join('\\n'),\r\n };\r\n }\r\n\r\n // ---- Private helpers ----\r\n\r\n private agentToRuleSource(target: AgentTarget): RuleSource | null {\r\n const map: Record<AgentTarget, RuleSource> = {\r\n cursor: 'cursor',\r\n 'claude-code': 'claude-code',\r\n codex: 'codex',\r\n windsurf: 'windsurf',\r\n copilot: 'copilot',\r\n antigravity: 'antigravity',\r\n 'gemini-cli': 'gemini-cli',\r\n kiro: 'kiro',\r\n opencode: 'codex',\r\n trae: 'trae',\r\n };\r\n return map[target] ?? null;\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 * Windsurf MCP config adapter.\r\n * Format: JSON file at ~/.codeium/windsurf/mcp_config.json\r\n *\r\n * Supports two transport modes:\r\n * 1. stdio: { command, args, env? }\r\n * 2. HTTP: { serverUrl, headers? }\r\n *\r\n * Also handles: disabled, disabledTools, env: null\r\n */\r\nexport class WindsurfMCPAdapter implements MCPConfigAdapter {\r\n readonly source = 'windsurf' 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: Windsurf uses \"serverUrl\" (not \"url\")\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 (can be null in Windsurf)\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 — Windsurf uses \"serverUrl\"\r\n entry.serverUrl = 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 return join(homedir(), '.codeium', 'windsurf', 'mcp_config.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 * Cursor MCP config adapter.\r\n * Format: JSON file at ~/.cursor/mcp.json or .cursor/mcp.json (project-level)\r\n * Structure: { mcpServers: { [name]: { command, args, env?, url? } } }\r\n */\r\nexport class CursorMCPAdapter implements MCPConfigAdapter {\r\n readonly source = 'cursor' 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 ?? {};\r\n return Object.entries(servers).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 }));\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, '.cursor', 'mcp.json');\r\n }\r\n return join(homedir(), '.cursor', 'mcp.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 * Codex MCP config adapter.\r\n * Format: TOML file at ~/.codex/config.toml or .codex/config.toml (project-level)\r\n *\r\n * Structure:\r\n * [mcp_servers.<name>]\r\n * command = \"npx\"\r\n * args = [\"-y\", \"memorix-mcp\"]\r\n * url = \"https://...\" # for HTTP servers\r\n *\r\n * [mcp_servers.<name>.env]\r\n * KEY = \"value\"\r\n *\r\n * We implement a lightweight TOML parser (no external deps) sufficient\r\n * for MCP server config blocks. This avoids adding a TOML dependency.\r\n */\r\nexport class CodexMCPAdapter implements MCPConfigAdapter {\r\n readonly source = 'codex' as const;\r\n\r\n parse(content: string): MCPServerEntry[] {\r\n if (!content.trim()) return [];\r\n\r\n const servers: MCPServerEntry[] = [];\r\n const lines = content.split('\\n');\r\n\r\n let currentServer: string | null = null;\r\n let isEnvBlock = false;\r\n const serverMap = new Map<\r\n string,\r\n { command: string; args: string[]; env: Record<string, string>; url?: string; enabled?: boolean }\r\n >();\r\n\r\n for (const rawLine of lines) {\r\n const line = rawLine.trim();\r\n\r\n // Skip comments and empty lines\r\n if (!line || line.startsWith('#')) continue;\r\n\r\n // Match [mcp_servers.<name>.env]\r\n const envMatch = line.match(/^\\[mcp_servers\\.([^.\\]]+)\\.env\\]$/);\r\n if (envMatch) {\r\n currentServer = envMatch[1];\r\n isEnvBlock = true;\r\n if (!serverMap.has(currentServer)) {\r\n serverMap.set(currentServer, { command: '', args: [], env: {} });\r\n }\r\n continue;\r\n }\r\n\r\n // Match [mcp_servers.<name>]\r\n const serverMatch = line.match(/^\\[mcp_servers\\.([^.\\]]+)\\]$/);\r\n if (serverMatch) {\r\n currentServer = serverMatch[1];\r\n isEnvBlock = false;\r\n if (!serverMap.has(currentServer)) {\r\n serverMap.set(currentServer, { command: '', args: [], env: {} });\r\n }\r\n continue;\r\n }\r\n\r\n // Any other section header resets context\r\n if (line.startsWith('[')) {\r\n currentServer = null;\r\n isEnvBlock = false;\r\n continue;\r\n }\r\n\r\n // Parse key = value within current server block\r\n if (currentServer) {\r\n const kvMatch = line.match(/^(\\w+)\\s*=\\s*(.+)$/);\r\n if (!kvMatch) continue;\r\n\r\n const key = kvMatch[1];\r\n const rawValue = kvMatch[2].trim();\r\n const entry = serverMap.get(currentServer)!;\r\n\r\n if (isEnvBlock) {\r\n entry.env[key] = this.parseTomlString(rawValue);\r\n } else if (key === 'command') {\r\n entry.command = this.parseTomlString(rawValue);\r\n } else if (key === 'args') {\r\n entry.args = this.parseTomlArray(rawValue);\r\n } else if (key === 'url') {\r\n entry.url = this.parseTomlString(rawValue);\r\n } else if (key === 'enabled') {\r\n entry.enabled = rawValue === 'true';\r\n }\r\n }\r\n }\r\n\r\n for (const [name, entry] of serverMap) {\r\n servers.push({\r\n name,\r\n command: entry.command,\r\n args: entry.args,\r\n ...(Object.keys(entry.env).length > 0 ? { env: entry.env } : {}),\r\n ...(entry.url ? { url: entry.url } : {}),\r\n });\r\n }\r\n\r\n return servers;\r\n }\r\n\r\n generate(servers: MCPServerEntry[]): string {\r\n const blocks: string[] = [];\r\n\r\n for (const s of servers) {\r\n const lines: string[] = [];\r\n lines.push(`[mcp_servers.${s.name}]`);\r\n\r\n if (s.url) {\r\n lines.push(`url = ${this.toTomlString(s.url)}`);\r\n } else {\r\n lines.push(`command = ${this.toTomlString(s.command)}`);\r\n lines.push(`args = [${s.args.map((a) => this.toTomlString(a)).join(', ')}]`);\r\n }\r\n\r\n if (s.env && Object.keys(s.env).length > 0) {\r\n lines.push('');\r\n lines.push(`[mcp_servers.${s.name}.env]`);\r\n for (const [key, value] of Object.entries(s.env)) {\r\n lines.push(`${key} = ${this.toTomlString(value)}`);\r\n }\r\n }\r\n\r\n blocks.push(lines.join('\\n'));\r\n }\r\n\r\n return blocks.join('\\n\\n') + '\\n';\r\n }\r\n\r\n getConfigPath(projectRoot?: string): string {\r\n if (projectRoot) {\r\n return join(projectRoot, '.codex', 'config.toml');\r\n }\r\n return join(homedir(), '.codex', 'config.toml');\r\n }\r\n\r\n // ---- TOML helpers ----\r\n\r\n private parseTomlString(raw: string): string {\r\n const trimmed = raw.trim();\r\n if (\r\n (trimmed.startsWith('\"') && trimmed.endsWith('\"')) ||\r\n (trimmed.startsWith(\"'\") && trimmed.endsWith(\"'\"))\r\n ) {\r\n return trimmed.slice(1, -1);\r\n }\r\n return trimmed;\r\n }\r\n\r\n private parseTomlArray(raw: string): string[] {\r\n const trimmed = raw.trim();\r\n if (!trimmed.startsWith('[') || !trimmed.endsWith(']')) return [];\r\n const inner = trimmed.slice(1, -1);\r\n const result: string[] = [];\r\n // Simple CSV parse respecting quotes\r\n let current = '';\r\n let inQuote = false;\r\n let quoteChar = '';\r\n for (const ch of inner) {\r\n if (inQuote) {\r\n if (ch === quoteChar) {\r\n inQuote = false;\r\n } else {\r\n current += ch;\r\n }\r\n } else if (ch === '\"' || ch === \"'\") {\r\n inQuote = true;\r\n quoteChar = ch;\r\n } else if (ch === ',') {\r\n const val = current.trim();\r\n if (val) result.push(val);\r\n current = '';\r\n } else {\r\n current += ch;\r\n }\r\n }\r\n const last = current.trim();\r\n if (last) result.push(last);\r\n return result;\r\n }\r\n\r\n private toTomlString(value: string): string {\r\n return `\"${value.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"')}\"`;\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 * Claude Code MCP config adapter.\r\n * Format: JSON file at ~/.claude.json or project-level .claude/settings.json\r\n * Structure: { mcpServers: { [name]: { command, args, env?, url? } } }\r\n */\r\nexport class ClaudeCodeMCPAdapter implements MCPConfigAdapter {\r\n readonly source = 'claude-code' 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 ?? {};\r\n return Object.entries(servers).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 }));\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, '.claude', 'settings.json');\r\n }\r\n return join(homedir(), '.claude.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 * VS Code Copilot MCP config adapter.\r\n *\r\n * Supports two config locations / formats:\r\n *\r\n * 1. Workspace-level (preferred, new):\r\n * Path: .vscode/mcp.json\r\n * Format: { \"servers\": { [name]: { command, args, env?, url? } } }\r\n *\r\n * 2. Global (legacy, still scanned):\r\n * Path: %APPDATA%/Code/User/settings.json\r\n * Format: { \"mcp\": { \"servers\": { [name]: { command, args, env? } } } }\r\n *\r\n * parse() auto-detects which format is provided.\r\n * generate() always outputs the new .vscode/mcp.json format.\r\n * getConfigPath(projectRoot) returns workspace path; getConfigPath() returns global path.\r\n */\r\nexport class CopilotMCPAdapter implements MCPConfigAdapter {\r\n readonly source = 'copilot' as const;\r\n\r\n parse(content: string): MCPServerEntry[] {\r\n try {\r\n const config = JSON.parse(content);\r\n\r\n // Auto-detect format:\r\n // 1. mcp.json format: { \"servers\": { ... } }\r\n // 2. settings.json format: { \"mcp\": { \"servers\": { ... } } }\r\n const servers = config?.servers ?? config?.mcp?.servers ?? {};\r\n\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 if (entry.type) {\r\n // VS Code mcp.json supports \"type\" field (e.g., \"http\", \"stdio\")\r\n // Map to url for HTTP types\r\n if ((entry.type === 'http' || entry.type === 'sse') && entry.url) {\r\n result.url = entry.url;\r\n }\r\n } else if (entry.url) {\r\n result.url = entry.url;\r\n }\r\n\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 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 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 if (s.url) {\r\n entry.type = 'http';\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 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\r\n // Output the new .vscode/mcp.json format: { \"servers\": { ... } }\r\n return JSON.stringify({ servers: mcpServers }, null, 2);\r\n }\r\n\r\n getConfigPath(projectRoot?: string): string {\r\n if (projectRoot) {\r\n // Workspace-level: .vscode/mcp.json (new official format)\r\n return join(projectRoot, '.vscode', 'mcp.json');\r\n }\r\n // Global: VS Code user settings path (legacy, for scan fallback)\r\n const home = homedir();\r\n if (process.platform === 'win32') {\r\n return join(home, 'AppData', 'Roaming', 'Code', 'User', 'settings.json');\r\n } else if (process.platform === 'darwin') {\r\n return join(home, 'Library', 'Application Support', 'Code', 'User', 'settings.json');\r\n } else {\r\n return join(home, '.config', 'Code', 'User', 'settings.json');\r\n }\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 * 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 * Gemini CLI MCP Configuration Adapter.\r\n *\r\n * Gemini CLI is Google's standalone command-line AI agent (the `gemini` command).\r\n * It shares the same JSON config format as Antigravity but is a distinct product:\r\n *\r\n * - Antigravity = Google's AI-native IDE (VS Code fork)\r\n * - Gemini CLI = standalone CLI tool (`gemini` command)\r\n *\r\n * Config files:\r\n * - Project-level: .gemini/settings.json\r\n * - Global: ~/.gemini/settings.json\r\n *\r\n * Format: { \"mcpServers\": { \"name\": { command, args, env? } } }\r\n *\r\n * Unlike Antigravity, Gemini CLI does NOT use ~/.gemini/antigravity/mcp_config.json.\r\n *\r\n * Source: https://googlegemini.wiki/gemini-cli/configuration\r\n */\r\nexport class GeminiCLIMCPAdapter implements MCPConfigAdapter {\r\n readonly source = 'gemini-cli' 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\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';\r\nimport { homedir } from 'node:os';\r\nimport { join } from 'node:path';\r\n\r\n/**\r\n * OpenCode MCP Configuration Adapter.\r\n *\r\n * OpenCode uses JSON config files for MCP servers:\r\n * 1. Project-level: opencode.json in project root\r\n * 2. Global: ~/.config/opencode/opencode.json\r\n *\r\n * Format:\r\n * {\r\n * \"$schema\": \"https://opencode.ai/config.json\",\r\n * \"mcp\": {\r\n * \"name\": {\r\n * \"type\": \"local\",\r\n * \"command\": [\"memorix\", \"serve\"],\r\n * \"environment\": { \"KEY\": \"value\" },\r\n * \"enabled\": true\r\n * }\r\n * }\r\n * }\r\n *\r\n * Remote (HTTP) servers:\r\n * {\r\n * \"mcp\": {\r\n * \"name\": {\r\n * \"type\": \"remote\",\r\n * \"url\": \"https://...\",\r\n * \"headers\": { \"Authorization\": \"Bearer ...\" }\r\n * }\r\n * }\r\n * }\r\n *\r\n * Source: https://opencode.ai/docs/mcp-servers/\r\n */\r\nexport class OpenCodeMCPAdapter implements MCPConfigAdapter {\r\n readonly source = 'opencode' 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.mcp ?? {};\r\n return Object.entries(servers).map(([name, entry]: [string, any]) => {\r\n const result: MCPServerEntry = {\r\n name,\r\n command: '',\r\n args: [],\r\n };\r\n\r\n if (entry.type === 'remote' && entry.url) {\r\n // HTTP transport\r\n result.url = entry.url;\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 } else {\r\n // Local (stdio) transport — command is an array in OpenCode\r\n if (Array.isArray(entry.command) && entry.command.length > 0) {\r\n result.command = entry.command[0];\r\n result.args = entry.command.slice(1);\r\n } else if (typeof entry.command === 'string') {\r\n result.command = entry.command;\r\n }\r\n }\r\n\r\n // Environment variables (OpenCode uses \"environment\" not \"env\")\r\n const env = entry.environment ?? entry.env;\r\n if (env && typeof env === 'object' && Object.keys(env).length > 0) {\r\n result.env = env;\r\n }\r\n\r\n // Disabled flag\r\n if (entry.enabled === false) {\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 mcp: 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.type = 'remote';\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 — OpenCode uses command as array\r\n entry.type = 'local';\r\n entry.command = [s.command, ...s.args];\r\n }\r\n\r\n if (s.env && Object.keys(s.env).length > 0) {\r\n entry.environment = s.env;\r\n }\r\n\r\n if (s.disabled === true) {\r\n entry.enabled = false;\r\n }\r\n\r\n mcp[s.name] = entry;\r\n }\r\n return JSON.stringify({ $schema: 'https://opencode.ai/config.json', mcp }, null, 2);\r\n }\r\n\r\n getConfigPath(projectRoot?: string): string {\r\n if (projectRoot) {\r\n return join(projectRoot, 'opencode.json');\r\n }\r\n return join(homedir(), '.config', 'opencode', 'opencode.json');\r\n }\r\n}\r\n","import type { MCPConfigAdapter, MCPServerEntry } from '../../types.js';\r\nimport { join } from 'node:path';\r\nimport { homedir } from 'node:os';\r\n\r\n/**\r\n * Trae IDE MCP Configuration Adapter.\r\n *\r\n * Trae stores MCP config at the user level:\r\n * %APPDATA%/Trae/User/mcp.json (Windows)\r\n * ~/Library/Application Support/Trae/User/mcp.json (macOS)\r\n * ~/.config/Trae/User/mcp.json (Linux)\r\n *\r\n * Format (OBJECT-keyed, same as Cursor):\r\n * {\r\n * \"mcpServers\": {\r\n * \"memorix\": {\r\n * \"command\": \"memorix\",\r\n * \"args\": [\"serve\"],\r\n * \"env\": { \"KEY\": \"value\" }\r\n * }\r\n * }\r\n * }\r\n *\r\n * SSE transport:\r\n * {\r\n * \"mcpServers\": {\r\n * \"remote\": {\r\n * \"url\": \"https://...\",\r\n * \"type\": \"sse\"\r\n * }\r\n * }\r\n * }\r\n *\r\n * Source: https://docs.trae.ai/ide/model-context-protocol\r\n */\r\nexport class TraeMCPAdapter implements MCPConfigAdapter {\r\n readonly source = 'trae' 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;\r\n\r\n if (!servers || typeof servers !== 'object') return [];\r\n\r\n // Object-keyed format: { \"mcpServers\": { \"name\": { ... } } }\r\n return Object.entries(servers).map(([name, entry]: [string, any]) => {\r\n const result: MCPServerEntry = {\r\n name,\r\n command: '',\r\n args: [],\r\n };\r\n\r\n if (typeof entry.command === 'string') {\r\n result.command = entry.command;\r\n }\r\n\r\n if (Array.isArray(entry.args)) {\r\n result.args = entry.args;\r\n }\r\n\r\n // SSE/HTTP transport\r\n if (entry.url) {\r\n result.url = entry.url;\r\n }\r\n\r\n // Environment variables\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 // 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 // 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\r\n for (const s of servers) {\r\n const entry: Record<string, any> = {};\r\n\r\n if (s.url) {\r\n // SSE/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 if (s.args && s.args.length > 0) {\r\n entry.args = s.args;\r\n }\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\r\n return JSON.stringify({ mcpServers }, null, 2);\r\n }\r\n\r\n getConfigPath(_projectRoot?: string): string {\r\n const home = homedir();\r\n // Trae stores user-level MCP config in AppData (Windows) / Application Support (macOS) / .config (Linux)\r\n if (process.platform === 'win32') {\r\n return join(process.env.APPDATA || join(home, 'AppData', 'Roaming'), 'Trae', 'User', 'mcp.json');\r\n }\r\n if (process.platform === 'darwin') {\r\n return join(home, 'Library', 'Application Support', 'Trae', 'User', 'mcp.json');\r\n }\r\n return join(home, '.config', 'Trae', 'User', 'mcp.json');\r\n }\r\n}\r\n","import matter from 'gray-matter';\r\nimport type { AgentTarget, WorkflowEntry } from '../types.js';\r\n\r\n/**\r\n * WorkflowSyncer — converts workflows between agent formats.\r\n *\r\n * Supported conversions:\r\n * Windsurf .windsurf/workflows/*.md → Codex SKILL.md\r\n * Windsurf .windsurf/workflows/*.md → Cursor .cursor/rules/*.mdc\r\n * Windsurf .windsurf/workflows/*.md → Claude Code CLAUDE.md section\r\n */\r\nexport class WorkflowSyncer {\r\n /**\r\n * Parse a Windsurf workflow markdown file into a WorkflowEntry.\r\n */\r\n parseWindsurfWorkflow(fileName: string, raw: string): WorkflowEntry {\r\n const name = fileName.replace(/\\.md$/i, '');\r\n let description = '';\r\n let content = raw;\r\n\r\n try {\r\n const parsed = matter(raw);\r\n description = parsed.data?.description ?? '';\r\n content = parsed.content.trim();\r\n } catch {\r\n // No frontmatter — use raw content\r\n }\r\n\r\n return {\r\n name,\r\n description,\r\n content,\r\n source: 'windsurf',\r\n filePath: `.windsurf/workflows/${fileName}`,\r\n };\r\n }\r\n\r\n /**\r\n * Convert a workflow to Codex SKILL.md format.\r\n */\r\n toCodexSkill(wf: WorkflowEntry): { filePath: string; content: string } {\r\n const safeName = this.sanitizeName(wf.name);\r\n const fm: Record<string, string> = { name: safeName };\r\n if (wf.description) {\r\n fm.description = wf.description;\r\n }\r\n const content = matter.stringify(wf.content, fm);\r\n return {\r\n filePath: `.agents/skills/${safeName}/SKILL.md`,\r\n content,\r\n };\r\n }\r\n\r\n /**\r\n * Convert a workflow to Cursor .mdc rule format.\r\n */\r\n toCursorRule(wf: WorkflowEntry): { filePath: string; content: string } {\r\n const safeName = this.sanitizeName(wf.name);\r\n const fm: Record<string, string> = {};\r\n if (wf.description) {\r\n fm.description = wf.description;\r\n }\r\n fm.globs = '';\r\n fm.alwaysApply = 'false';\r\n const content = matter.stringify(wf.content, fm);\r\n return {\r\n filePath: `.cursor/rules/${safeName}.mdc`,\r\n content,\r\n };\r\n }\r\n\r\n /**\r\n * Convert a workflow to a CLAUDE.md section string.\r\n */\r\n toClaudeSection(wf: WorkflowEntry): string {\r\n const lines: string[] = [];\r\n lines.push(`## Workflow: ${wf.name}`);\r\n if (wf.description) {\r\n lines.push('');\r\n lines.push(`> ${wf.description}`);\r\n }\r\n lines.push('');\r\n lines.push(wf.content);\r\n return lines.join('\\n');\r\n }\r\n\r\n /**\r\n * Convert all workflows to the target agent format.\r\n * Returns an array of { filePath, content } for each generated file.\r\n */\r\n convertAll(\r\n workflows: WorkflowEntry[],\r\n target: AgentTarget,\r\n ): { filePath: string; content: string }[] {\r\n if (target === 'windsurf') {\r\n // No conversion needed — already in Windsurf format\r\n return [];\r\n }\r\n\r\n if (target === 'codex') {\r\n return workflows.map((wf) => this.toCodexSkill(wf));\r\n }\r\n\r\n if (target === 'cursor') {\r\n return workflows.map((wf) => this.toCursorRule(wf));\r\n }\r\n\r\n if (target === 'claude-code') {\r\n // Merge all workflows into a single CLAUDE.md\r\n const sections = workflows.map((wf) => this.toClaudeSection(wf));\r\n return [\r\n {\r\n filePath: 'CLAUDE.md',\r\n content: sections.join('\\n\\n'),\r\n },\r\n ];\r\n }\r\n\r\n return [];\r\n }\r\n\r\n // ---- Helpers ----\r\n\r\n private sanitizeName(name: string): string {\r\n return name\r\n .replace(/[^a-zA-Z0-9_-]/g, '-')\r\n .replace(/-+/g, '-')\r\n .replace(/^-|-$/g, '')\r\n || 'workflow';\r\n }\r\n}\r\n","/**\r\n * Sanitizer — mask sensitive values (tokens, keys, passwords) in output.\r\n *\r\n * Patterns detected:\r\n * - API keys / tokens (github_pat_*, ctx7sk-*, sk-*, ghp_*, ghu_*, etc.)\r\n * - Generic key=value where key contains \"token\", \"key\", \"secret\", \"password\"\r\n * - Bearer tokens\r\n */\r\n\r\nconst SENSITIVE_PATTERNS: { pattern: RegExp; replacement: string }[] = [\r\n // GitHub PAT (classic & fine-grained)\r\n { pattern: /ghp_[A-Za-z0-9_]{36,}/g, replacement: 'ghp_***' },\r\n { pattern: /github_pat_[A-Za-z0-9_]{60,}/g, replacement: 'github_pat_***' },\r\n { pattern: /ghu_[A-Za-z0-9_]{36,}/g, replacement: 'ghu_***' },\r\n { pattern: /ghs_[A-Za-z0-9_]{36,}/g, replacement: 'ghs_***' },\r\n // OpenAI / Anthropic style keys\r\n { pattern: /sk-[A-Za-z0-9_-]{20,}/g, replacement: 'sk-***' },\r\n // Context7 keys\r\n { pattern: /ctx7sk-[A-Za-z0-9-]{20,}/g, replacement: 'ctx7sk-***' },\r\n // Generic long hex/base64 tokens (32+ chars) in quoted values\r\n { pattern: /\"([A-Za-z0-9_-]{40,})\"/g, replacement: '\"***\"' },\r\n];\r\n\r\nconst SENSITIVE_KEY_PATTERN = /(?:token|key|secret|password|credential|auth)/i;\r\n\r\n/**\r\n * Mask sensitive values in a string.\r\n */\r\nexport function sanitize(input: string): string {\r\n let result = input;\r\n\r\n // Apply known token patterns\r\n for (const { pattern, replacement } of SENSITIVE_PATTERNS) {\r\n // Reset lastIndex for global regexes\r\n pattern.lastIndex = 0;\r\n result = result.replace(pattern, replacement);\r\n }\r\n\r\n return result;\r\n}\r\n\r\n/**\r\n * Mask sensitive values in MCPServerEntry env/headers objects.\r\n * Returns a new object with masked values.\r\n */\r\nexport function sanitizeRecord(\r\n record: Record<string, string> | undefined | null,\r\n): Record<string, string> | undefined {\r\n if (!record) return undefined;\r\n\r\n const masked: Record<string, string> = {};\r\n for (const [key, value] of Object.entries(record)) {\r\n if (SENSITIVE_KEY_PATTERN.test(key)) {\r\n masked[key] = '***';\r\n } else {\r\n masked[key] = value;\r\n }\r\n }\r\n return masked;\r\n}\r\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","/**\r\n * Tool Profile System — Progressive Disclosure for MCP tools\r\n *\r\n * The full Memorix tool set contains 30+ tools, but most users only ever\r\n * use a small subset (store / search / detail). Exposing all of them at\r\n * tools/list time causes cognitive overload.\r\n *\r\n * We provide three profiles:\r\n * - \"lite\" (stdio default): Core memory CRUD, sessions, reasoning, retention,\r\n * backup — 13 tools. Suitable for solo users who just want cross-agent memory.\r\n * - \"team\" (HTTP default): lite + autonomous agent team tools + dashboard — 20 tools.\n * Suitable when an operator explicitly wants task/message/lock surfaces.\n * - \"full\": Everything, including niche / advanced tools (consolidate, dedup,\r\n * formation metrics, skills, rules/workspace sync, KG-official, image ingest).\r\n * Opt in via `MEMORIX_MODE=full` or `--mode full`.\r\n *\r\n * Users can override at any time via the `MEMORIX_MODE` env var, the `--mode`\r\n * CLI flag, or programmatically via `createMemorixServer({ toolProfile: ... })`.\r\n */\r\n\r\nexport type ToolProfile = 'lite' | 'team' | 'full';\r\n\r\n/**\r\n * Canonical tool name → which profile(s) include it.\r\n * Every `registerTool` call in server.ts MUST consult this map.\r\n */\r\nexport const TOOL_PROFILES: Record<string, ReadonlyArray<ToolProfile>> = Object.freeze({\r\n // ── lite: core cross-agent memory — always available ──────────────\r\n memorix_store: ['lite', 'team', 'full'],\r\n memorix_search: ['lite', 'team', 'full'],\r\n memorix_detail: ['lite', 'team', 'full'],\r\n memorix_resolve: ['lite', 'team', 'full'],\r\n memorix_timeline: ['lite', 'team', 'full'],\r\n memorix_suggest_topic_key: ['lite', 'team', 'full'],\r\n memorix_session_start: ['lite', 'team', 'full'],\r\n memorix_session_end: ['lite', 'team', 'full'],\r\n memorix_session_context: ['lite', 'team', 'full'],\r\n memorix_store_reasoning: ['lite', 'team', 'full'],\r\n memorix_search_reasoning: ['lite', 'team', 'full'],\r\n memorix_transfer: ['lite', 'team', 'full'],\r\n memorix_retention: ['lite', 'team', 'full'],\r\n\r\n // ── team: autonomous agent team surfaces — HTTP default ───────────\n memorix_dashboard: ['team', 'full'],\r\n memorix_handoff: ['team', 'full'],\r\n memorix_poll: ['team', 'full'],\r\n team_manage: ['team', 'full'],\r\n team_message: ['team', 'full'],\r\n team_task: ['team', 'full'],\r\n team_file_lock: ['team', 'full'],\r\n\r\n // ── full: advanced / specialized — opt-in only ───────────────────\r\n memorix_audit_project: ['full'],\r\n memorix_deduplicate: ['full'],\r\n memorix_consolidate: ['full'],\r\n memorix_formation_metrics: ['full'],\r\n memorix_skills: ['full'],\r\n memorix_promote: ['full'],\r\n memorix_rules_sync: ['full'],\r\n memorix_workspace_sync: ['full'],\r\n memorix_ingest_image: ['full'],\r\n\r\n // ── MCP Official Memory Server compatibility (KG tools) ──────────\r\n // These are only useful to users specifically migrating from the\r\n // reference mcp-memory server. Hide them unless explicitly enabled.\r\n create_entities: ['full'],\r\n create_relations: ['full'],\r\n add_observations: ['full'],\r\n delete_entities: ['full'],\r\n delete_observations: ['full'],\r\n delete_relations: ['full'],\r\n read_graph: ['full'],\r\n search_nodes: ['full'],\r\n open_nodes: ['full'],\r\n});\r\n\r\n/**\r\n * Check whether a tool should be registered under the given profile.\r\n *\r\n * Unknown tool names default to `full` (so accidentally-unlisted tools\r\n * remain available via full mode but are hidden by default).\r\n */\r\nexport function isToolInProfile(toolName: string, profile: ToolProfile): boolean {\r\n const profiles = TOOL_PROFILES[toolName];\r\n if (!profiles) {\r\n // Unknown tool: conservative default — only show under 'full'\r\n return profile === 'full';\r\n }\r\n return profiles.includes(profile);\r\n}\r\n\r\nexport interface ResolveToolProfileOpts {\r\n /** Explicit profile from caller (highest priority). */\r\n explicit?: ToolProfile | string | null;\r\n /** Raw env var value, e.g. from process.env.MEMORIX_MODE. */\r\n envValue?: string | null;\r\n /** Default when nothing is set — typically 'lite' for stdio, 'team' for HTTP. */\r\n fallback: ToolProfile;\r\n}\r\n\r\n/**\r\n * Resolve the effective tool profile.\r\n *\r\n * Priority: explicit option > MEMORIX_MODE env > fallback.\r\n * Invalid values fall through to the next level so users never silently\r\n * lose tools due to a typo.\r\n */\r\nexport function resolveToolProfile(opts: ResolveToolProfileOpts): ToolProfile {\r\n const normalize = (v: string | null | undefined): ToolProfile | null => {\r\n if (!v) return null;\r\n const s = String(v).trim().toLowerCase();\r\n if (s === 'lite' || s === 'team' || s === 'full') return s;\r\n return null;\r\n };\r\n\r\n return (\r\n normalize(opts.explicit as string | null | undefined) ??\r\n normalize(opts.envValue) ??\r\n opts.fallback\r\n );\r\n}\r\n\r\n/**\r\n * Human-readable description for logs / diagnostics.\r\n */\r\nexport function describeProfile(profile: ToolProfile): string {\r\n switch (profile) {\r\n case 'lite': return 'lite (core memory + sessions, ~13 tools)';\r\n case 'team': return 'team (lite + agent team tools + dashboard, ~20 tools)';\n case 'full': return 'full (all tools including advanced / KG-compat)';\r\n }\r\n}\r\n\r\n/**\r\n * Count tools registered under each profile — useful for docs and tests.\r\n */\r\nexport function countToolsInProfile(profile: ToolProfile): number {\r\n let n = 0;\r\n for (const name of Object.keys(TOOL_PROFILES)) {\r\n if (isToolInProfile(name, profile)) n++;\r\n }\r\n return n;\r\n}\r\n","export const DEFAULT_FORMATION_TIMEOUT_MS = 12_000;\r\nexport const FORMATION_TIMEOUT_MIN_MS = 1_000;\r\nexport const FORMATION_TIMEOUT_MAX_MS = 300_000;\r\n\r\n/**\r\n * Parse and validate MEMORIX_FORMATION_TIMEOUT_MS.\r\n * - Must be a valid integer in the range 1000-300000ms.\r\n * - Invalid values fall back to the default and log a warning.\r\n * - Out-of-range values are clamped to the nearest bound.\r\n * Default: 12000ms (12s).\r\n */\r\nexport function parseFormationTimeoutMs(raw: string | undefined): number {\r\n const value = raw?.trim();\r\n if (!value) return DEFAULT_FORMATION_TIMEOUT_MS;\r\n\r\n const parsed = Number(value);\r\n if (!Number.isInteger(parsed) || Number.isNaN(parsed)) {\r\n console.warn(\r\n `[memorix] MEMORIX_FORMATION_TIMEOUT_MS=\"${raw}\" is invalid (must be a positive integer between ${FORMATION_TIMEOUT_MIN_MS}-${FORMATION_TIMEOUT_MAX_MS}ms). Using default ${DEFAULT_FORMATION_TIMEOUT_MS}ms.`,\r\n );\r\n return DEFAULT_FORMATION_TIMEOUT_MS;\r\n }\r\n\r\n if (parsed < FORMATION_TIMEOUT_MIN_MS) return FORMATION_TIMEOUT_MIN_MS;\r\n if (parsed > FORMATION_TIMEOUT_MAX_MS) return FORMATION_TIMEOUT_MAX_MS;\r\n return parsed;\r\n}\r\n"],"mappings":"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","names":["path","require","db","fs","path","fs","path","projectDir","observations","nextId","fs","path","projectDir","path","fs","count","projectDir","observations","path","fs","safeJsonParse","store","count","nextId","projectDir","observations","cached","matter","existsSync","readFileSync","join","homedir","existsSync","readFileSync","join","homedir","join","homedir","cached","cache","MAX_CACHE_SIZE","cached","createHash","readFile","writeFile","mkdir","join","homedir","textHash","loadDiskCache","CACHE_FILE","cache","CACHE_DIR","diskCacheDirty","MAX_CACHE_SIZE","cached","embedding","getEmbeddingMode","getEmbeddingApiKey","getEmbeddingBaseUrl","getEmbeddingModel","FastEmbedProvider","TransformersProvider","APIEmbeddingProvider","provider_exports","getLLMApiKey","getLLMProvider","getLLMModel","getLLMBaseUrl","provider","init_provider","init_provider","fs","path","os","HIGH_VALUE_TYPES","init_provider","getDb","insert","remove","COMMAND_LIKE_QUERY","COMMAND_LOG_TITLE","provider","observations","resolveAliases","rerankResults","withFreshIndex","getAllObservations","path","fs","safeJsonParse","nextId","count","observations","_store","_storeDataDir","SqliteBackend","store","getObservationCount","removeObservation","provider","count","path","fs","_store","_storeDataDir","store","count","existsSync","readFileSync","path","id","name","init_provider","extractFacts","callLLM","mergeFacts","getObservation","callLLM","SIMILARITY_HIGH","SIMILARITY_MEDIUM","count","readFileSync","join","homedir","NOISE_PATTERNS","TYPE_WEIGHTS","projectDir","count","projectDir","access","existsSync","readFileSync","writeFileSync","mkdirSync","readdirSync","join","homedir","COMMAND_TRACE_PATTERNS","observations","projectDir","path","fs","row","now","raw","count","projectDir","count","OBSERVATION_ICONS","observations","nextId","fs","path","getCanonicalId","count","classifyProjectId","isDirtyProjectId","observations","nextId","isImmune","getEmbeddingProvider","os","existsSync","join","loadYamlConfig","loadDotenv","getLoadedEnvFiles","initTeamStore","getTeamStore","isTeamStoreInitialized","projectId","d","execSync","readFileSync","existsSync","join","projectDir","randomUUID","storeObservation","init_provider","fs","path","homedir","detectProject","fs","path","os","execSync","getProjectFiles","removeFile","access","unlink","basename","recordFile","existsSync","readFileSync","statSync","mkdirSync","path","createHash","z","count","basename","refs","fs","path","createHash","matter","matter","matter","matter","matter","matter","matter","matter","matter","matter","matter","matter","matter","matter","fs","path","readFileSync","readdirSync","existsSync","mkdirSync","join","homedir","homedir","join","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","readdirSync","mkdirSync","init_provider","createHash","migrateSubdirsToFlat","projectDir","initProjectRoot","loadDotenv","getAllObservations","getAllAliasGroups","z","getBehaviorConfig","action","resolveObservations","getActiveSession","compressNarrative","recordBeforeAfterMetrics","suggestTopicKey","getLastSearchMode","getRetentionSummary","getArchiveCandidates","rankByRelevance","archiveExpired","getRetentionZone","explainRetention","getDb","search","count","homedir","join","readFile","observations","lines","SkillsEngine","path","promoteToMiniSkill","loadAllMiniSkills","deleteMiniSkill","formatMiniSkillsForInjection","findConsolidationCandidates","executeConsolidation","findGitInSubdirs","startSession","AGENT_TYPE_ROLE_MAP","computeWatermark","loadMiniSkills","recordMiniSkillUsage","endSession","getSessionContext","listSessions","exportAsJson","exportAsMarkdown","importFromJson","exec","fileURLToPath","startDashboard","initTeamStore","TeamEventBus","occupancy","role","checkPipelineGuards","computePoll","createHandoffArtifact","analyzeImage","getHookStatus","getGitConfig","ensureHooksDir","existsSync","readFileSync","writeFileSync","deduplicateMemory","getVectorStatus","backfillVectorEmbeddings","isEmbeddingExplicitlyDisabled","detectProjectWithDiagnostics","resetDotenv","path","os","fs"]}