memorix 1.2.4 → 1.2.5

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../node_modules/tsup/assets/esm_shims.js","../src/store/bun-sqlite-compat.ts","../src/store/sqlite-db.ts","../src/config/config-paths.ts","../src/config/dotenv-loader.ts","../src/config/yaml-loader.ts","../src/project/detector.ts","../src/config/legacy-loader.ts","../src/config/toml-loader.ts","../src/config/resolved-config.ts","../src/config.ts","../src/llm/provider.ts","../src/store/sqlite-store.ts","../src/store/obs-store.ts","../src/types.ts","../src/store/file-lock.ts","../src/store/mini-skill-store.ts","../src/compact/token-budget.ts","../src/skills/mini-skills.ts","../src/memory/visibility.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/search/query-expansion.ts","../src/project/aliases.ts","../src/llm/quality.ts","../src/memory/freshness.ts","../src/store/orama-store.ts","../src/memory/entity-extractor.ts","../src/memory/secret-filter.ts","../src/runtime/maintenance-jobs.ts","../src/runtime/lifecycle.ts","../src/codegraph/ids.ts","../src/codegraph/store.ts","../src/codegraph/binder.ts","../src/memory/observations.ts","../src/knowledge/workspace-store.ts","../src/knowledge/workspace.ts","../src/memory/admission.ts","../src/memory/consolidation.ts","../src/llm/memory-manager.ts","../src/memory/retention.ts","../src/codegraph/code-state.ts","../src/codegraph/exclude.ts","../src/codegraph/lite-provider.ts","../src/knowledge/claim-store.ts","../src/knowledge/claims.ts","../src/knowledge/markdown.ts","../src/knowledge/wiki.ts","../src/workspace/workflow-sync.ts","../src/knowledge/workflow-store.ts","../src/codegraph/task-lens.ts","../src/knowledge/workflows.ts","../src/runtime/maintenance-runner.ts","../src/runtime/isolated-maintenance.ts","../src/runtime/project-maintenance.ts"],"sourcesContent":["// Shim globals in esm bundle\nimport path from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\nconst getFilename = () => fileURLToPath(import.meta.url)\nconst getDirname = () => path.dirname(getFilename())\n\nexport const __dirname = /* @__PURE__ */ getDirname()\nexport const __filename = /* @__PURE__ */ getFilename()\n","/**\n * Bun SQLite Compatibility Layer\n *\n * Provides a small better-sqlite3 compatibility layer for the available local\n * SQLite implementation. Node 22 ships node:sqlite, which keeps Memorix\n * usable when an optional better-sqlite3 native binary is unavailable.\n */\n\nimport { createRequire } from 'node:module';\n\nlet Database: any;\nlet driver: 'better-sqlite3' | 'node:sqlite' | 'bun:sqlite' | undefined;\nconst requireFromHere = createRequire(import.meta.url);\n\nfunction loadNodeSqlite(): any {\n const nodeSqlite = requireFromHere('node:sqlite');\n return nodeSqlite.DatabaseSync;\n}\n\nfunction isNativeBindingFailure(error: unknown): boolean {\n const message = error instanceof Error ? error.message : String(error);\n return /could not locate the bindings file|better_sqlite3\\.node|module did not self-register/i.test(message);\n}\n\nfunction addCompatibility(db: any): any {\n // Bun and node:sqlite do not expose better-sqlite3's pragma helper.\n if (!db.pragma) {\n db.pragma = function (pragma: string, options?: { simple?: boolean }) {\n const statement = db.prepare(`PRAGMA ${pragma}`);\n if (options?.simple) {\n const result = statement.get();\n return result ? Object.values(result)[0] : undefined;\n }\n return statement.all();\n };\n }\n\n // Stores use better-sqlite3's synchronous transaction factory. Keep nested\n // calls correct with savepoints instead of silently committing inner work.\n if (!db.transaction) {\n let depth = 0;\n let sequence = 0;\n db.transaction = function <T>(fn: (...args: any[]) => T) {\n return (...args: any[]): T => {\n const outermost = depth === 0;\n const savepoint = `memorix_tx_${++sequence}`;\n if (outermost) {\n db.exec('BEGIN IMMEDIATE');\n } else {\n db.exec(`SAVEPOINT ${savepoint}`);\n }\n depth += 1;\n try {\n const result = fn(...args);\n if (result && typeof (result as any).then === 'function') {\n throw new Error('[memorix] SQLite transactions must be synchronous');\n }\n depth -= 1;\n if (outermost) {\n db.exec('COMMIT');\n } else {\n db.exec(`RELEASE SAVEPOINT ${savepoint}`);\n }\n return result;\n } catch (error) {\n depth -= 1;\n try {\n if (outermost) {\n db.exec('ROLLBACK');\n } else {\n db.exec(`ROLLBACK TO SAVEPOINT ${savepoint}`);\n db.exec(`RELEASE SAVEPOINT ${savepoint}`);\n }\n } catch {\n // Preserve the original application failure when rollback itself fails.\n }\n throw error;\n }\n };\n };\n }\n\n return db;\n}\n\nfunction instantiateDatabase(Sqlite: any, filePath: string, options?: any): any {\n // DatabaseSync validates that an explicitly supplied second argument is an\n // object, unlike better-sqlite3 which accepts undefined.\n return driver === 'node:sqlite' && options === undefined\n ? new Sqlite(filePath)\n : new Sqlite(filePath, options);\n}\n\nexport function loadSqlite(): any {\n if (Database) return Database;\n\n // Kept as an operational escape hatch and a regression-test seam. Node 22\n // is the supported minimum runtime, so this does not expand the platform\n // contract beyond package.json's existing engine requirement.\n if (process.env.MEMORIX_SQLITE_DRIVER === 'node') {\n Database = loadNodeSqlite();\n driver = 'node:sqlite';\n return Database;\n }\n\n // Try better-sqlite3 first (Node.js)\n try {\n Database = requireFromHere('better-sqlite3');\n driver = 'better-sqlite3';\n return Database;\n } catch {\n // Fall through to node:sqlite, then Bun's runtime implementation.\n }\n\n try {\n Database = loadNodeSqlite();\n driver = 'node:sqlite';\n return Database;\n } catch {\n // Fall through to bun:sqlite\n }\n\n // Try bun:sqlite (Bun runtime)\n try {\n // bun:sqlite is a Bun built-in\n const bunSqlite = requireFromHere('bun:sqlite');\n Database = bunSqlite.Database;\n driver = 'bun:sqlite';\n return Database;\n } catch {\n throw new Error('[memorix] SQLite is unavailable (better-sqlite3, node:sqlite, and bun:sqlite failed)');\n }\n}\n\n/**\n * Create a SQLite database with better-sqlite3 compatible API.\n * Works under both Node.js (better-sqlite3) and Bun (bun:sqlite).\n */\nexport function createDatabase(path: string, options?: any): any {\n const Sqlite = loadSqlite();\n try {\n return addCompatibility(instantiateDatabase(Sqlite, path, options));\n } catch (error) {\n // require('better-sqlite3') can succeed even when npm had no prebuild and\n // no local compiler. Fall back to Node's built-in SQLite for that one\n // recoverable case; real open/corruption errors still surface unchanged.\n if (driver !== 'better-sqlite3' || !isNativeBindingFailure(error)) throw error;\n Database = loadNodeSqlite();\n driver = 'node:sqlite';\n return addCompatibility(instantiateDatabase(Database, path, options));\n }\n}\n\n/** Test-only reset for the driver cache used by the forced node:sqlite path. */\nexport function resetSqliteDriverForTests(): void {\n Database = undefined;\n driver = undefined;\n}\n","/**\n * Shared SQLite Database Handle\n *\n * Provides a singleton-per-dataDir better-sqlite3 connection shared across\n * all SQLite-backed stores (observations, mini-skills, sessions, team).\n *\n * Responsibilities:\n * - Dynamic require of better-sqlite3 (optionalDependencies)\n * - WAL mode and busy_timeout configuration\n * - Schema creation for ALL tables (observations, mini_skills, sessions, meta, team_*)\n * - Singleton caching per dataDir\n * - Graceful close\n */\n\nimport { createRequire } from 'node:module';\nimport path from 'node:path';\nimport fs from 'node:fs';\nimport { createDatabase, loadSqlite } from './bun-sqlite-compat.js';\n\n// Dynamic require for SQLite (better-sqlite3, node:sqlite, or bun:sqlite)\nlet BetterSqlite3: any;\n\nexport function loadBetterSqlite3(): any {\n if (BetterSqlite3) return BetterSqlite3;\n try {\n BetterSqlite3 = loadSqlite();\n return BetterSqlite3;\n } catch {\n throw new Error('[memorix] SQLite is not available (better-sqlite3, node:sqlite, and bun:sqlite all failed)');\n }\n}\n\n// ── Schema DDL ──────────────────────────────────────────────────────\n\nconst CREATE_OBSERVATIONS_TABLE = `\nCREATE TABLE IF NOT EXISTS observations (\n id INTEGER PRIMARY KEY,\n entityName TEXT NOT NULL,\n type TEXT NOT NULL,\n title TEXT NOT NULL,\n narrative TEXT NOT NULL DEFAULT '',\n facts TEXT NOT NULL DEFAULT '[]',\n filesModified TEXT NOT NULL DEFAULT '[]',\n concepts TEXT NOT NULL DEFAULT '[]',\n tokens INTEGER NOT NULL DEFAULT 0,\n createdAt TEXT NOT NULL,\n updatedAt TEXT,\n projectId TEXT NOT NULL,\n hasCausalLanguage INTEGER DEFAULT 0,\n topicKey TEXT,\n revisionCount INTEGER DEFAULT 1,\n sessionId TEXT,\n status TEXT NOT NULL DEFAULT 'active',\n progress TEXT,\n source TEXT DEFAULT 'agent',\n commitHash TEXT,\n relatedCommits TEXT,\n relatedEntities TEXT,\n sourceDetail TEXT,\n valueCategory TEXT,\n admissionState TEXT,\n admissionReason TEXT,\n visibility TEXT,\n sharedWithAgentIds TEXT\n);\n`;\n\nconst CREATE_MINI_SKILLS_TABLE = `\nCREATE TABLE IF NOT EXISTS mini_skills (\n id INTEGER PRIMARY KEY,\n sourceObservationIds TEXT NOT NULL DEFAULT '[]',\n sourceEntity TEXT NOT NULL DEFAULT 'unknown',\n title TEXT NOT NULL,\n instruction TEXT NOT NULL DEFAULT '',\n trigger_desc TEXT NOT NULL DEFAULT '',\n facts TEXT NOT NULL DEFAULT '[]',\n projectId TEXT NOT NULL,\n createdAt TEXT NOT NULL,\n usedCount INTEGER NOT NULL DEFAULT 0,\n tags TEXT NOT NULL DEFAULT '[]'\n);\n`;\n\nconst CREATE_SESSIONS_TABLE = `\nCREATE TABLE IF NOT EXISTS sessions (\n id TEXT PRIMARY KEY,\n projectId TEXT NOT NULL,\n startedAt TEXT NOT NULL,\n endedAt TEXT,\n status TEXT NOT NULL DEFAULT 'active',\n summary TEXT,\n agent TEXT\n);\n`;\n\nconst CREATE_META_TABLE = `\nCREATE TABLE IF NOT EXISTS meta (\n key TEXT PRIMARY KEY,\n value TEXT NOT NULL\n);\n`;\n\n// ── Phase 4a: Orchestration Coordination Tables ─────────────────────\n\nconst CREATE_TEAM_AGENTS_TABLE = `\nCREATE TABLE IF NOT EXISTS team_agents (\n agent_id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL,\n agent_type TEXT NOT NULL,\n instance_id TEXT NOT NULL,\n name TEXT NOT NULL DEFAULT '',\n role TEXT,\n capabilities TEXT,\n status TEXT NOT NULL DEFAULT 'active',\n joined_at INTEGER NOT NULL,\n last_heartbeat INTEGER NOT NULL,\n left_at INTEGER,\n last_seen_obs_generation INTEGER NOT NULL DEFAULT 0,\n UNIQUE(project_id, agent_type, instance_id)\n);\n`;\n\nconst CREATE_TEAM_MESSAGES_TABLE = `\nCREATE TABLE IF NOT EXISTS team_messages (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL,\n sender_agent_id TEXT NOT NULL,\n recipient_agent_id TEXT,\n type TEXT NOT NULL DEFAULT 'direct',\n content TEXT NOT NULL DEFAULT '',\n payload TEXT,\n task_id TEXT,\n read_at INTEGER,\n created_at INTEGER NOT NULL,\n to_role TEXT,\n handoff_status TEXT,\n FOREIGN KEY (sender_agent_id) REFERENCES team_agents(agent_id),\n FOREIGN KEY (task_id) REFERENCES team_tasks(task_id)\n);\n`;\n\nconst CREATE_TEAM_TASKS_TABLE = `\nCREATE TABLE IF NOT EXISTS team_tasks (\n task_id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL,\n description TEXT NOT NULL,\n status TEXT NOT NULL DEFAULT 'pending',\n assignee_agent_id TEXT,\n result TEXT,\n metadata TEXT,\n created_by TEXT,\n created_at INTEGER NOT NULL,\n updated_at INTEGER NOT NULL,\n required_role TEXT,\n preferred_role TEXT,\n FOREIGN KEY (assignee_agent_id) REFERENCES team_agents(agent_id),\n FOREIGN KEY (created_by) REFERENCES team_agents(agent_id)\n);\n`;\n\nconst CREATE_TEAM_TASK_DEPS_TABLE = `\nCREATE TABLE IF NOT EXISTS team_task_deps (\n task_id TEXT NOT NULL,\n dep_task_id TEXT NOT NULL,\n PRIMARY KEY (task_id, dep_task_id),\n FOREIGN KEY (task_id) REFERENCES team_tasks(task_id),\n FOREIGN KEY (dep_task_id) REFERENCES team_tasks(task_id)\n);\n`;\n\nconst CREATE_TEAM_LOCKS_TABLE = `\nCREATE TABLE IF NOT EXISTS team_locks (\n file TEXT NOT NULL,\n project_id TEXT NOT NULL,\n locked_by TEXT NOT NULL,\n locked_at INTEGER NOT NULL,\n expires_at INTEGER NOT NULL,\n PRIMARY KEY (file, project_id),\n FOREIGN KEY (locked_by) REFERENCES team_agents(agent_id)\n);\n`;\n\n// ── Phase 4d: Role-based Coordination Tables ─────────────────────────\n\nconst CREATE_TEAM_ROLES_TABLE = `\nCREATE TABLE IF NOT EXISTS team_roles (\n role_id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL,\n label TEXT NOT NULL,\n description TEXT,\n preferred_agent_types TEXT NOT NULL DEFAULT '[]',\n max_concurrent INTEGER NOT NULL DEFAULT 1,\n created_at INTEGER NOT NULL\n);\n`;\n\n// ── Chat Transcript Table ──────────────────────────────────────────────\n\nconst CREATE_CHAT_TRANSCRIPT_TABLE = `\nCREATE TABLE IF NOT EXISTS chat_transcript (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n project_id TEXT NOT NULL,\n thread_id TEXT NOT NULL DEFAULT 'default',\n role TEXT NOT NULL,\n content TEXT NOT NULL DEFAULT '',\n sources_json TEXT NOT NULL DEFAULT '[]',\n meta_json TEXT NOT NULL DEFAULT '{}',\n error INTEGER NOT NULL DEFAULT 0,\n created_at TEXT NOT NULL\n);\n`;\n\n// ── Knowledge Graph Tables ────────────────────────────────────────────\n\nconst CREATE_GRAPH_ENTITIES_TABLE = `\nCREATE TABLE IF NOT EXISTS graph_entities (\n name TEXT PRIMARY KEY,\n entityType TEXT NOT NULL DEFAULT '',\n observations TEXT NOT NULL DEFAULT '[]'\n);\n`;\n\nconst CREATE_GRAPH_RELATIONS_TABLE = `\nCREATE TABLE IF NOT EXISTS graph_relations (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n from_entity TEXT NOT NULL,\n to_entity TEXT NOT NULL,\n relationType TEXT NOT NULL DEFAULT '',\n UNIQUE(from_entity, to_entity, relationType)\n);\n`;\n\n// ── CodeGraph Memory Tables ─────────────────────────────────────────\n\nconst CREATE_CODE_FILES_TABLE = `\nCREATE TABLE IF NOT EXISTS code_files (\n id TEXT PRIMARY KEY,\n projectId TEXT NOT NULL,\n path TEXT NOT NULL,\n language TEXT,\n contentHash TEXT NOT NULL,\n mtimeMs INTEGER,\n sizeBytes INTEGER,\n indexedAt TEXT NOT NULL,\n gitCommit TEXT,\n UNIQUE(projectId, path)\n);\n`;\n\nconst CREATE_CODE_SYMBOLS_TABLE = `\nCREATE TABLE IF NOT EXISTS code_symbols (\n id TEXT PRIMARY KEY,\n projectId TEXT NOT NULL,\n fileId TEXT NOT NULL,\n path TEXT NOT NULL,\n name TEXT NOT NULL,\n qualifiedName TEXT NOT NULL,\n kind TEXT NOT NULL,\n startLine INTEGER,\n endLine INTEGER,\n signature TEXT,\n contentHash TEXT,\n indexedAt TEXT NOT NULL,\n stale INTEGER NOT NULL DEFAULT 0,\n UNIQUE(projectId, fileId, qualifiedName, kind)\n);\n`;\n\nconst CREATE_CODE_EDGES_TABLE = `\nCREATE TABLE IF NOT EXISTS code_edges (\n id TEXT PRIMARY KEY,\n projectId TEXT NOT NULL,\n fromSymbolId TEXT,\n toSymbolId TEXT,\n fromFileId TEXT,\n toFileId TEXT,\n type TEXT NOT NULL,\n confidence REAL NOT NULL DEFAULT 1.0,\n evidence TEXT,\n indexedAt TEXT NOT NULL\n);\n`;\n\nconst CREATE_OBSERVATION_CODE_REFS_TABLE = `\nCREATE TABLE IF NOT EXISTS observation_code_refs (\n id TEXT PRIMARY KEY,\n projectId TEXT NOT NULL,\n observationId INTEGER NOT NULL,\n fileId TEXT,\n symbolId TEXT,\n capturedFileHash TEXT,\n capturedSymbolHash TEXT,\n status TEXT NOT NULL,\n reason TEXT,\n createdAt TEXT NOT NULL,\n updatedAt TEXT\n);\n`;\n\nconst CREATE_SCHEMA_MIGRATIONS_TABLE = [\n 'CREATE TABLE IF NOT EXISTS schema_migrations (',\n ' id TEXT PRIMARY KEY,',\n ' applied_at TEXT NOT NULL',\n ');',\n].join('\\n');\n\nconst CREATE_CODE_STATE_SNAPSHOTS_TABLE = [\n 'CREATE TABLE IF NOT EXISTS code_state_snapshots (',\n ' id TEXT PRIMARY KEY,',\n ' projectId TEXT NOT NULL,',\n ' provider TEXT NOT NULL,',\n ' baseRevision TEXT,',\n ' worktreeFingerprint TEXT NOT NULL,',\n ' worktreeState TEXT NOT NULL,',\n ' changedPathCount INTEGER NOT NULL DEFAULT 0,',\n ' indexedAt TEXT NOT NULL,',\n ' sourceEpoch INTEGER NOT NULL,',\n \" completenessJson TEXT NOT NULL DEFAULT '{}',\",\n ' previousSnapshotId TEXT,',\n ' UNIQUE(projectId, sourceEpoch)',\n ');',\n].join('\\n');\n\n// ── 1.2 Knowledge Claim Ledger ──────────────────────────────────────\n\nconst CREATE_KNOWLEDGE_CLAIMS_TABLE = `\nCREATE TABLE IF NOT EXISTS knowledge_claims (\n id TEXT PRIMARY KEY,\n projectId TEXT NOT NULL,\n subject TEXT NOT NULL,\n predicate TEXT NOT NULL,\n objectValue TEXT NOT NULL,\n scope TEXT NOT NULL,\n claimKey TEXT NOT NULL,\n conflictKey TEXT NOT NULL,\n status TEXT NOT NULL,\n confidence REAL NOT NULL,\n observedAt TEXT NOT NULL,\n validFrom TEXT,\n validTo TEXT,\n supersededBy TEXT,\n reviewState TEXT NOT NULL,\n origin TEXT NOT NULL,\n createdAt TEXT NOT NULL,\n updatedAt TEXT NOT NULL\n);\n`;\n\nconst CREATE_KNOWLEDGE_CLAIM_EVIDENCE_TABLE = `\nCREATE TABLE IF NOT EXISTS knowledge_claim_evidence (\n id TEXT PRIMARY KEY,\n claimId TEXT NOT NULL,\n evidenceKind TEXT NOT NULL,\n evidenceId TEXT NOT NULL,\n relation TEXT NOT NULL,\n snapshotId TEXT,\n locator TEXT,\n capturedHash TEXT,\n evidenceKey TEXT NOT NULL,\n createdAt TEXT NOT NULL,\n UNIQUE(claimId, evidenceKey),\n FOREIGN KEY (claimId) REFERENCES knowledge_claims(id) ON DELETE CASCADE\n);\n`;\n\nconst CREATE_KNOWLEDGE_CLAIM_EVENTS_TABLE = `\nCREATE TABLE IF NOT EXISTS knowledge_claim_events (\n id TEXT PRIMARY KEY,\n projectId TEXT NOT NULL,\n claimId TEXT NOT NULL,\n kind TEXT NOT NULL,\n fromStatus TEXT,\n toStatus TEXT,\n relatedClaimId TEXT,\n detail TEXT,\n createdAt TEXT NOT NULL,\n FOREIGN KEY (claimId) REFERENCES knowledge_claims(id) ON DELETE CASCADE\n);\n`;\n\n// ── 1.2 Knowledge Workspace ─────────────────────────────────────────\n\nconst CREATE_KNOWLEDGE_WORKSPACES_TABLE = [\n 'CREATE TABLE IF NOT EXISTS knowledge_workspaces (',\n ' id TEXT PRIMARY KEY,',\n ' projectId TEXT NOT NULL,',\n ' mode TEXT NOT NULL,',\n ' rootPath TEXT NOT NULL,',\n ' projectRoot TEXT,',\n ' status TEXT NOT NULL,',\n ' createdAt TEXT NOT NULL,',\n ' updatedAt TEXT NOT NULL,',\n ' lastCompiledAt TEXT,',\n ' lastLintedAt TEXT,',\n ' UNIQUE(projectId, mode)',\n ');',\n].join('\\n');\n\nconst CREATE_KNOWLEDGE_PAGES_TABLE = [\n 'CREATE TABLE IF NOT EXISTS knowledge_pages (',\n ' id TEXT PRIMARY KEY,',\n ' workspaceId TEXT NOT NULL,',\n ' relativePath TEXT NOT NULL,',\n ' title TEXT NOT NULL,',\n ' kind TEXT NOT NULL,',\n ' status TEXT NOT NULL,',\n ' reviewState TEXT NOT NULL,',\n ' contentHash TEXT NOT NULL,',\n ' sourceHash TEXT NOT NULL,',\n \" claimIdsJson TEXT NOT NULL DEFAULT '[]',\",\n ' snapshotId TEXT,',\n \" tagsJson TEXT NOT NULL DEFAULT '[]',\",\n ' generatedAt TEXT NOT NULL,',\n ' updatedAt TEXT NOT NULL,',\n ' lastLintedAt TEXT,',\n ' manualContentHash TEXT,',\n ' UNIQUE(workspaceId, relativePath),',\n ' FOREIGN KEY (workspaceId) REFERENCES knowledge_workspaces(id) ON DELETE CASCADE',\n ');',\n].join('\\n');\n\nconst CREATE_KNOWLEDGE_PAGE_CLAIMS_TABLE = [\n 'CREATE TABLE IF NOT EXISTS knowledge_page_claims (',\n ' pageId TEXT NOT NULL,',\n ' claimId TEXT NOT NULL,',\n ' role TEXT NOT NULL,',\n ' PRIMARY KEY (pageId, claimId),',\n ' FOREIGN KEY (pageId) REFERENCES knowledge_pages(id) ON DELETE CASCADE,',\n ' FOREIGN KEY (claimId) REFERENCES knowledge_claims(id) ON DELETE RESTRICT',\n ');',\n].join('\\n');\n\nconst CREATE_KNOWLEDGE_PAGE_LINKS_TABLE = [\n 'CREATE TABLE IF NOT EXISTS knowledge_page_links (',\n ' sourcePageId TEXT NOT NULL,',\n ' targetPath TEXT NOT NULL,',\n ' PRIMARY KEY (sourcePageId, targetPath),',\n ' FOREIGN KEY (sourcePageId) REFERENCES knowledge_pages(id) ON DELETE CASCADE',\n ');',\n].join('\\n');\n\nconst CREATE_KNOWLEDGE_PROPOSALS_TABLE = [\n 'CREATE TABLE IF NOT EXISTS knowledge_proposals (',\n ' id TEXT PRIMARY KEY,',\n ' workspaceId TEXT NOT NULL,',\n ' pageId TEXT NOT NULL,',\n ' targetPath TEXT NOT NULL,',\n ' proposalPath TEXT NOT NULL,',\n ' baseContentHash TEXT,',\n ' sourceHash TEXT NOT NULL,',\n ' reason TEXT NOT NULL,',\n ' status TEXT NOT NULL,',\n ' createdAt TEXT NOT NULL,',\n ' appliedAt TEXT,',\n ' UNIQUE(workspaceId, proposalPath),',\n ' FOREIGN KEY (workspaceId) REFERENCES knowledge_workspaces(id) ON DELETE CASCADE,',\n ' FOREIGN KEY (pageId) REFERENCES knowledge_pages(id) ON DELETE CASCADE',\n ');',\n].join('\\n');\n\n// ── 1.2 Workflow inheritance ────────────────────────────────────────\n\nconst CREATE_KNOWLEDGE_WORKFLOWS_TABLE = [\n 'CREATE TABLE IF NOT EXISTS knowledge_workflows (',\n ' id TEXT PRIMARY KEY,',\n ' workspaceId TEXT NOT NULL,',\n ' sourcePath TEXT NOT NULL,',\n ' title TEXT NOT NULL,',\n ' status TEXT NOT NULL,',\n ' version INTEGER NOT NULL,',\n ' sourceHash TEXT NOT NULL,',\n ' contentHash TEXT NOT NULL,',\n ' specJson TEXT NOT NULL,',\n ' importedFrom TEXT,',\n ' createdAt TEXT NOT NULL,',\n ' updatedAt TEXT NOT NULL,',\n ' UNIQUE(workspaceId, sourcePath),',\n ' FOREIGN KEY (workspaceId) REFERENCES knowledge_workspaces(id) ON DELETE CASCADE',\n ');',\n].join('\\n');\n\nconst CREATE_KNOWLEDGE_WORKFLOW_RUNS_TABLE = [\n 'CREATE TABLE IF NOT EXISTS knowledge_workflow_runs (',\n ' id TEXT PRIMARY KEY,',\n ' workflowId TEXT NOT NULL,',\n ' projectId TEXT NOT NULL,',\n ' task TEXT NOT NULL,',\n ' startingSnapshotId TEXT,',\n \" selectedEvidenceJson TEXT NOT NULL DEFAULT '[]',\",\n \" phaseStateJson TEXT NOT NULL DEFAULT '{}',\",\n ' outcome TEXT NOT NULL,',\n ' verificationVerdict TEXT NOT NULL,',\n ' failureReason TEXT,',\n ' startedAt TEXT NOT NULL,',\n ' completedAt TEXT,',\n ' FOREIGN KEY (workflowId) REFERENCES knowledge_workflows(id) ON DELETE CASCADE',\n ');',\n].join('\\n');\n\n// ── Runtime maintenance jobs ───────────────────────────────────────\n\nconst CREATE_MAINTENANCE_JOBS_TABLE = `\nCREATE TABLE IF NOT EXISTS maintenance_jobs (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL,\n kind TEXT NOT NULL,\n dedupe_key TEXT NOT NULL,\n payload_json TEXT NOT NULL DEFAULT '{}',\n status TEXT NOT NULL DEFAULT 'pending',\n attempts INTEGER NOT NULL DEFAULT 0,\n max_attempts INTEGER NOT NULL DEFAULT 8,\n run_after INTEGER NOT NULL,\n lease_owner TEXT,\n lease_expires_at INTEGER,\n last_error TEXT,\n created_at INTEGER NOT NULL,\n updated_at INTEGER NOT NULL,\n completed_at INTEGER\n);\n`;\n\nconst CREATE_MAINTENANCE_TARGETS_TABLE = `\nCREATE TABLE IF NOT EXISTS maintenance_targets (\n project_id TEXT PRIMARY KEY,\n project_root TEXT NOT NULL,\n data_dir TEXT NOT NULL,\n updated_at INTEGER NOT NULL\n);\n`;\n\nconst CREATE_INDEXES = `\nCREATE INDEX IF NOT EXISTS idx_observations_projectId ON observations(projectId);\nCREATE INDEX IF NOT EXISTS idx_observations_topicKey ON observations(projectId, topicKey);\nCREATE INDEX IF NOT EXISTS idx_observations_status ON observations(status);\nCREATE INDEX IF NOT EXISTS idx_observations_project_status_id ON observations(projectId, status, id);\nCREATE INDEX IF NOT EXISTS idx_observations_project_admission ON observations(projectId, status, admissionState, id);\nCREATE INDEX IF NOT EXISTS idx_observations_project_visibility ON observations(projectId, status, visibility, id);\nCREATE INDEX IF NOT EXISTS idx_mini_skills_projectId ON mini_skills(projectId);\nCREATE INDEX IF NOT EXISTS idx_sessions_projectId ON sessions(projectId);\nCREATE INDEX IF NOT EXISTS idx_sessions_status ON sessions(projectId, status);\nCREATE INDEX IF NOT EXISTS idx_team_agents_project ON team_agents(project_id, status);\nCREATE INDEX IF NOT EXISTS idx_team_messages_recipient ON team_messages(recipient_agent_id, read_at);\nCREATE INDEX IF NOT EXISTS idx_team_messages_project ON team_messages(project_id, created_at);\nCREATE INDEX IF NOT EXISTS idx_team_tasks_project ON team_tasks(project_id, status);\nCREATE INDEX IF NOT EXISTS idx_team_tasks_assignee ON team_tasks(assignee_agent_id, status);\nCREATE INDEX IF NOT EXISTS idx_team_locks_project ON team_locks(project_id);\nCREATE INDEX IF NOT EXISTS idx_team_roles_project ON team_roles(project_id);\nCREATE INDEX IF NOT EXISTS idx_team_tasks_role ON team_tasks(required_role);\nCREATE INDEX IF NOT EXISTS idx_team_messages_role ON team_messages(to_role);\nCREATE INDEX IF NOT EXISTS idx_graph_relations_from ON graph_relations(from_entity);\nCREATE INDEX IF NOT EXISTS idx_graph_relations_to ON graph_relations(to_entity);\nCREATE INDEX IF NOT EXISTS idx_chat_transcript_project ON chat_transcript(project_id, thread_id);\nCREATE INDEX IF NOT EXISTS idx_code_files_project ON code_files(projectId);\nCREATE INDEX IF NOT EXISTS idx_code_symbols_project_name ON code_symbols(projectId, name);\nCREATE INDEX IF NOT EXISTS idx_code_symbols_file ON code_symbols(fileId);\nCREATE INDEX IF NOT EXISTS idx_code_edges_project ON code_edges(projectId, type);\nCREATE INDEX IF NOT EXISTS idx_code_snapshots_project_epoch ON code_state_snapshots(projectId, sourceEpoch DESC);\nCREATE INDEX IF NOT EXISTS idx_code_files_snapshot ON code_files(projectId, snapshotId);\nCREATE INDEX IF NOT EXISTS idx_code_symbols_snapshot ON code_symbols(projectId, snapshotId);\nCREATE INDEX IF NOT EXISTS idx_code_edges_snapshot ON code_edges(projectId, snapshotId);\nCREATE INDEX IF NOT EXISTS idx_observation_code_refs_obs ON observation_code_refs(projectId, observationId);\nCREATE INDEX IF NOT EXISTS idx_observation_code_refs_status ON observation_code_refs(projectId, status);\nCREATE INDEX IF NOT EXISTS idx_knowledge_claims_project_status ON knowledge_claims(projectId, status, updatedAt DESC);\nCREATE INDEX IF NOT EXISTS idx_knowledge_claims_project_conflict ON knowledge_claims(projectId, conflictKey, status);\nCREATE INDEX IF NOT EXISTS idx_knowledge_claims_project_key ON knowledge_claims(projectId, claimKey, status);\nCREATE INDEX IF NOT EXISTS idx_knowledge_claim_evidence_claim ON knowledge_claim_evidence(claimId, createdAt);\nCREATE INDEX IF NOT EXISTS idx_knowledge_claim_events_claim ON knowledge_claim_events(claimId, createdAt);\nCREATE INDEX IF NOT EXISTS idx_knowledge_workspaces_project ON knowledge_workspaces(projectId, mode);\nCREATE INDEX IF NOT EXISTS idx_knowledge_pages_workspace_status ON knowledge_pages(workspaceId, status, updatedAt DESC);\nCREATE INDEX IF NOT EXISTS idx_knowledge_page_claims_claim ON knowledge_page_claims(claimId);\nCREATE INDEX IF NOT EXISTS idx_knowledge_proposals_workspace_status ON knowledge_proposals(workspaceId, status, createdAt DESC);\nCREATE INDEX IF NOT EXISTS idx_knowledge_workflows_workspace_status ON knowledge_workflows(workspaceId, status, updatedAt DESC);\nCREATE INDEX IF NOT EXISTS idx_knowledge_workflow_runs_project_workflow ON knowledge_workflow_runs(projectId, workflowId, startedAt DESC);\nCREATE INDEX IF NOT EXISTS idx_maintenance_jobs_ready ON maintenance_jobs(status, run_after);\nCREATE INDEX IF NOT EXISTS idx_maintenance_jobs_project ON maintenance_jobs(project_id, status, run_after);\nCREATE INDEX IF NOT EXISTS idx_maintenance_targets_updated ON maintenance_targets(updated_at);\nCREATE UNIQUE INDEX IF NOT EXISTS idx_maintenance_jobs_active_dedupe\n ON maintenance_jobs(project_id, kind, dedupe_key)\n WHERE status IN ('pending', 'running', 'retry');\n`;\n\ninterface SchemaMigration {\n id: string;\n apply: (db: any) => void;\n}\n\nfunction hasColumn(db: any, table: string, column: string): boolean {\n return db.prepare('PRAGMA table_info(' + table + ')')\n .all()\n .some((row: { name?: string }) => row.name === column);\n}\n\nfunction addColumnIfMissing(db: any, table: string, column: string, definition: string): void {\n if (hasColumn(db, table, column)) return;\n db.exec('ALTER TABLE ' + table + ' ADD COLUMN ' + definition);\n}\n\nconst SCHEMA_MIGRATIONS: SchemaMigration[] = [\n {\n id: '1.2.2-observation-admission',\n apply: (db) => {\n addColumnIfMissing(db, 'observations', 'admissionState', 'admissionState TEXT');\n addColumnIfMissing(db, 'observations', 'admissionReason', 'admissionReason TEXT');\n db.exec('CREATE INDEX IF NOT EXISTS idx_observations_project_admission ON observations(projectId, status, admissionState, id)');\n },\n },\n {\n id: '1.2.2-observation-visibility',\n apply: (db) => {\n addColumnIfMissing(db, 'observations', 'visibility', 'visibility TEXT');\n addColumnIfMissing(db, 'observations', 'sharedWithAgentIds', 'sharedWithAgentIds TEXT');\n db.exec('CREATE INDEX IF NOT EXISTS idx_observations_project_visibility ON observations(projectId, status, visibility, id)');\n },\n },\n {\n id: '1.2-code-state-snapshots',\n apply: (db) => {\n db.exec(CREATE_CODE_STATE_SNAPSHOTS_TABLE);\n addColumnIfMissing(db, 'code_files', 'snapshotId', 'snapshotId TEXT');\n addColumnIfMissing(db, 'code_files', 'sourceEpoch', 'sourceEpoch INTEGER');\n addColumnIfMissing(db, 'code_symbols', 'snapshotId', 'snapshotId TEXT');\n addColumnIfMissing(db, 'code_symbols', 'sourceEpoch', 'sourceEpoch INTEGER');\n addColumnIfMissing(db, 'code_edges', 'snapshotId', 'snapshotId TEXT');\n addColumnIfMissing(db, 'code_edges', 'sourceEpoch', 'sourceEpoch INTEGER');\n addColumnIfMissing(db, 'observation_code_refs', 'snapshotId', 'snapshotId TEXT');\n db.exec('CREATE INDEX IF NOT EXISTS idx_code_snapshots_project_epoch ON code_state_snapshots(projectId, sourceEpoch DESC)');\n db.exec('CREATE INDEX IF NOT EXISTS idx_code_files_snapshot ON code_files(projectId, snapshotId)');\n db.exec('CREATE INDEX IF NOT EXISTS idx_code_symbols_snapshot ON code_symbols(projectId, snapshotId)');\n db.exec('CREATE INDEX IF NOT EXISTS idx_code_edges_snapshot ON code_edges(projectId, snapshotId)');\n },\n },\n {\n id: '1.2-knowledge-claim-ledger',\n apply: (db) => {\n db.exec(CREATE_KNOWLEDGE_CLAIMS_TABLE);\n db.exec(CREATE_KNOWLEDGE_CLAIM_EVIDENCE_TABLE);\n db.exec(CREATE_KNOWLEDGE_CLAIM_EVENTS_TABLE);\n db.exec('CREATE INDEX IF NOT EXISTS idx_knowledge_claims_project_status ON knowledge_claims(projectId, status, updatedAt DESC)');\n db.exec('CREATE INDEX IF NOT EXISTS idx_knowledge_claims_project_conflict ON knowledge_claims(projectId, conflictKey, status)');\n db.exec('CREATE INDEX IF NOT EXISTS idx_knowledge_claims_project_key ON knowledge_claims(projectId, claimKey, status)');\n db.exec('CREATE INDEX IF NOT EXISTS idx_knowledge_claim_evidence_claim ON knowledge_claim_evidence(claimId, createdAt)');\n db.exec('CREATE INDEX IF NOT EXISTS idx_knowledge_claim_events_claim ON knowledge_claim_events(claimId, createdAt)');\n },\n },\n {\n id: '1.2-knowledge-workspace',\n apply: (db) => {\n db.exec(CREATE_KNOWLEDGE_WORKSPACES_TABLE);\n db.exec(CREATE_KNOWLEDGE_PAGES_TABLE);\n db.exec(CREATE_KNOWLEDGE_PAGE_CLAIMS_TABLE);\n db.exec(CREATE_KNOWLEDGE_PAGE_LINKS_TABLE);\n db.exec(CREATE_KNOWLEDGE_PROPOSALS_TABLE);\n db.exec('CREATE INDEX IF NOT EXISTS idx_knowledge_workspaces_project ON knowledge_workspaces(projectId, mode)');\n db.exec('CREATE INDEX IF NOT EXISTS idx_knowledge_pages_workspace_status ON knowledge_pages(workspaceId, status, updatedAt DESC)');\n db.exec('CREATE INDEX IF NOT EXISTS idx_knowledge_page_claims_claim ON knowledge_page_claims(claimId)');\n db.exec('CREATE INDEX IF NOT EXISTS idx_knowledge_proposals_workspace_status ON knowledge_proposals(workspaceId, status, createdAt DESC)');\n },\n },\n {\n id: '1.2-workflow-inheritance',\n apply: (db) => {\n db.exec(CREATE_KNOWLEDGE_WORKFLOWS_TABLE);\n db.exec(CREATE_KNOWLEDGE_WORKFLOW_RUNS_TABLE);\n db.exec('CREATE INDEX IF NOT EXISTS idx_knowledge_workflows_workspace_status ON knowledge_workflows(workspaceId, status, updatedAt DESC)');\n db.exec('CREATE INDEX IF NOT EXISTS idx_knowledge_workflow_runs_project_workflow ON knowledge_workflow_runs(projectId, workflowId, startedAt DESC)');\n },\n },\n];\n\nfunction applySchemaMigrations(db: any): void {\n db.exec(CREATE_SCHEMA_MIGRATIONS_TABLE);\n for (const migration of SCHEMA_MIGRATIONS) {\n const applied = db.prepare('SELECT 1 FROM schema_migrations WHERE id = ?').get(migration.id);\n if (applied) continue;\n const apply = db.transaction(() => {\n migration.apply(db);\n db.prepare('INSERT INTO schema_migrations (id, applied_at) VALUES (?, ?)').run(\n migration.id,\n new Date().toISOString(),\n );\n });\n apply();\n }\n}\n\n// ── Singleton cache ─────────────────────────────────────────────────\n\nconst _dbCache = new Map<string, any>();\n\n/**\n * Get or create a shared SQLite database handle for the given data directory.\n *\n * The handle is cached per normalized dataDir path. All stores (observations,\n * mini-skills, sessions) share the same connection and the same DB file.\n *\n * Callers must NOT close the returned handle directly — use closeDatabase().\n */\nexport function getDatabase(dataDir: string): any {\n const normalized = path.resolve(dataDir);\n const existing = _dbCache.get(normalized);\n if (existing) return existing;\n\n loadBetterSqlite3();\n fs.mkdirSync(dataDir, { recursive: true });\n\n const dbPath = path.join(dataDir, 'memorix.db');\n const db = createDatabase(dbPath);\n\n // WAL mode for concurrent read performance\n db.pragma('journal_mode = WAL');\n db.pragma('busy_timeout = 5000');\n db.pragma('foreign_keys = ON');\n\n // Create all tables\n db.exec(CREATE_OBSERVATIONS_TABLE);\n db.exec(CREATE_MINI_SKILLS_TABLE);\n db.exec(CREATE_SESSIONS_TABLE);\n db.exec(CREATE_META_TABLE);\n // Phase 4a: coordination tables (order matters for FK references)\n db.exec(CREATE_TEAM_AGENTS_TABLE);\n db.exec(CREATE_TEAM_TASKS_TABLE);\n db.exec(CREATE_TEAM_TASK_DEPS_TABLE);\n db.exec(CREATE_TEAM_MESSAGES_TABLE);\n db.exec(CREATE_TEAM_LOCKS_TABLE);\n db.exec(CREATE_TEAM_ROLES_TABLE);\n db.exec(CREATE_GRAPH_ENTITIES_TABLE);\n db.exec(CREATE_GRAPH_RELATIONS_TABLE);\n db.exec(CREATE_CHAT_TRANSCRIPT_TABLE);\n db.exec(CREATE_CODE_FILES_TABLE);\n db.exec(CREATE_CODE_SYMBOLS_TABLE);\n db.exec(CREATE_CODE_EDGES_TABLE);\n db.exec(CREATE_OBSERVATION_CODE_REFS_TABLE);\n db.exec(CREATE_MAINTENANCE_JOBS_TABLE);\n db.exec(CREATE_MAINTENANCE_TARGETS_TABLE);\n\n // Phase 3a migration: add sourceSnapshot + updatedAt to mini_skills\n // Idempotent — ALTER TABLE ADD COLUMN throws if column already exists\n // IMPORTANT: These must run BEFORE CREATE_INDEXES so columns exist when indexes reference them\n try { db.exec(`ALTER TABLE mini_skills ADD COLUMN sourceSnapshot TEXT NOT NULL DEFAULT ''`); } catch { /* already exists */ }\n try { db.exec(`ALTER TABLE mini_skills ADD COLUMN updatedAt TEXT`); } catch { /* already exists */ }\n\n // Phase 4a: observation attribution columns\n try { db.exec(`ALTER TABLE observations ADD COLUMN createdByAgentId TEXT`); } catch { /* already exists */ }\n try { db.exec(`ALTER TABLE observations ADD COLUMN writeGeneration INTEGER DEFAULT 0`); } catch { /* already exists */ }\n\n // Phase 4d: role-based coordination columns\n try { db.exec(`ALTER TABLE team_tasks ADD COLUMN required_role TEXT`); } catch { /* already exists */ }\n try { db.exec(`ALTER TABLE team_tasks ADD COLUMN preferred_role TEXT`); } catch { /* already exists */ }\n try { db.exec(`ALTER TABLE team_messages ADD COLUMN to_role TEXT`); } catch { /* already exists */ }\n try { db.exec(`ALTER TABLE team_messages ADD COLUMN handoff_status TEXT`); } catch { /* already exists */ }\n\n // New migrations are transactional and tracked. Older idempotent migrations\n // remain untouched for backwards compatibility with existing local stores.\n applySchemaMigrations(db);\n\n // Create indexes AFTER all ALTER TABLE migrations so referenced columns exist\n db.exec(CREATE_INDEXES);\n\n // Seed meta defaults\n db.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('storage_generation', '0')`).run();\n db.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('next_id', '1')`).run();\n db.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('mini_skills_generation', '0')`).run();\n\n _dbCache.set(normalized, db);\n return db;\n}\n\n/**\n * Close and remove a cached database handle for the given data directory.\n * Safe to call even if no handle exists.\n */\nexport function closeDatabase(dataDir: string): void {\n const normalized = path.resolve(dataDir);\n const db = _dbCache.get(normalized);\n if (db) {\n try { db.close(); } catch { /* best-effort */ }\n _dbCache.delete(normalized);\n }\n}\n\n/**\n * Close all cached database handles. Used during shutdown or tests.\n */\nexport function closeAllDatabases(): void {\n for (const [key, db] of _dbCache) {\n try { db.close(); } catch { /* best-effort */ }\n _dbCache.delete(key);\n }\n}\n\n/**\n * Check if better-sqlite3 is available without throwing.\n */\nexport function isSqliteAvailable(): boolean {\n try {\n loadBetterSqlite3();\n return true;\n } catch {\n return false;\n }\n}\n","import { join } from 'node:path';\n\nexport function getGlobalConfigTomlPath(homeDir: string): string {\n return join(homeDir, '.memorix', 'config.toml');\n}\n\nexport function getProjectConfigTomlPath(projectRoot: string): string {\n return join(projectRoot, 'memorix.toml');\n}\n\nexport function getGlobalYamlPath(homeDir: string): string {\n return join(homeDir, '.memorix', 'memorix.yml');\n}\n\nexport function getProjectYamlPath(projectRoot: string): string {\n return join(projectRoot, 'memorix.yml');\n}\n\nexport function getGlobalDotenvPath(homeDir: string): string {\n return join(homeDir, '.memorix', '.env');\n}\n\nexport function getProjectDotenvPath(projectRoot: string): string {\n return join(projectRoot, '.env');\n}\n\nexport function getLegacyConfigJsonPath(homeDir: string): string {\n return join(homeDir, '.memorix', 'config.json');\n}\n","/**\n * .env Loader for Memorix\n *\n * Loads compatibility environment overrides from project/user .env files.\n * The primary product configuration is TOML:\n * - ~/.memorix/config.toml\n * - <git-root>/memorix.toml\n *\n * Design principle:\n * TOML = normal user setup and structured behavior\n * .env = compatibility, CI, launchers, and temporary overrides\n *\n * Priority (highest wins):\n * 1. System environment variables (from MCP host `env` field or shell)\n * 2. Project .env file (./ .env in project root)\n * 3. User .env file (~/.memorix/.env) — advanced, not promoted\n *\n * Do not promote .env as the default product surface. Keep it as an override\n * layer for users who need launcher-specific behavior.\n */\n\nimport { existsSync, readFileSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { parse } from 'dotenv';\nimport { getGlobalDotenvPath, getProjectDotenvPath } from './config-paths.js';\n\n// ─── State ───\n\nlet dotenvLoaded = false;\nlet dotenvProjectRoot: string | null = null;\n\n/** Track which .env files were loaded (for diagnostics) */\nconst loadedEnvFiles: string[] = [];\n/** Track keys injected by .env so project switches can cleanly restore process.env */\nconst injectedKeys = new Set<string>();\n\nfunction loadEnvFile(filePath: string): void {\n if (!existsSync(filePath)) return;\n\n const parsed = parse(readFileSync(filePath, 'utf-8'));\n for (const [key, value] of Object.entries(parsed)) {\n if (!(key in process.env)) {\n process.env[key] = value;\n injectedKeys.add(key);\n }\n }\n\n loadedEnvFiles.push(filePath);\n}\n\ninterface DotenvLoadOptions {\n userHomeDir?: string;\n}\n\n// ─── Public API ───\n\n/**\n * Load .env files into process.env.\n * Called once during startup. Does NOT override existing env vars.\n *\n * @param projectRoot - Project root directory (for project-level .env)\n */\nexport function loadDotenv(projectRoot?: string, options: DotenvLoadOptions = {}): void {\n if (dotenvLoaded && dotenvProjectRoot === (projectRoot ?? null)) return;\n\n if (dotenvLoaded && dotenvProjectRoot !== (projectRoot ?? null)) {\n resetDotenv();\n }\n\n loadedEnvFiles.length = 0;\n\n // Loading order = priority order (with override: false, first value wins).\n // System env vars already exist in process.env, so they always win.\n\n // 1. Project-level .env — highest .env priority, load first\n if (projectRoot) {\n loadEnvFile(getProjectDotenvPath(projectRoot));\n }\n\n // 2. User-level .env (~/.memorix/.env) — lowest .env priority, load second\n // (override: false means it only fills in keys not already set)\n loadEnvFile(getGlobalDotenvPath(options.userHomeDir ?? homedir()));\n\n dotenvLoaded = true;\n dotenvProjectRoot = projectRoot ?? null;\n}\n\n/**\n * Reset dotenv state (for testing or project switch).\n */\nexport function resetDotenv(): void {\n for (const key of injectedKeys) {\n delete process.env[key];\n }\n injectedKeys.clear();\n dotenvLoaded = false;\n dotenvProjectRoot = null;\n loadedEnvFiles.length = 0;\n}\n\n/**\n * Get list of .env files that were loaded (for diagnostics).\n */\nexport function getLoadedEnvFiles(): readonly string[] {\n return loadedEnvFiles;\n}\n\n// ─── Supported .env variables ───\n// These are the ONLY variables Memorix reads from .env.\n// All are secrets or endpoint URLs — no behavior config.\n//\n// MEMORIX_LLM_API_KEY — Background memory LLM API key\n// MEMORIX_LLM_BASE_URL — Background memory LLM endpoint\n// MEMORIX_AGENT_API_KEY — TUI/chat coding agent API key\n// MEMORIX_AGENT_BASE_URL — TUI/chat coding agent endpoint\n// MEMORIX_AGENT_LLM_API_KEY — Legacy alias for MEMORIX_AGENT_API_KEY\n// MEMORIX_AGENT_LLM_BASE_URL — Legacy alias for MEMORIX_AGENT_BASE_URL\n// MEMORIX_EMBEDDING_API_KEY — Embedding/vector API key\n// MEMORIX_EMBEDDING_BASE_URL — Custom embedding endpoint\n// MEMORIX_API_KEY — Memory LLM simple key (not used for embedding or agent)\n// OPENAI_API_KEY — OpenAI compatibility fallback\n// ANTHROPIC_API_KEY — Anthropic compatibility fallback\n// OPENROUTER_API_KEY — OpenRouter compatibility fallback\n","/**\n * memorix.yml Configuration Loader\n *\n * Loads YAML configuration from project-level and user-level paths.\n * This is the platform-grade config format — Memorix as a central hub,\n * not just an MCP plugin.\n *\n * Priority chain (highest wins):\n * 1. Environment variables\n * 2. ./memorix.yml (project-level, in project root)\n * 3. ~/.memorix/memorix.yml (user-level, global defaults)\n * 4. ~/.memorix/config.json (legacy, backward compat)\n * 5. Hardcoded defaults\n *\n * Inspired by: Cipher's cipher.yml, Docker's docker-compose.yml\n */\n\nimport { existsSync, readFileSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { createRequire } from 'node:module';\nimport { getGlobalYamlPath, getProjectYamlPath } from './config-paths.js';\n\n// ─── Types ───────────────────────────────────────────────────────────\n\nexport interface MemorixYamlConfig {\n /** LLM provider configuration */\n llm?: {\n provider?: 'openai' | 'anthropic' | 'openrouter' | string;\n model?: string;\n apiKey?: string;\n baseUrl?: string;\n };\n\n /** TUI / chat agent LLM provider configuration */\n agent?: {\n provider?: 'openai' | 'anthropic' | 'openrouter' | string;\n model?: string;\n apiKey?: string;\n baseUrl?: string;\n };\n\n /** Embedding / vector search configuration */\n embedding?: {\n provider?: 'off' | 'api' | 'fastembed' | 'transformers' | 'auto';\n model?: string;\n apiKey?: string;\n baseUrl?: string;\n dimensions?: number;\n };\n\n /** Git-Memory pipeline configuration */\n git?: {\n /** Auto-install post-commit hook on first run (default: false) */\n autoHook?: boolean;\n /** Ingest commits as memories on post-commit (default: true when hook installed) */\n ingestOnCommit?: boolean;\n /** Maximum diff size (chars) to include in memory (default: 500) */\n maxDiffSize?: number;\n /** Skip merge commits (default: true) */\n skipMergeCommits?: boolean;\n /** File patterns to exclude from git memory (glob) */\n excludePatterns?: string[];\n /** Additional commit message phrases to treat as noise (literal, case-insensitive) */\n noiseKeywords?: string[];\n };\n\n /** CodeGraph / Project Context configuration */\n codegraph?: {\n /** File patterns to exclude from CodeGraph indexing and context suggestions */\n excludePatterns?: string[];\n /** Maximum source file size to parse into CodeGraph Memory */\n maxFileBytes?: number;\n /** Use a healthy pre-existing local CodeGraph index when present (default: auto). */\n externalContext?: 'auto' | 'off';\n /** Optional CodeGraph executable path when it is not available on PATH. */\n externalCommand?: string;\n /** Bound for one local semantic context request. */\n externalTimeoutMs?: number;\n };\n\n /** Behavior settings */\n behavior?: {\n /** Session start injection mode */\n sessionInject?: 'full' | 'minimal' | 'silent';\n /** Show sync advisory on first search */\n syncAdvisory?: boolean;\n /** Auto-archive expired memories on startup */\n autoCleanup?: boolean;\n /** Formation Pipeline mode */\n formationMode?: 'active' | 'shadow' | 'fallback';\n };\n\n /** MCP server mode configuration (when Memorix runs as hub) */\n server?: {\n /** Transport: stdio (default) or http */\n transport?: 'stdio' | 'http';\n /** HTTP port (only for http transport) */\n port?: number;\n /** Enable Web Dashboard */\n dashboard?: boolean;\n /** Dashboard port (default: 3210) */\n dashboardPort?: number;\n };\n\n /** Orchestration coordination settings */\n team?: {\n /** Enable orchestration coordination features */\n enabled?: boolean;\n /** Shared workspace memory collection */\n workspaceCollection?: string;\n };\n\n /** Additional MCP servers to aggregate (Memorix as hub) */\n mcpServers?: Record<string, {\n type?: 'stdio' | 'sse';\n command?: string;\n args?: string[];\n env?: Record<string, string>;\n url?: string;\n }>;\n}\n\n// ─── Loader ──────────────────────────────────────────────────────────\n\n// Per-project config cache — keyed by resolved projectRoot string.\n// null key = user-level-only config (no project root).\nconst configCache = new Map<string | null, MemorixYamlConfig>();\nconst require = createRequire(import.meta.url);\n\n/** Stored project root — set once by server init, used by all no-arg loadYamlConfig() calls */\nlet globalProjectRoot: string | null = null;\n\n/**\n * Set the project root for YAML config resolution.\n * Call this once during server init so all config getters\n * (which call loadYamlConfig() without args) pick up project-level memorix.yml.\n *\n * In HTTP mode, this is called per-session/switchProject — the Map cache\n * preserves configs for all projects simultaneously.\n */\nexport function initProjectRoot(root: string): void {\n globalProjectRoot = root;\n // Invalidate this project's cache entry so file changes are picked up\n configCache.delete(root);\n}\n\n/**\n * Clear the global project root used by no-arg loadYamlConfig().\n * Useful when a long-lived process switches to a project whose root is unknown.\n */\nexport function clearProjectRoot(): void {\n globalProjectRoot = null;\n}\n\n/**\n * Load memorix.yml from project root and/or user home.\n * Project-level overrides user-level (shallow merge per top-level key).\n */\nexport function loadYamlConfig(projectRoot?: string | null): MemorixYamlConfig {\n // When null is explicitly passed, skip global fallback (user-level config only).\n // When undefined (no arg), fall back to globally-initialized project root.\n const resolvedRoot = projectRoot === null ? null : (projectRoot ?? globalProjectRoot ?? null);\n\n // Per-project cache hit\n const cached = configCache.get(resolvedRoot ?? null);\n if (cached) return cached;\n\n const userYaml = getGlobalYamlPath(homedir());\n const projectYaml = resolvedRoot ? getProjectYamlPath(resolvedRoot) : null;\n\n let userConfig: MemorixYamlConfig = {};\n let projectConfig: MemorixYamlConfig = {};\n\n // Load user-level config\n if (existsSync(userYaml)) {\n try {\n userConfig = parseYaml(readFileSync(userYaml, 'utf-8'));\n } catch (err) {\n console.error(`[memorix] Warning: Failed to parse ${userYaml}: ${err}`);\n }\n }\n\n // Load project-level config (overrides user-level)\n if (projectYaml && existsSync(projectYaml)) {\n try {\n projectConfig = parseYaml(readFileSync(projectYaml, 'utf-8'));\n } catch (err) {\n console.error(`[memorix] Warning: Failed to parse ${projectYaml}: ${err}`);\n }\n }\n\n // Shallow merge: project-level top keys override user-level\n const merged: MemorixYamlConfig = {\n ...userConfig,\n ...projectConfig,\n // Deep merge for nested objects where both exist\n llm: { ...userConfig.llm, ...projectConfig.llm },\n agent: { ...userConfig.agent, ...projectConfig.agent },\n embedding: { ...userConfig.embedding, ...projectConfig.embedding },\n git: { ...userConfig.git, ...projectConfig.git },\n codegraph: { ...userConfig.codegraph, ...projectConfig.codegraph },\n behavior: { ...userConfig.behavior, ...projectConfig.behavior },\n server: { ...userConfig.server, ...projectConfig.server },\n team: { ...userConfig.team, ...projectConfig.team },\n };\n configCache.set(resolvedRoot ?? null, merged);\n\n return merged;\n}\n\n/**\n * Reset cached YAML config (for testing or project switching).\n * Invalidates all cached entries, or a specific projectRoot if provided.\n */\nexport function resetYamlConfigCache(projectRoot?: string | null): void {\n if (projectRoot !== undefined) {\n configCache.delete(projectRoot ?? null);\n } else {\n configCache.clear();\n }\n}\n\n/**\n * Parse YAML string using gray-matter's internal js-yaml.\n * gray-matter is already a dependency — no new deps needed.\n */\nfunction parseYaml(content: string): MemorixYamlConfig {\n // gray-matter uses js-yaml internally; we import it from there\n // But for simplicity and reliability, use a basic YAML parser\n // that handles the flat config structure we need.\n try {\n const yaml = require('js-yaml');\n return yaml.load(content) as MemorixYamlConfig ?? {};\n } catch {\n // Fallback: try gray-matter which wraps js-yaml\n try {\n const matter = require('gray-matter');\n const parsed = matter(`---\\n${content}\\n---`);\n return (parsed.data as MemorixYamlConfig) ?? {};\n } catch {\n console.error('[memorix] YAML parse failed — check memorix.yml syntax');\n return {};\n }\n }\n}\n","/**\n * Project Detector\n *\n * Strict .git-based project detection.\n * No .git = not a project. No fallbacks, no accommodations.\n *\n * ID strategy:\n * - .git + remote → normalizeGitRemote(remote) (globally unique, e.g. \"user/repo\")\n * - .git + no remote → \"local/<dirname>\" (local git repo, no remote yet)\n * - no .git → null (not a project)\n */\n\nimport { execSync } from 'node:child_process';\nimport { existsSync, readFileSync, readdirSync, statSync } from 'node:fs';\nimport path from 'node:path';\nimport type { ProjectInfo, DetectionResult, DetectionFailure } from '../types.js';\n\n/**\n * Detect the current project identity from Git.\n * Returns null if no .git directory is found — caller must handle this.\n * @param cwd - Working directory to detect from (defaults to process.cwd())\n */\nexport function detectProject(cwd?: string): ProjectInfo | null {\n return detectProjectWithDiagnostics(cwd).project;\n}\n\n/**\n * Detect project with full diagnostic info.\n * Returns both the project (if found) and a failure descriptor (if not).\n * Callers can use failure.reason to produce actionable error messages.\n */\nexport function detectProjectWithDiagnostics(cwd?: string): DetectionResult {\n const basePath = cwd ?? process.cwd();\n\n // Check: does the path exist?\n if (!existsSync(basePath)) {\n return {\n project: null,\n failure: { reason: 'path_not_found', path: basePath, detail: `Path does not exist: \"${basePath}\"` },\n };\n }\n\n // Check: is it a directory?\n try {\n if (!statSync(basePath).isDirectory()) {\n return {\n project: null,\n failure: { reason: 'not_a_directory', path: basePath, detail: `Path is not a directory: \"${basePath}\"` },\n };\n }\n } catch {\n return {\n project: null,\n failure: { reason: 'path_not_found', path: basePath, detail: `Cannot stat path: \"${basePath}\"` },\n };\n }\n\n // Check: git root\n const gitRootResult = getGitRootWithDiagnostics(basePath);\n if (!gitRootResult.root) {\n return {\n project: null,\n failure: gitRootResult.failure ?? {\n reason: 'no_git',\n path: basePath,\n detail: `No .git directory found in \"${basePath}\" or any parent directory.`,\n },\n };\n }\n\n const gitRoot = gitRootResult.root;\n const gitRemote = getGitRemote(gitRoot);\n\n if (gitRemote) {\n const id = normalizeGitRemote(gitRemote);\n const name = id.split('/').pop() ?? path.basename(gitRoot);\n return { project: { id, name, gitRemote, rootPath: gitRoot }, failure: null };\n }\n\n // Git repo without remote — local-only project\n const name = path.basename(gitRoot);\n const id = `local/${name}`;\n return { project: { id, name, rootPath: gitRoot }, failure: null };\n}\n\n/**\n * Get the Git repository root directory.\n * Returns null if not inside a git repository.\n */\nfunction getGitRoot(cwd: string): string | null {\n return getGitRootWithDiagnostics(cwd).root;\n}\n\n/**\n * Get git root with diagnostic failure info.\n * Distinguishes: no_git, git_worktree_error, git_safe_directory.\n */\nfunction getGitRootWithDiagnostics(cwd: string): { root: string | null; failure: DetectionFailure | null } {\n // Fast path: walk up to find .git directory (instant, no subprocess)\n let dir = path.resolve(cwd);\n const fsRoot = path.parse(dir).root;\n while (dir !== fsRoot) {\n const gitPath = path.join(dir, '.git');\n if (existsSync(gitPath)) {\n // .git may be a file (worktree) or directory (normal repo)\n try {\n const st = statSync(gitPath);\n if (st.isDirectory() || st.isFile()) return { root: dir, failure: null };\n } catch {\n return {\n root: null,\n failure: {\n reason: 'git_worktree_error',\n path: cwd,\n detail: `Found .git at \"${gitPath}\" but cannot stat it (permission denied or broken worktree link).`,\n },\n };\n }\n }\n dir = path.dirname(dir);\n }\n\n // Slow path: git CLI for edge cases (submodules, worktrees, bare repos)\n try {\n const root = execSync('git -c safe.directory=* rev-parse --show-toplevel', {\n cwd,\n encoding: 'utf-8',\n stdio: ['pipe', 'pipe', 'pipe'],\n timeout: 5000,\n }).trim();\n return root ? { root, failure: null } : { root: null, failure: null };\n } catch (err) {\n // Inspect stderr for known git error patterns\n const msg = err instanceof Error ? err.message : String(err);\n if (msg.includes('safe.directory') || msg.includes('dubious ownership')) {\n return {\n root: null,\n failure: {\n reason: 'git_safe_directory',\n path: cwd,\n detail: `Git refuses to operate in \"${cwd}\" due to ownership/safe.directory restrictions. ` +\n 'Run: git config --global --add safe.directory \"' + cwd + '\"',\n },\n };\n }\n return {\n root: null,\n failure: { reason: 'no_git', path: cwd, detail: `No git repository found at \"${cwd}\" or any parent directory.` },\n };\n }\n}\n\n/**\n * Get the Git remote URL for the given directory.\n * Returns null if not a git repository or no remote configured.\n */\nfunction getGitRemote(cwd: string): string | null {\n // Fast path: read .git/config directly (instant, no subprocess)\n const fsRemote = readGitConfigRemote(cwd);\n if (fsRemote) return fsRemote;\n\n // Slow path: git CLI for edge cases (submodules, worktrees, non-standard layouts)\n try {\n const remote = execSync('git -c safe.directory=* remote get-url origin', {\n cwd,\n encoding: 'utf-8',\n stdio: ['pipe', 'pipe', 'pipe'],\n timeout: 5000,\n }).trim();\n return remote || null;\n } catch {\n return null;\n }\n}\n\n/**\n * Fallback: parse remote.origin.url from .git/config when git CLI fails.\n * Handles Windows \"dubious ownership\" and other permission issues.\n */\nfunction readGitConfigRemote(cwd: string): string | null {\n try {\n const configPath = path.join(cwd, '.git', 'config');\n if (!existsSync(configPath)) return null;\n const content = readFileSync(configPath, 'utf-8');\n // Parse INI-style: [remote \"origin\"] section, url = ...\n const remoteMatch = content.match(/\\[remote\\s+\"origin\"\\]([\\s\\S]*?)(?=\\n\\[|$)/);\n if (!remoteMatch) return null;\n const urlMatch = remoteMatch[1].match(/^\\s*url\\s*=\\s*(.+)$/m);\n return urlMatch ? urlMatch[1].trim() : null;\n } catch {\n return null;\n }\n}\n\n/**\n * Detect if a directory is a \"system directory\" that's clearly not a user workspace.\n * These include Windows system dirs, IDE installation dirs, and temp dirs.\n */\nexport function isSystemDirectory(dir: string): boolean {\n const lower = dir.toLowerCase().replace(/\\\\/g, '/');\n return (\n lower.includes('/windows/') || lower.endsWith('/windows') ||\n lower.includes('/program files') ||\n lower.includes('/appdata/') ||\n // IDE installation directories\n /\\/(windsurf|cursor|code|vscode)\\/\\1/i.test(lower) ||\n /\\/windsurf\\b/i.test(lower) && !lower.includes('.windsurf') ||\n // Node / npm internal paths\n lower.includes('/node_modules/') ||\n lower.includes('/nvm') ||\n // System root\n /^[a-z]:\\/$/i.test(lower)\n );\n}\n\n/**\n * Scan immediate subdirectories for a .git directory.\n * Used when the workspace root itself isn't a git repo (multi-project workspace).\n * Returns the first subdirectory containing .git, or null.\n */\nexport function findGitInSubdirs(dir: string): string | null {\n try {\n const resolved = path.resolve(dir);\n const entries = readdirSync(resolved);\n for (const entry of entries) {\n if (entry.startsWith('.')) continue; // skip hidden dirs\n const fullPath = path.join(resolved, entry);\n try {\n if (statSync(fullPath).isDirectory() && existsSync(path.join(fullPath, '.git'))) {\n return fullPath;\n }\n } catch { /* permission error, skip */ }\n }\n } catch { /* readdir failed */ }\n return null;\n}\n\n/**\n * Normalize a Git remote URL to a consistent project ID.\n *\n * Examples:\n * https://github.com/user/repo.git → user/repo\n * git@github.com:user/repo.git → user/repo\n * ssh://git@github.com/user/repo → user/repo\n */\nfunction normalizeGitRemote(remote: string): string {\n let normalized = remote;\n\n // Remove trailing .git\n normalized = normalized.replace(/\\.git$/, '');\n\n // Handle SSH format: git@github.com:user/repo\n const sshMatch = normalized.match(/^[\\w-]+@[\\w.-]+:(.+)$/);\n if (sshMatch) {\n return sshMatch[1];\n }\n\n // Handle HTTPS/SSH URL format\n try {\n const url = new URL(normalized);\n // Remove leading slash\n return url.pathname.replace(/^\\//, '');\n } catch {\n // If URL parsing fails, take last two segments\n const segments = normalized.split('/').filter(Boolean);\n return segments.slice(-2).join('/');\n }\n}\n","import { existsSync, readFileSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { getLegacyConfigJsonPath } from './config-paths.js';\n\nexport interface MemorixConfig {\n llm?: {\n provider?: string;\n apiKey?: string;\n model?: string;\n baseUrl?: string;\n };\n agent?: {\n provider?: string;\n apiKey?: string;\n model?: string;\n baseUrl?: string;\n };\n embedding?: string;\n embeddingApi?: {\n apiKey?: string;\n baseUrl?: string;\n model?: string;\n dimensions?: number;\n };\n}\n\nlet cachedConfig: MemorixConfig | null = null;\n\nexport function loadFileConfig(): MemorixConfig {\n if (cachedConfig !== null) return cachedConfig;\n\n const configPath = getLegacyConfigJsonPath(homedir());\n try {\n if (existsSync(configPath)) {\n cachedConfig = JSON.parse(readFileSync(configPath, 'utf-8'));\n return cachedConfig!;\n }\n } catch {\n // Corrupt or unreadable legacy config should not block startup.\n }\n cachedConfig = {};\n return cachedConfig;\n}\n\nexport function resetConfigCache(): void {\n cachedConfig = null;\n}\n","import { existsSync, readFileSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { getGlobalConfigTomlPath, getProjectConfigTomlPath } from './config-paths.js';\n\nexport interface MemorixTomlConfig {\n agent?: {\n provider?: string;\n model?: string;\n base_url?: string;\n api_key?: string;\n };\n memory?: {\n inject?: 'full' | 'minimal' | 'silent';\n formation?: 'active' | 'shadow' | 'fallback';\n auto_cleanup?: boolean;\n sync_advisory?: boolean;\n llm?: {\n provider?: string;\n model?: string;\n base_url?: string;\n api_key?: string;\n };\n };\n embedding?: {\n provider?: 'off' | 'api' | 'fastembed' | 'transformers' | 'auto' | string;\n model?: string;\n base_url?: string;\n api_key?: string;\n dimensions?: number;\n };\n hooks?: {\n native_memcode?: boolean;\n external_agents?: boolean;\n };\n git?: {\n auto_hook?: boolean;\n ingest_on_commit?: boolean;\n max_diff_size?: number;\n skip_merge_commits?: boolean;\n exclude_patterns?: string[];\n noise_keywords?: string[];\n };\n codegraph?: {\n exclude_patterns?: string[];\n max_file_bytes?: number;\n external_context?: 'auto' | 'off';\n external_command?: string;\n external_timeout_ms?: number;\n };\n server?: {\n transport?: 'stdio' | 'http';\n dashboard?: boolean;\n dashboard_port?: number;\n port?: number;\n };\n}\n\ninterface LoadTomlOptions {\n projectRoot?: string | null;\n homeDir?: string;\n}\n\nconst configCache = new Map<string, MemorixTomlConfig>();\n\nexport function loadTomlConfig(options: LoadTomlOptions = {}): MemorixTomlConfig {\n const homeDir = options.homeDir ?? homedir();\n const projectRoot = options.projectRoot ?? null;\n const cacheKey = `${homeDir}\\0${projectRoot ?? ''}`;\n const cached = configCache.get(cacheKey);\n if (cached) return cached;\n\n const userToml = getGlobalConfigTomlPath(homeDir);\n const projectToml = projectRoot ? getProjectConfigTomlPath(projectRoot) : null;\n\n const userConfig = existsSync(userToml) ? parseTomlConfig(readFileSync(userToml, 'utf8'), userToml) : {};\n const projectConfig = projectToml && existsSync(projectToml)\n ? parseTomlConfig(readFileSync(projectToml, 'utf8'), projectToml)\n : {};\n\n const merged = mergeTomlConfig(userConfig, projectConfig);\n configCache.set(cacheKey, merged);\n return merged;\n}\n\nexport function resetTomlConfigCache(): void {\n configCache.clear();\n}\n\nfunction mergeTomlConfig(base: MemorixTomlConfig, override: MemorixTomlConfig): MemorixTomlConfig {\n return {\n ...base,\n ...override,\n agent: { ...base.agent, ...override.agent },\n memory: {\n ...base.memory,\n ...override.memory,\n llm: { ...base.memory?.llm, ...override.memory?.llm },\n },\n embedding: { ...base.embedding, ...override.embedding },\n hooks: { ...base.hooks, ...override.hooks },\n git: { ...base.git, ...override.git },\n codegraph: { ...base.codegraph, ...override.codegraph },\n server: { ...base.server, ...override.server },\n };\n}\n\nfunction parseTomlConfig(content: string, filePath: string): MemorixTomlConfig {\n const root: Record<string, unknown> = {};\n let current: Record<string, unknown> = root;\n\n for (const [index, rawLine] of content.split(/\\r?\\n/).entries()) {\n const line = stripComment(rawLine).trim();\n if (!line) continue;\n\n const tableMatch = line.match(/^\\[([A-Za-z0-9_.-]+)\\]$/);\n if (tableMatch) {\n current = ensureTable(root, tableMatch[1].split('.'));\n continue;\n }\n\n const assignment = line.match(/^([A-Za-z0-9_-]+)\\s*=\\s*(.+)$/);\n if (!assignment) {\n throw new Error(`Invalid TOML syntax in ${filePath}:${index + 1}`);\n }\n current[assignment[1]] = parseTomlValue(assignment[2].trim(), filePath, index + 1);\n }\n\n return root as MemorixTomlConfig;\n}\n\nfunction ensureTable(root: Record<string, unknown>, path: string[]): Record<string, unknown> {\n let cursor = root;\n for (const part of path) {\n const value = cursor[part];\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n cursor[part] = {};\n }\n cursor = cursor[part] as Record<string, unknown>;\n }\n return cursor;\n}\n\nfunction parseTomlValue(raw: string, filePath: string, line: number): unknown {\n if (raw.startsWith('\"') && raw.endsWith('\"')) {\n return raw.slice(1, -1).replace(/\\\\\"/g, '\"').replace(/\\\\\\\\/g, '\\\\');\n }\n if (raw.startsWith(\"'\") && raw.endsWith(\"'\")) {\n return raw.slice(1, -1);\n }\n if (raw === 'true') return true;\n if (raw === 'false') return false;\n if (/^-?\\d+$/.test(raw)) return Number.parseInt(raw, 10);\n if (/^-?\\d+\\.\\d+$/.test(raw)) return Number.parseFloat(raw);\n if (raw.startsWith('[') && raw.endsWith(']')) {\n const body = raw.slice(1, -1).trim();\n if (!body) return [];\n return body.split(',').map((entry) => parseTomlValue(entry.trim(), filePath, line));\n }\n throw new Error(`Unsupported TOML value in ${filePath}:${line}`);\n}\n\nfunction stripComment(line: string): string {\n let quote: '\"' | \"'\" | null = null;\n let escaped = false;\n for (let i = 0; i < line.length; i++) {\n const char = line[i];\n if (escaped) {\n escaped = false;\n continue;\n }\n if (char === '\\\\' && quote === '\"') {\n escaped = true;\n continue;\n }\n if (char === '\"' || char === \"'\") {\n if (quote === char) quote = null;\n else if (quote === null) quote = char;\n continue;\n }\n if (char === '#' && quote === null) {\n return line.slice(0, i);\n }\n }\n return line;\n}\n","import { homedir } from 'node:os';\nimport { existsSync } from 'node:fs';\nimport { detectProject } from '../project/detector.js';\nimport {\n getGlobalConfigTomlPath,\n getGlobalYamlPath,\n getLegacyConfigJsonPath,\n getProjectConfigTomlPath,\n getProjectYamlPath,\n} from './config-paths.js';\nimport { loadFileConfig } from './legacy-loader.js';\nimport { loadTomlConfig } from './toml-loader.js';\nimport { loadYamlConfig } from './yaml-loader.js';\nimport { loadDotenv } from './dotenv-loader.js';\n\nexport interface ResolvedLaneOptions {\n projectRoot?: string | null;\n homeDir?: string;\n}\n\nexport interface ResolvedMemorixConfig {\n agent: {\n provider?: string;\n model?: string;\n baseUrl?: string;\n apiKey?: string;\n };\n memory: {\n inject?: 'full' | 'minimal' | 'silent';\n formation?: 'active' | 'shadow' | 'fallback';\n autoCleanup?: boolean;\n syncAdvisory?: boolean;\n llm: {\n provider?: string;\n model?: string;\n baseUrl?: string;\n apiKey?: string;\n };\n };\n embedding: {\n provider?: 'off' | 'fastembed' | 'transformers' | 'api' | 'auto' | string;\n model?: string;\n baseUrl?: string;\n apiKey?: string;\n dimensions?: number;\n };\n git: {\n autoHook?: boolean;\n ingestOnCommit?: boolean;\n maxDiffSize?: number;\n skipMergeCommits?: boolean;\n excludePatterns?: string[];\n noiseKeywords?: string[];\n };\n codegraph: {\n excludePatterns?: string[];\n maxFileBytes?: number;\n externalContext: 'auto' | 'off';\n externalCommand?: string;\n externalTimeoutMs?: number;\n };\n server: {\n transport?: 'stdio' | 'http';\n dashboard?: boolean;\n dashboardPort?: number;\n port?: number;\n };\n sources: {\n toml: string[];\n legacy: string[];\n env: string[];\n };\n}\n\nexport function getResolvedConfig(options: ResolvedLaneOptions = {}): ResolvedMemorixConfig {\n const homeDir = options.homeDir ?? homedir();\n const projectRoot = options.projectRoot === undefined ? detectProject()?.rootPath ?? null : options.projectRoot;\n\n // Make .env a first-class config source so every consumer of this resolved\n // config (embedding API key, LLM base URL, etc.) sees values from\n // ~/.memorix/.env / <project>/.env. loadDotenv() is idempotent — guarded by\n // a module-level `dotenvLoaded` flag — so repeat calls within one process\n // are essentially free, and it never overrides an already-set process env.\n loadDotenv(projectRoot === null ? undefined : projectRoot ?? undefined, { userHomeDir: homeDir });\n\n const toml = loadTomlConfig({ projectRoot: projectRoot ?? null, homeDir });\n const yaml = loadYamlConfig(projectRoot ?? null);\n const legacy = loadFileConfig();\n const embeddingBaseUrl = first(process.env.MEMORIX_EMBEDDING_BASE_URL, toml.embedding?.base_url, yaml.embedding?.baseUrl, legacy.embeddingApi?.baseUrl);\n const openRouterEmbeddingApiKey = isOpenRouterUrl(embeddingBaseUrl) ? process.env.OPENROUTER_API_KEY : undefined;\n\n const resolved: ResolvedMemorixConfig = {\n agent: {\n provider: first(\n process.env.MEMORIX_AGENT_PROVIDER,\n process.env.MEMORIX_AGENT_LLM_PROVIDER,\n toml.agent?.provider,\n yaml.agent?.provider,\n legacy.agent?.provider,\n ),\n model: first(\n process.env.MEMORIX_AGENT_MODEL,\n process.env.MEMORIX_AGENT_LLM_MODEL,\n toml.agent?.model,\n yaml.agent?.model,\n legacy.agent?.model,\n ),\n baseUrl: first(\n process.env.MEMORIX_AGENT_BASE_URL,\n process.env.MEMORIX_AGENT_LLM_BASE_URL,\n toml.agent?.base_url,\n yaml.agent?.baseUrl,\n legacy.agent?.baseUrl,\n ),\n apiKey: first(\n process.env.MEMORIX_AGENT_API_KEY,\n process.env.MEMORIX_AGENT_LLM_API_KEY,\n toml.agent?.api_key,\n yaml.agent?.apiKey,\n legacy.agent?.apiKey,\n ),\n },\n memory: {\n inject: first(toml.memory?.inject, yaml.behavior?.sessionInject),\n formation: first(toml.memory?.formation, yaml.behavior?.formationMode),\n autoCleanup: firstBool(toml.memory?.auto_cleanup, yaml.behavior?.autoCleanup),\n syncAdvisory: firstBool(toml.memory?.sync_advisory, yaml.behavior?.syncAdvisory),\n llm: {\n provider: first(process.env.MEMORIX_LLM_PROVIDER, toml.memory?.llm?.provider, yaml.llm?.provider, legacy.llm?.provider),\n model: first(process.env.MEMORIX_LLM_MODEL, toml.memory?.llm?.model, yaml.llm?.model, legacy.llm?.model),\n baseUrl: first(process.env.MEMORIX_LLM_BASE_URL, toml.memory?.llm?.base_url, yaml.llm?.baseUrl, legacy.llm?.baseUrl),\n apiKey: first(\n process.env.MEMORIX_LLM_API_KEY,\n process.env.MEMORIX_API_KEY,\n toml.memory?.llm?.api_key,\n yaml.llm?.apiKey,\n legacy.llm?.apiKey,\n process.env.OPENAI_API_KEY,\n process.env.ANTHROPIC_API_KEY,\n process.env.OPENROUTER_API_KEY,\n ),\n },\n },\n embedding: {\n provider: first(process.env.MEMORIX_EMBEDDING, toml.embedding?.provider, yaml.embedding?.provider, legacy.embedding, 'off'),\n model: first(process.env.MEMORIX_EMBEDDING_MODEL, toml.embedding?.model, yaml.embedding?.model, legacy.embeddingApi?.model),\n baseUrl: embeddingBaseUrl,\n apiKey: first(process.env.MEMORIX_EMBEDDING_API_KEY, toml.embedding?.api_key, yaml.embedding?.apiKey, legacy.embeddingApi?.apiKey, openRouterEmbeddingApiKey),\n dimensions: firstNumber(parseNumber(process.env.MEMORIX_EMBEDDING_DIMENSIONS), toml.embedding?.dimensions, yaml.embedding?.dimensions, legacy.embeddingApi?.dimensions),\n },\n git: {\n autoHook: firstBool(toml.git?.auto_hook, yaml.git?.autoHook),\n ingestOnCommit: firstBool(toml.git?.ingest_on_commit, yaml.git?.ingestOnCommit),\n maxDiffSize: firstNumber(toml.git?.max_diff_size, yaml.git?.maxDiffSize),\n skipMergeCommits: firstBool(toml.git?.skip_merge_commits, yaml.git?.skipMergeCommits),\n excludePatterns: firstArray(toml.git?.exclude_patterns, yaml.git?.excludePatterns),\n noiseKeywords: firstArray(toml.git?.noise_keywords, yaml.git?.noiseKeywords),\n },\n codegraph: {\n excludePatterns: firstArray(toml.codegraph?.exclude_patterns, yaml.codegraph?.excludePatterns),\n maxFileBytes: firstNumber(toml.codegraph?.max_file_bytes, yaml.codegraph?.maxFileBytes),\n externalContext: first(\n normalizeExternalContext(process.env.MEMORIX_CODEGRAPH_EXTERNAL_CONTEXT),\n toml.codegraph?.external_context,\n yaml.codegraph?.externalContext,\n 'auto',\n )!,\n externalCommand: first(\n process.env.MEMORIX_CODEGRAPH_EXTERNAL_COMMAND,\n toml.codegraph?.external_command,\n yaml.codegraph?.externalCommand,\n ),\n externalTimeoutMs: firstNumber(\n parseNumber(process.env.MEMORIX_CODEGRAPH_EXTERNAL_TIMEOUT_MS),\n toml.codegraph?.external_timeout_ms,\n yaml.codegraph?.externalTimeoutMs,\n ),\n },\n server: {\n transport: first(toml.server?.transport, yaml.server?.transport),\n dashboard: firstBool(toml.server?.dashboard, yaml.server?.dashboard),\n dashboardPort: firstNumber(toml.server?.dashboard_port, yaml.server?.dashboardPort),\n port: firstNumber(toml.server?.port, yaml.server?.port),\n },\n sources: {\n toml: getExistingConfigSources([\n getGlobalConfigTomlPath(homeDir),\n ...(projectRoot ? [getProjectConfigTomlPath(projectRoot)] : []),\n ]),\n legacy: getExistingConfigSources([\n getGlobalYamlPath(homeDir),\n ...(projectRoot ? [getProjectYamlPath(projectRoot)] : []),\n getLegacyConfigJsonPath(homeDir),\n ]),\n env: getEnvSourceNames(),\n },\n };\n\n return resolved;\n}\n\nexport function getResolvedConfigForCwd(cwd = process.cwd()): ResolvedMemorixConfig {\n const project = detectProject(cwd);\n return getResolvedConfig({ projectRoot: project?.rootPath ?? null });\n}\n\nexport function getResolvedAgentLane(options: ResolvedLaneOptions = {}): ResolvedMemorixConfig['agent'] {\n const resolved = getResolvedConfig(options);\n return {\n ...resolved.agent,\n provider: resolved.agent.provider ?? resolved.memory.llm.provider,\n model: resolved.agent.model ?? resolved.memory.llm.model,\n baseUrl: resolved.agent.baseUrl ?? resolved.memory.llm.baseUrl,\n apiKey: resolved.agent.apiKey ?? resolved.memory.llm.apiKey,\n };\n}\n\nexport function getResolvedMemoryLane(options: ResolvedLaneOptions = {}): ResolvedMemorixConfig['memory'] {\n return getResolvedConfig(options).memory;\n}\n\nexport function getResolvedEmbeddingLane(options: ResolvedLaneOptions = {}): ResolvedMemorixConfig['embedding'] {\n return getResolvedConfig(options).embedding;\n}\n\nexport function resetResolvedConfigCache(): void {\n // Kept as a public test helper. File-level caches live in individual loaders.\n}\n\nfunction first<T>(...values: Array<T | null | undefined | ''>): T | undefined {\n return values.find((value): value is T => value !== undefined && value !== null && value !== '');\n}\n\nfunction firstBool(...values: Array<boolean | undefined>): boolean | undefined {\n return values.find((value): value is boolean => value !== undefined);\n}\n\nfunction firstNumber(...values: Array<number | undefined | null>): number | undefined {\n return values.find((value): value is number => value !== undefined && value !== null && Number.isFinite(value));\n}\n\nfunction firstArray<T>(...values: Array<T[] | undefined>): T[] | undefined {\n return values.find((value): value is T[] => Array.isArray(value));\n}\n\nfunction parseNumber(value: string | undefined): number | undefined {\n if (!value) return undefined;\n const parsed = Number.parseInt(value, 10);\n return Number.isFinite(parsed) ? parsed : undefined;\n}\n\nfunction getExistingConfigSources(paths: string[]): string[] {\n return paths.filter((filePath) => existsSync(filePath));\n}\n\nfunction getEnvSourceNames(): string[] {\n return [\n 'MEMORIX_AGENT_PROVIDER',\n 'MEMORIX_AGENT_MODEL',\n 'MEMORIX_AGENT_API_KEY',\n 'MEMORIX_AGENT_BASE_URL',\n 'MEMORIX_AGENT_LLM_PROVIDER',\n 'MEMORIX_AGENT_LLM_MODEL',\n 'MEMORIX_AGENT_LLM_API_KEY',\n 'MEMORIX_AGENT_LLM_BASE_URL',\n 'MEMORIX_LLM_PROVIDER',\n 'MEMORIX_LLM_MODEL',\n 'MEMORIX_LLM_API_KEY',\n 'MEMORIX_LLM_BASE_URL',\n 'MEMORIX_API_KEY',\n 'MEMORIX_EMBEDDING',\n 'MEMORIX_EMBEDDING_API_KEY',\n 'MEMORIX_EMBEDDING_BASE_URL',\n 'MEMORIX_EMBEDDING_MODEL',\n 'MEMORIX_EMBEDDING_DIMENSIONS',\n 'MEMORIX_CODEGRAPH_EXTERNAL_CONTEXT',\n 'MEMORIX_CODEGRAPH_EXTERNAL_COMMAND',\n 'MEMORIX_CODEGRAPH_EXTERNAL_TIMEOUT_MS',\n 'OPENROUTER_API_KEY',\n ].filter((name) => process.env[name]);\n}\n\nfunction isOpenRouterUrl(value: string | undefined): boolean {\n if (!value) return false;\n try {\n const url = new URL(value);\n return url.hostname.toLowerCase() === 'openrouter.ai' || url.hostname.toLowerCase().endsWith('.openrouter.ai');\n } catch {\n return /(^|\\.)openrouter\\.ai(?::|\\/|$)/i.test(value);\n }\n}\n\nfunction normalizeExternalContext(value: string | undefined): 'auto' | 'off' | undefined {\n const normalized = value?.trim().toLowerCase();\n if (normalized === 'auto' || normalized === 'off') return normalized;\n return undefined;\n}\n","/**\n * Unified Configuration Reader\n *\n * Priority chain (highest wins):\n * 1. Environment variables (from MCP JSON `env` field or system env)\n * 2. memorix.toml / ~/.memorix/config.toml\n * 3. memorix.yml / ~/.memorix/memorix.yml compatibility files\n * 4. ~/.memorix/config.json legacy file\n * 5. Hardcoded defaults\n */\n\nimport { loadYamlConfig, type MemorixYamlConfig } from './config/yaml-loader.js';\nimport {\n getResolvedAgentLane,\n getResolvedConfig,\n getResolvedEmbeddingLane,\n getResolvedMemoryLane,\n type ResolvedLaneOptions,\n} from './config/resolved-config.js';\nexport { loadDotenv, resetDotenv, getLoadedEnvFiles } from './config/dotenv-loader.js';\nexport { loadFileConfig, resetConfigCache, type MemorixConfig } from './config/legacy-loader.js';\n\n// ─── Resolved Getters ────────────────────────────────────────────────\n\n/** Memory/background LLM API key: env > memorix.yml > config.json > provider env fallbacks */\nexport function getLLMApiKey(): string | undefined {\n return getResolvedMemoryLane().llm.apiKey;\n}\n\n/** LLM provider: env > memorix.yml > config.json > auto-detect */\nexport function getLLMProvider(): string {\n const provider = getResolvedMemoryLane().llm.provider;\n if (provider) return provider;\n // Auto-detect from env var names\n if (process.env.ANTHROPIC_API_KEY && !process.env.OPENAI_API_KEY) return 'anthropic';\n if (process.env.OPENROUTER_API_KEY && !process.env.OPENAI_API_KEY) return 'openrouter';\n return 'openai';\n}\n\n/** LLM model: env > memorix.yml > config.json > provider default */\nexport function getLLMModel(providerDefault: string): string {\n return getResolvedMemoryLane().llm.model || providerDefault;\n}\n\n/** LLM base URL: env > memorix.yml > config.json > provider default */\nexport function getLLMBaseUrl(providerDefault: string): string {\n return getResolvedMemoryLane().llm.baseUrl || providerDefault;\n}\n\n/** TUI/chat agent API key: agent env > agent config > memory LLM fallback */\nexport function getAgentLLMApiKey(): string | undefined {\n return getResolvedAgentLane().apiKey;\n}\n\n/** TUI/chat agent provider: agent env > agent config > memory LLM fallback */\nexport function getAgentLLMProvider(): string {\n return getResolvedAgentLane().provider || getLLMProvider();\n}\n\n/** TUI/chat agent model: agent env > agent config > memory LLM fallback */\nexport function getAgentLLMModel(providerDefault: string): string {\n return getResolvedAgentLane().model || getLLMModel(providerDefault);\n}\n\n/** TUI/chat agent base URL: agent env > agent config > memory LLM fallback */\nexport function getAgentLLMBaseUrl(providerDefault: string): string {\n return getResolvedAgentLane().baseUrl || getLLMBaseUrl(providerDefault);\n}\n\n/** Embedding mode: env > memorix.yml > config.json > 'off' */\nexport function getEmbeddingMode(): 'off' | 'fastembed' | 'transformers' | 'api' | 'auto' {\n const provider = getResolvedEmbeddingLane().provider?.toLowerCase()?.trim();\n if (provider === 'fastembed' || provider === 'transformers' || provider === 'api' || provider === 'auto') return provider;\n return 'off';\n}\n\n/** Embedding API key: embedding lane only. Do not borrow memory LLM or agent keys. */\nexport function getEmbeddingApiKey(): string | undefined {\n return getResolvedEmbeddingLane().apiKey;\n}\n\n/** Embedding base URL: env > memorix.yml > config.json > provider default */\nexport function getEmbeddingBaseUrl(): string {\n return getResolvedEmbeddingLane().baseUrl || 'https://api.openai.com/v1';\n}\n\n/** Embedding model: env > memorix.yml > config.json > default */\nexport function getEmbeddingModel(): string {\n return getResolvedEmbeddingLane().model || 'text-embedding-3-small';\n}\n\n/** Embedding dimensions override: env > memorix.yml > config.json > null (auto-detect) */\nexport function getEmbeddingDimensions(): number | null {\n return getResolvedEmbeddingLane().dimensions ?? null;\n}\n\n// ─── YAML-specific getters (new config sections) ────────────────────\n\n/** Git-Memory pipeline config */\nexport function getGitConfig(options: ResolvedLaneOptions = {}): NonNullable<MemorixYamlConfig['git']> {\n const git = getResolvedConfig(options).git;\n return {\n autoHook: git.autoHook,\n ingestOnCommit: git.ingestOnCommit,\n maxDiffSize: git.maxDiffSize,\n skipMergeCommits: git.skipMergeCommits,\n excludePatterns: git.excludePatterns,\n noiseKeywords: git.noiseKeywords,\n };\n}\n\n/** Server config */\nexport function getServerConfig(): NonNullable<MemorixYamlConfig['server']> {\n const server = getResolvedConfig().server;\n return {\n transport: server.transport,\n dashboard: server.dashboard,\n dashboardPort: server.dashboardPort,\n port: server.port,\n };\n}\n\n/** Team config */\nexport function getTeamConfig(): NonNullable<MemorixYamlConfig['team']> {\n return loadYamlConfig().team ?? {};\n}\n\n/** Get the full resolved YAML config (for status display) */\nexport { loadYamlConfig } from './config/yaml-loader.js';\n","/**\n * LLM Provider\n *\n * Abstraction layer for LLM-enhanced memory management.\n * Supports OpenAI-compatible APIs (OpenAI, Anthropic via proxy, local models).\n *\n * This is the optional \"premium\" path — Memorix works without it,\n * but with an LLM configured, memory quality approaches Mem0/Cipher level.\n */\n\nimport {\n getAgentLLMApiKey,\n getAgentLLMBaseUrl,\n getAgentLLMModel,\n getAgentLLMProvider,\n getLLMApiKey,\n getLLMBaseUrl,\n getLLMModel,\n getLLMProvider,\n} from '../config.js';\n\nexport interface LLMConfig {\n provider: 'openai' | 'anthropic' | 'openrouter' | 'custom';\n apiKey: string;\n model?: string;\n baseUrl?: string;\n}\n\nconst LLM_TIMEOUT_DEFAULT_MS = 30_000;\nconst LLM_TIMEOUT_MIN_MS = 1_000;\nconst LLM_TIMEOUT_MAX_MS = 300_000;\nconst MAX_LLM_RESPONSE_BYTES = 2 * 1024 * 1024;\n\n/**\n * Parse and validate MEMORIX_LLM_TIMEOUT_MS environment variable.\n * - Must be a valid integer in the range 1000–300000ms.\n * - Non-integer or out-of-range values log a warning and fall back to the default.\n * Default: 30000ms (30s) — allows for proxy routing and cold starts.\n */\nexport function parseLLMTimeoutMs(raw: string | undefined): number {\n if (raw === undefined || raw.trim() === '') return LLM_TIMEOUT_DEFAULT_MS;\n const parsed = Number(raw);\n if (!Number.isInteger(parsed) || Number.isNaN(parsed)) {\n console.warn(\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.`,\n );\n return LLM_TIMEOUT_DEFAULT_MS;\n }\n if (parsed < LLM_TIMEOUT_MIN_MS) return LLM_TIMEOUT_MIN_MS;\n if (parsed > LLM_TIMEOUT_MAX_MS) return LLM_TIMEOUT_MAX_MS;\n return parsed;\n}\n\nconst LLM_CALL_TIMEOUT_MS = parseLLMTimeoutMs(process.env.MEMORIX_LLM_TIMEOUT_MS);\n\nexport interface LLMResponse {\n content: string;\n usage?: { promptTokens: number; completionTokens: number };\n}\n\n/** A single tool call requested by the LLM */\nexport interface ToolCall {\n id: string;\n name: string;\n arguments: string; // JSON string\n}\n\n/** Response from callLLMWithTools — may contain text, tool calls, or both */\nexport interface LLMToolResponse {\n content: string;\n toolCalls: ToolCall[];\n stopReason: 'end_turn' | 'tool_use' | 'stop' | 'unknown';\n usage?: { promptTokens: number; completionTokens: number };\n}\n\n/** Streaming event from callLLMWithToolsStream */\nexport type LLMStreamEvent =\n | { type: 'text'; content: string }\n | { type: 'tool_call'; toolCall: ToolCall }\n | { type: 'done'; response: LLMToolResponse };\n\nasync function readResponseText(response: Response, signal?: AbortSignal, maxBytes = MAX_LLM_RESPONSE_BYTES): Promise<string> {\n const contentLength = response.headers.get('content-length');\n if (contentLength && Number(contentLength) > maxBytes) {\n throw new Error(`LLM response too large (${contentLength} bytes)`);\n }\n\n const reader = response.body?.getReader();\n if (!reader) {\n signal?.throwIfAborted();\n return response.text();\n }\n\n const decoder = new TextDecoder();\n const chunks: string[] = [];\n let bytesRead = 0;\n const abortReader = () => {\n void reader.cancel(signal?.reason).catch(() => undefined);\n };\n\n signal?.addEventListener('abort', abortReader, { once: true });\n\n try {\n while (true) {\n signal?.throwIfAborted();\n const { value, done } = await reader.read();\n if (done) break;\n signal?.throwIfAborted();\n if (!value) continue;\n bytesRead += value.byteLength;\n if (bytesRead > maxBytes) {\n await reader.cancel('response too large').catch(() => undefined);\n throw new Error(`LLM response exceeded ${maxBytes} bytes`);\n }\n chunks.push(decoder.decode(value, { stream: true }));\n }\n\n chunks.push(decoder.decode());\n signal?.throwIfAborted();\n return chunks.join('');\n } finally {\n signal?.removeEventListener('abort', abortReader);\n reader.releaseLock();\n }\n}\n\nasync function readResponseJson<T>(response: Response, signal?: AbortSignal, maxBytes = MAX_LLM_RESPONSE_BYTES): Promise<T> {\n const text = await readResponseText(response, signal, maxBytes);\n return JSON.parse(text) as T;\n}\n\n/**\n * Call the LLM with tools in streaming mode.\n * Yields text chunks as they arrive, then a final 'done' event with the complete response.\n * Tool calls are accumulated and yielded at the end.\n */\nexport async function* callLLMWithToolsStream(\n messages: ChatMessage[],\n tools: ToolDefinition[],\n): AsyncGenerator<LLMStreamEvent, void, undefined> {\n if (!currentConfig) {\n throw new Error('LLM not configured. Set MEMORIX_LLM_API_KEY or OPENAI_API_KEY.');\n }\n\n if (currentConfig.provider === 'anthropic') {\n yield* callAnthropicWithToolsStream(messages, tools);\n return;\n }\n\n yield* callOpenAIWithToolsStream(messages, tools);\n}\n\n/** Tool definition for LLM function calling */\nexport interface ToolDefinition {\n name: string;\n description: string;\n parameters: Record<string, unknown>; // JSON Schema object\n}\n\n/** Chat message for multi-turn tool-use conversations */\nexport interface ChatMessage {\n role: 'system' | 'user' | 'assistant' | 'tool';\n content: string;\n toolCallId?: string; // for role='tool': which call this result is for\n toolCalls?: ToolCall[]; // for role='assistant': tool calls made\n name?: string; // for role='tool': function name\n}\n\n/** Provider defaults per provider type */\nconst PROVIDER_DEFAULTS: Record<string, { baseUrl: string; model: string }> = {\n openai: { baseUrl: 'https://api.openai.com/v1', model: 'gpt-4.1-nano' },\n anthropic: { baseUrl: 'https://api.anthropic.com/v1', model: 'claude-3-5-haiku-latest' },\n openrouter: { baseUrl: 'https://openrouter.ai/api/v1', model: 'openai/gpt-4.1-nano' },\n custom: { baseUrl: 'http://localhost:11434/v1', model: 'llama3' },\n};\n\nlet currentConfig: LLMConfig | null = null;\n\nexport type LLMConfigScope = 'memory' | 'agent';\n\nexport interface InitLLMOptions {\n scope?: LLMConfigScope;\n}\n\n/**\n * Initialize the LLM provider from environment variables.\n * Returns null if no API key is configured — Memorix gracefully degrades.\n */\nexport function initLLM(options: InitLLMOptions = {}): LLMConfig | null {\n const scope = options.scope ?? 'memory';\n const apiKey = scope === 'agent' ? getAgentLLMApiKey() : getLLMApiKey();\n if (!apiKey) {\n currentConfig = null;\n return null;\n }\n\n const provider = (scope === 'agent' ? getAgentLLMProvider() : getLLMProvider()) as LLMConfig['provider'];\n const defaults = PROVIDER_DEFAULTS[provider] ?? PROVIDER_DEFAULTS.openai;\n\n currentConfig = {\n provider,\n apiKey,\n model: scope === 'agent' ? getAgentLLMModel(defaults.model) : getLLMModel(defaults.model),\n baseUrl: scope === 'agent' ? getAgentLLMBaseUrl(defaults.baseUrl) : getLLMBaseUrl(defaults.baseUrl),\n };\n\n return currentConfig;\n}\n\n/**\n * Check if LLM is available.\n */\nexport function isLLMEnabled(): boolean {\n return currentConfig !== null;\n}\n\n/**\n * Get current LLM config (for display/debug).\n */\nexport function getLLMConfig(): LLMConfig | null {\n return currentConfig;\n}\n\n/**\n * Set LLM config directly (for testing or programmatic use).\n */\nexport function setLLMConfig(config: LLMConfig | null): void {\n currentConfig = config;\n}\n\n/**\n * Call the LLM with a prompt.\n * Uses OpenAI-compatible chat completions API (works with OpenRouter, Ollama, etc.)\n *\n * For Anthropic, we use their Messages API directly.\n */\nexport async function callLLM(\n systemPrompt: string,\n userMessage: string,\n): Promise<LLMResponse> {\n if (!currentConfig) {\n throw new Error('LLM not configured. Set MEMORIX_LLM_API_KEY or OPENAI_API_KEY.');\n }\n\n if (currentConfig.provider === 'anthropic') {\n return callAnthropic(systemPrompt, userMessage);\n }\n\n return callOpenAICompatible(systemPrompt, userMessage);\n}\n\n/**\n * OpenAI-compatible API call (works with OpenAI, OpenRouter, Ollama, etc.)\n */\nasync function callOpenAICompatible(\n systemPrompt: string,\n userMessage: string,\n): Promise<LLMResponse> {\n const config = currentConfig!;\n // Auto-fix: append /v1 if baseUrl doesn't end with it (common user mistake)\n let base = config.baseUrl!.replace(/\\/+$/, '');\n if (!base.endsWith('/v1')) base += '/v1';\n const url = `${base}/chat/completions`;\n\n const response = await fetch(url, {\n signal: AbortSignal.timeout(LLM_CALL_TIMEOUT_MS),\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${config.apiKey}`,\n },\n body: JSON.stringify({\n model: config.model,\n messages: [\n { role: 'system', content: systemPrompt },\n { role: 'user', content: userMessage },\n ],\n temperature: 0.1,\n max_tokens: 1024,\n }),\n });\n\n if (!response.ok) {\n const error = await readResponseText(response, undefined, 64 * 1024).catch(() => 'unknown error');\n throw new Error(`LLM API error (${response.status}): ${error}`);\n }\n\n const data = await readResponseJson<{\n choices: Array<{ message: { content: string } }>;\n usage?: { prompt_tokens: number; completion_tokens: number };\n }>(response);\n\n return {\n content: data.choices[0]?.message?.content ?? '',\n usage: data.usage ? {\n promptTokens: data.usage.prompt_tokens,\n completionTokens: data.usage.completion_tokens,\n } : undefined,\n };\n}\n\n/**\n * Anthropic Messages API call.\n */\nasync function callAnthropic(\n systemPrompt: string,\n userMessage: string,\n): Promise<LLMResponse> {\n const config = currentConfig!;\n const url = `${config.baseUrl}/messages`;\n\n const response = await fetch(url, {\n signal: AbortSignal.timeout(LLM_CALL_TIMEOUT_MS),\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': config.apiKey,\n 'anthropic-version': '2023-06-01',\n },\n body: JSON.stringify({\n model: config.model,\n system: systemPrompt,\n messages: [\n { role: 'user', content: userMessage },\n ],\n temperature: 0.1,\n max_tokens: 1024,\n }),\n });\n\n if (!response.ok) {\n const error = await readResponseText(response, undefined, 64 * 1024).catch(() => 'unknown error');\n throw new Error(`Anthropic API error (${response.status}): ${error}`);\n }\n\n const data = await readResponseJson<{\n content: Array<{ text: string }>;\n usage?: { input_tokens: number; output_tokens: number };\n }>(response);\n\n return {\n content: data.content[0]?.text ?? '',\n usage: data.usage ? {\n promptTokens: data.usage.input_tokens,\n completionTokens: data.usage.output_tokens,\n } : undefined,\n };\n}\n\n/**\n * Call the LLM with tool definitions (agentic harness pattern).\n *\n * The LLM can decide to call tools or respond directly.\n * Returns structured response with tool_calls for the agentic loop.\n */\nexport async function callLLMWithTools(\n messages: ChatMessage[],\n tools: ToolDefinition[],\n signal?: AbortSignal,\n): Promise<LLMToolResponse> {\n if (!currentConfig) {\n throw new Error('LLM not configured. Set MEMORIX_LLM_API_KEY or OPENAI_API_KEY.');\n }\n\n if (currentConfig.provider === 'anthropic') {\n return callAnthropicWithTools(messages, tools, signal);\n }\n\n return callOpenAIWithTools(messages, tools, signal);\n}\n\n/**\n * OpenAI-compatible tool calling (works with OpenAI, OpenRouter, Ollama, etc.)\n */\nasync function callOpenAIWithTools(\n messages: ChatMessage[],\n tools: ToolDefinition[],\n signal?: AbortSignal,\n): Promise<LLMToolResponse> {\n const config = currentConfig!;\n let base = config.baseUrl!.replace(/\\/+$/, '');\n if (!base.endsWith('/v1')) base += '/v1';\n const url = `${base}/chat/completions`;\n\n // Convert ChatMessage[] to OpenAI format\n const openaiMessages: Array<Record<string, unknown>> = messages.map((msg) => {\n if (msg.role === 'tool') {\n return { role: 'tool', content: msg.content, tool_call_id: msg.toolCallId };\n }\n if (msg.role === 'assistant' && msg.toolCalls && msg.toolCalls.length > 0) {\n return {\n role: 'assistant',\n content: msg.content || null,\n tool_calls: msg.toolCalls.map((tc) => ({\n id: tc.id,\n type: 'function',\n function: { name: tc.name, arguments: tc.arguments },\n })),\n };\n }\n return { role: msg.role, content: msg.content };\n });\n\n const openaiTools = tools.map((t) => ({\n type: 'function' as const,\n function: { name: t.name, description: t.description, parameters: t.parameters },\n }));\n\n const fetchSignal = signal\n ? AbortSignal.any([signal, AbortSignal.timeout(LLM_CALL_TIMEOUT_MS)])\n : AbortSignal.timeout(LLM_CALL_TIMEOUT_MS);\n\n const response = await fetch(url, {\n signal: fetchSignal,\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${config.apiKey}`,\n },\n body: JSON.stringify({\n model: config.model,\n messages: openaiMessages,\n tools: openaiTools.length > 0 ? openaiTools : undefined,\n temperature: 0.3,\n max_tokens: 2048,\n }),\n });\n\n if (!response.ok) {\n const error = await readResponseText(response, signal, 64 * 1024).catch(() => 'unknown error');\n throw new Error(`LLM tool-call API error (${response.status}): ${error}`);\n }\n\n const data = await readResponseJson<{\n choices: Array<{\n message: {\n content: string | null;\n tool_calls?: Array<{\n id: string;\n type: string;\n function: { name: string; arguments: string };\n }>;\n };\n finish_reason: string;\n }>;\n usage?: { prompt_tokens: number; completion_tokens: number };\n }>(response, signal);\n\n const choice = data.choices[0];\n const content = choice?.message?.content ?? '';\n const toolCalls: ToolCall[] = (choice?.message?.tool_calls ?? []).map((tc: { id: string; function: { name: string; arguments: string } }) => ({\n id: tc.id,\n name: tc.function.name,\n arguments: tc.function.arguments,\n }));\n\n const stopReason = choice?.finish_reason === 'tool_calls' ? 'tool_use'\n : choice?.finish_reason === 'stop' ? 'stop'\n : 'unknown';\n\n return {\n content,\n toolCalls,\n stopReason,\n usage: data.usage ? {\n promptTokens: data.usage.prompt_tokens,\n completionTokens: data.usage.completion_tokens,\n } : undefined,\n };\n}\n\n/**\n * Anthropic tool calling (Messages API with tool_use).\n */\nasync function callAnthropicWithTools(\n messages: ChatMessage[],\n tools: ToolDefinition[],\n signal?: AbortSignal,\n): Promise<LLMToolResponse> {\n const config = currentConfig!;\n const url = `${config.baseUrl}/messages`;\n\n // Separate system message from the rest\n const systemContent = messages.find((m) => m.role === 'system')?.content ?? '';\n const nonSystemMessages = messages.filter((m) => m.role !== 'system');\n\n // Convert to Anthropic message format\n const anthropicMessages: Array<Record<string, unknown>> = [];\n for (const msg of nonSystemMessages) {\n if (msg.role === 'user') {\n anthropicMessages.push({ role: 'user', content: msg.content });\n } else if (msg.role === 'assistant') {\n const contentBlocks: Array<Record<string, unknown>> = [];\n if (msg.content) contentBlocks.push({ type: 'text', text: msg.content });\n if (msg.toolCalls) {\n for (const tc of msg.toolCalls) {\n contentBlocks.push({\n type: 'tool_use',\n id: tc.id,\n name: tc.name,\n input: JSON.parse(tc.arguments),\n });\n }\n }\n anthropicMessages.push({ role: 'assistant', content: contentBlocks });\n } else if (msg.role === 'tool') {\n anthropicMessages.push({\n role: 'user',\n content: [{\n type: 'tool_result',\n tool_use_id: msg.toolCallId,\n content: msg.content,\n }],\n });\n }\n }\n\n const anthropicTools = tools.map((t) => ({\n name: t.name,\n description: t.description,\n input_schema: t.parameters,\n }));\n\n const fetchSignal = signal\n ? AbortSignal.any([signal, AbortSignal.timeout(LLM_CALL_TIMEOUT_MS)])\n : AbortSignal.timeout(LLM_CALL_TIMEOUT_MS);\n\n const response = await fetch(url, {\n signal: fetchSignal,\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': config.apiKey,\n 'anthropic-version': '2023-06-01',\n },\n body: JSON.stringify({\n model: config.model,\n system: systemContent,\n messages: anthropicMessages,\n tools: anthropicTools.length > 0 ? anthropicTools : undefined,\n temperature: 0.3,\n max_tokens: 2048,\n }),\n });\n\n if (!response.ok) {\n const error = await readResponseText(response, signal, 64 * 1024).catch(() => 'unknown error');\n throw new Error(`Anthropic tool-call API error (${response.status}): ${error}`);\n }\n\n const data = await readResponseJson<{\n content: Array<{ type: string; text?: string; id?: string; name?: string; input?: unknown }>;\n stop_reason: string;\n usage?: { input_tokens: number; output_tokens: number };\n }>(response, signal);\n\n let content = '';\n const toolCalls: ToolCall[] = [];\n for (const block of data.content) {\n if (block.type === 'text' && block.text) {\n content += block.text;\n } else if (block.type === 'tool_use' && block.id && block.name) {\n toolCalls.push({\n id: block.id,\n name: block.name,\n arguments: JSON.stringify(block.input ?? {}),\n });\n }\n }\n\n const stopReason = data.stop_reason === 'tool_use' ? 'tool_use'\n : data.stop_reason === 'end_turn' ? 'end_turn'\n : 'unknown';\n\n return {\n content,\n toolCalls,\n stopReason,\n usage: data.usage ? {\n promptTokens: data.usage.input_tokens,\n completionTokens: data.usage.output_tokens,\n } : undefined,\n };\n}\n\n// ── Streaming implementations ────────────────────────────────────\n\n/**\n * OpenAI-compatible streaming with tool support.\n * Parses SSE chunks, yields text deltas, accumulates tool calls.\n */\nasync function* callOpenAIWithToolsStream(\n messages: ChatMessage[],\n tools: ToolDefinition[],\n): AsyncGenerator<LLMStreamEvent, void, undefined> {\n const config = currentConfig!;\n let base = config.baseUrl!.replace(/\\/+$/, '');\n if (!base.endsWith('/v1')) base += '/v1';\n const url = `${base}/chat/completions`;\n\n const openaiMessages: Array<Record<string, unknown>> = messages.map((msg) => {\n if (msg.role === 'tool') {\n return { role: 'tool', content: msg.content, tool_call_id: msg.toolCallId };\n }\n if (msg.role === 'assistant' && msg.toolCalls && msg.toolCalls.length > 0) {\n return {\n role: 'assistant',\n content: msg.content || null,\n tool_calls: msg.toolCalls.map((tc) => ({\n id: tc.id,\n type: 'function',\n function: { name: tc.name, arguments: tc.arguments },\n })),\n };\n }\n return { role: msg.role, content: msg.content };\n });\n\n const openaiTools = tools.map((t) => ({\n type: 'function' as const,\n function: { name: t.name, description: t.description, parameters: t.parameters },\n }));\n\n const response = await fetch(url, {\n signal: AbortSignal.timeout(LLM_CALL_TIMEOUT_MS * 2), // longer timeout for streaming\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${config.apiKey}`,\n },\n body: JSON.stringify({\n model: config.model,\n messages: openaiMessages,\n tools: openaiTools.length > 0 ? openaiTools : undefined,\n temperature: 0.3,\n max_tokens: 2048,\n stream: true,\n }),\n });\n\n if (!response.ok) {\n const error = await response.text().catch(() => 'unknown error');\n throw new Error(`LLM streaming API error (${response.status}): ${error}`);\n }\n\n // Parse SSE stream\n const reader = response.body?.getReader();\n if (!reader) throw new Error('No response body for streaming');\n\n const decoder = new TextDecoder();\n let fullContent = '';\n const toolCallMap = new Map<number, { id: string; name: string; arguments: string }>();\n let finishReason = 'unknown';\n let buffer = '';\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() ?? ''; // keep incomplete line in buffer\n\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed || trimmed === 'data: [DONE]') continue;\n if (!trimmed.startsWith('data: ')) continue;\n\n try {\n const chunk = JSON.parse(trimmed.slice(6));\n const delta = chunk.choices?.[0]?.delta;\n if (!delta) continue;\n\n // Text content\n if (delta.content) {\n fullContent += delta.content;\n yield { type: 'text' as const, content: delta.content };\n }\n\n // Tool call deltas — accumulate\n if (delta.tool_calls) {\n for (const tc of delta.tool_calls) {\n const idx = tc.index ?? 0;\n if (!toolCallMap.has(idx)) {\n toolCallMap.set(idx, {\n id: tc.id ?? '',\n name: tc.function?.name ?? '',\n arguments: tc.function?.arguments ?? '',\n });\n } else {\n const existing = toolCallMap.get(idx)!;\n if (tc.id) existing.id = tc.id;\n if (tc.function?.name) existing.name = tc.function.name;\n if (tc.function?.arguments) existing.arguments += tc.function.arguments;\n }\n }\n }\n\n // Finish reason\n if (chunk.choices?.[0]?.finish_reason) {\n finishReason = chunk.choices[0].finish_reason;\n }\n } catch {\n // Skip malformed JSON chunks\n }\n }\n }\n } finally {\n reader.releaseLock();\n }\n\n const toolCalls = [...toolCallMap.values()].map((tc) => ({\n id: tc.id,\n name: tc.name,\n arguments: tc.arguments,\n }));\n\n // Yield tool_call events\n for (const tc of toolCalls) {\n yield { type: 'tool_call' as const, toolCall: tc };\n }\n\n const stopReason = finishReason === 'tool_calls' ? 'tool_use'\n : finishReason === 'stop' ? 'stop'\n : 'unknown';\n\n yield {\n type: 'done' as const,\n response: {\n content: fullContent,\n toolCalls,\n stopReason,\n },\n };\n}\n\n/**\n * Anthropic streaming with tool support.\n * Parses SSE events, yields text deltas, accumulates tool_use blocks.\n */\nasync function* callAnthropicWithToolsStream(\n messages: ChatMessage[],\n tools: ToolDefinition[],\n): AsyncGenerator<LLMStreamEvent, void, undefined> {\n const config = currentConfig!;\n const url = `${config.baseUrl}/messages`;\n\n const systemContent = messages.find((m) => m.role === 'system')?.content ?? '';\n const nonSystemMessages = messages.filter((m) => m.role !== 'system');\n\n const anthropicMessages: Array<Record<string, unknown>> = [];\n for (const msg of nonSystemMessages) {\n if (msg.role === 'user') {\n anthropicMessages.push({ role: 'user', content: msg.content });\n } else if (msg.role === 'assistant') {\n const contentBlocks: Array<Record<string, unknown>> = [];\n if (msg.content) contentBlocks.push({ type: 'text', text: msg.content });\n if (msg.toolCalls) {\n for (const tc of msg.toolCalls) {\n contentBlocks.push({\n type: 'tool_use',\n id: tc.id,\n name: tc.name,\n input: JSON.parse(tc.arguments),\n });\n }\n }\n anthropicMessages.push({ role: 'assistant', content: contentBlocks });\n } else if (msg.role === 'tool') {\n anthropicMessages.push({\n role: 'user',\n content: [{\n type: 'tool_result',\n tool_use_id: msg.toolCallId,\n content: msg.content,\n }],\n });\n }\n }\n\n const anthropicTools = tools.map((t) => ({\n name: t.name,\n description: t.description,\n input_schema: t.parameters,\n }));\n\n const response = await fetch(url, {\n signal: AbortSignal.timeout(LLM_CALL_TIMEOUT_MS * 2),\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': config.apiKey,\n 'anthropic-version': '2023-06-01',\n },\n body: JSON.stringify({\n model: config.model,\n system: systemContent,\n messages: anthropicMessages,\n tools: anthropicTools.length > 0 ? anthropicTools : undefined,\n temperature: 0.3,\n max_tokens: 2048,\n stream: true,\n }),\n });\n\n if (!response.ok) {\n const error = await response.text().catch(() => 'unknown error');\n throw new Error(`Anthropic streaming API error (${response.status}): ${error}`);\n }\n\n const reader = response.body?.getReader();\n if (!reader) throw new Error('No response body for streaming');\n\n const decoder = new TextDecoder();\n let fullContent = '';\n const toolCalls: ToolCall[] = [];\n let currentToolId = '';\n let currentToolName = '';\n let currentToolInput = '';\n let stopReason = 'unknown';\n let buffer = '';\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() ?? '';\n\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed.startsWith('data: ')) continue;\n\n try {\n const event = JSON.parse(trimmed.slice(6));\n\n if (event.type === 'content_block_delta') {\n const delta = event.delta;\n if (delta?.type === 'text_delta' && delta.text) {\n fullContent += delta.text;\n yield { type: 'text' as const, content: delta.text };\n } else if (delta?.type === 'input_json_delta' && delta.partial_json) {\n currentToolInput += delta.partial_json;\n }\n } else if (event.type === 'content_block_start') {\n const block = event.content_block;\n if (block?.type === 'tool_use') {\n currentToolId = block.id ?? '';\n currentToolName = block.name ?? '';\n currentToolInput = '';\n }\n } else if (event.type === 'content_block_stop') {\n // Finalize current tool call\n if (currentToolId && currentToolName) {\n const tc: ToolCall = {\n id: currentToolId,\n name: currentToolName,\n arguments: currentToolInput || '{}',\n };\n toolCalls.push(tc);\n yield { type: 'tool_call' as const, toolCall: tc };\n currentToolId = '';\n currentToolName = '';\n currentToolInput = '';\n }\n } else if (event.type === 'message_delta') {\n if (event.delta?.stop_reason) {\n stopReason = event.delta.stop_reason;\n }\n }\n } catch {\n // Skip malformed JSON\n }\n }\n }\n } finally {\n reader.releaseLock();\n }\n\n const mappedStopReason = stopReason === 'tool_use' ? 'tool_use'\n : stopReason === 'end_turn' ? 'end_turn'\n : 'unknown';\n\n yield {\n type: 'done' as const,\n response: {\n content: fullContent,\n toolCalls,\n stopReason: mappedStopReason,\n },\n };\n}\n","/**\n * SqliteBackend — ObservationStore implementation backed by better-sqlite3.\n *\n * Features:\n * - WAL mode for concurrent read performance\n * - storage_generation counter for cross-process freshness detection\n * - next_id counter in meta table (replaces counter.json)\n * - One-time migration from observations.json on first init\n * - Dynamic require of better-sqlite3 (optionalDependencies)\n *\n * Array fields (facts, filesModified, concepts, relatedCommits, relatedEntities)\n * are stored as JSON strings in SQLite columns.\n *\n * Uses the shared database handle from sqlite-db.ts so that observations,\n * mini-skills, and sessions all share one connection and one DB file.\n */\n\nimport type { Observation } from '../types.js';\nimport type { ObservationStore, StoreTransaction } from './obs-store.js';\nimport { getDatabase, closeDatabase } from './sqlite-db.js';\nimport path from 'node:path';\nimport fs from 'node:fs';\n\n// ── Row ↔ Observation serialization ────────────────────────────────\n\nfunction obsToRow(obs: Observation): Record<string, unknown> {\n return {\n id: obs.id,\n entityName: obs.entityName,\n type: obs.type,\n title: obs.title,\n narrative: obs.narrative,\n facts: JSON.stringify(obs.facts ?? []),\n filesModified: JSON.stringify(obs.filesModified ?? []),\n concepts: JSON.stringify(obs.concepts ?? []),\n tokens: obs.tokens ?? 0,\n createdAt: obs.createdAt,\n updatedAt: obs.updatedAt ?? null,\n projectId: obs.projectId,\n hasCausalLanguage: obs.hasCausalLanguage ? 1 : 0,\n topicKey: obs.topicKey ?? null,\n revisionCount: obs.revisionCount ?? 1,\n sessionId: obs.sessionId ?? null,\n status: obs.status ?? 'active',\n progress: obs.progress ? JSON.stringify(obs.progress) : null,\n source: obs.source ?? 'agent',\n commitHash: obs.commitHash ?? null,\n relatedCommits: obs.relatedCommits ? JSON.stringify(obs.relatedCommits) : null,\n relatedEntities: obs.relatedEntities ? JSON.stringify(obs.relatedEntities) : null,\n sourceDetail: obs.sourceDetail ?? null,\n valueCategory: obs.valueCategory ?? null,\n admissionState: obs.admissionState ?? null,\n admissionReason: obs.admissionReason ?? null,\n visibility: obs.visibility ?? null,\n sharedWithAgentIds: obs.sharedWithAgentIds ? JSON.stringify(obs.sharedWithAgentIds) : null,\n createdByAgentId: obs.createdByAgentId ?? null,\n writeGeneration: obs.writeGeneration ?? 0,\n };\n}\n\nfunction rowToObs(row: any): Observation {\n return {\n id: row.id,\n entityName: row.entityName,\n type: row.type,\n title: row.title,\n narrative: row.narrative,\n facts: safeJsonParse(row.facts, []),\n filesModified: safeJsonParse(row.filesModified, []),\n concepts: safeJsonParse(row.concepts, []),\n tokens: row.tokens,\n createdAt: row.createdAt,\n ...(row.updatedAt ? { updatedAt: row.updatedAt } : {}),\n projectId: row.projectId,\n hasCausalLanguage: !!row.hasCausalLanguage,\n ...(row.topicKey ? { topicKey: row.topicKey } : {}),\n revisionCount: row.revisionCount ?? 1,\n ...(row.sessionId ? { sessionId: row.sessionId } : {}),\n status: row.status ?? 'active',\n ...(row.progress ? { progress: safeJsonParse(row.progress, undefined) } : {}),\n ...(row.source ? { source: row.source } : {}),\n ...(row.commitHash ? { commitHash: row.commitHash } : {}),\n ...(row.relatedCommits ? { relatedCommits: safeJsonParse(row.relatedCommits, []) } : {}),\n ...(row.relatedEntities ? { relatedEntities: safeJsonParse(row.relatedEntities, []) } : {}),\n ...(row.sourceDetail ? { sourceDetail: row.sourceDetail } : {}),\n ...(row.valueCategory ? { valueCategory: row.valueCategory } : {}),\n ...(row.admissionState ? { admissionState: row.admissionState } : {}),\n ...(row.admissionReason ? { admissionReason: row.admissionReason } : {}),\n ...(row.visibility ? { visibility: row.visibility } : {}),\n ...(row.sharedWithAgentIds ? { sharedWithAgentIds: safeJsonParse(row.sharedWithAgentIds, []) } : {}),\n ...(row.createdByAgentId ? { createdByAgentId: row.createdByAgentId } : {}),\n ...(row.writeGeneration ? { writeGeneration: row.writeGeneration } : {}),\n } as Observation;\n}\n\nfunction safeJsonParse(val: string | null | undefined, fallback: any): any {\n if (val == null || val === '') return fallback;\n try { return JSON.parse(val); } catch { return fallback; }\n}\n\n// ── SqliteBackend ──────────────────────────────────────────────────\n\nexport class SqliteBackend implements ObservationStore {\n private db: any = null;\n private dataDir: string = '';\n private knownGeneration: number = 0;\n\n // Async mutex for serializing atomic() calls on the single connection\n private _atomicQueue: Promise<unknown> = Promise.resolve();\n\n // Prepared statements (lazy-initialized after db open)\n private stmtInsert: any = null;\n private stmtUpdate: any = null;\n private stmtSetStatus: any = null;\n private stmtSetStatusIfCurrent: any = null;\n private stmtDelete: any = null;\n private stmtSelectAll: any = null;\n private stmtSelectById: any = null;\n private stmtSelectByProject: any = null;\n private stmtSelectByProjectStatus: any = null;\n private stmtSelectByProjectAfterId: any = null;\n private stmtSelectByProjectStatusAfterId: any = null;\n private stmtCountByProject: any = null;\n private stmtCountByProjectStatus: any = null;\n private stmtSelectByTopicKey: any = null;\n private stmtSelectGeneration: any = null;\n private stmtBumpGeneration: any = null;\n private stmtGetMeta: any = null;\n private stmtSetMeta: any = null;\n\n async init(dataDir: string): Promise<void> {\n this.dataDir = dataDir;\n\n // Use shared database handle (opens DB, creates all tables, sets pragmas)\n this.db = getDatabase(dataDir);\n\n // Prepare statements\n this.stmtInsert = this.db.prepare(`\n INSERT OR REPLACE INTO observations\n (id, entityName, type, title, narrative, facts, filesModified, concepts, tokens,\n createdAt, updatedAt, projectId, hasCausalLanguage, topicKey, revisionCount,\n sessionId, status, progress, source, commitHash, relatedCommits, relatedEntities,\n sourceDetail, valueCategory, admissionState, admissionReason, visibility, sharedWithAgentIds,\n createdByAgentId, writeGeneration)\n VALUES\n (@id, @entityName, @type, @title, @narrative, @facts, @filesModified, @concepts, @tokens,\n @createdAt, @updatedAt, @projectId, @hasCausalLanguage, @topicKey, @revisionCount,\n @sessionId, @status, @progress, @source, @commitHash, @relatedCommits, @relatedEntities,\n @sourceDetail, @valueCategory, @admissionState, @admissionReason, @visibility, @sharedWithAgentIds,\n @createdByAgentId, @writeGeneration)\n `);\n this.stmtUpdate = this.stmtInsert; // INSERT OR REPLACE works for both\n this.stmtSetStatus = this.db.prepare(`UPDATE observations SET status = ? WHERE id = ?`);\n this.stmtSetStatusIfCurrent = this.db.prepare(\n `UPDATE observations SET status = ? WHERE id = ? AND status = ?`,\n );\n this.stmtDelete = this.db.prepare(`DELETE FROM observations WHERE id = ?`);\n this.stmtSelectAll = this.db.prepare(`SELECT * FROM observations`);\n this.stmtSelectById = this.db.prepare(`SELECT * FROM observations WHERE id = ?`);\n this.stmtSelectByProject = this.db.prepare(`\n SELECT * FROM observations WHERE projectId = ?\n ORDER BY id ASC LIMIT ? OFFSET ?\n `);\n this.stmtSelectByProjectStatus = this.db.prepare(`\n SELECT * FROM observations WHERE projectId = ? AND status = ?\n ORDER BY id ASC LIMIT ? OFFSET ?\n `);\n this.stmtSelectByProjectAfterId = this.db.prepare(`\n SELECT * FROM observations WHERE projectId = ? AND id > ?\n ORDER BY id ASC LIMIT ?\n `);\n this.stmtSelectByProjectStatusAfterId = this.db.prepare(`\n SELECT * FROM observations WHERE projectId = ? AND status = ? AND id > ?\n ORDER BY id ASC LIMIT ?\n `);\n this.stmtCountByProject = this.db.prepare(\n `SELECT COUNT(*) AS count FROM observations WHERE projectId = ?`,\n );\n this.stmtCountByProjectStatus = this.db.prepare(\n `SELECT COUNT(*) AS count FROM observations WHERE projectId = ? AND status = ?`,\n );\n this.stmtSelectByTopicKey = this.db.prepare(\n `SELECT * FROM observations WHERE projectId = ? AND topicKey = ? ORDER BY id ASC LIMIT 1`,\n );\n this.stmtSelectGeneration = this.db.prepare(`SELECT value FROM meta WHERE key = 'storage_generation'`);\n this.stmtBumpGeneration = this.db.prepare(`UPDATE meta SET value = CAST(CAST(value AS INTEGER) + 1 AS TEXT) WHERE key = 'storage_generation'`);\n this.stmtGetMeta = this.db.prepare(`SELECT value FROM meta WHERE key = ?`);\n this.stmtSetMeta = this.db.prepare(`INSERT OR REPLACE INTO meta (key, value) VALUES (?, ?)`);\n\n // Read initial generation\n this.knownGeneration = this.readGeneration();\n\n // Migration: if observations table is empty but observations.json exists, import\n await this.migrateFromJsonIfNeeded();\n }\n\n // ── Internal helpers ─────────────────────────────────────────────\n\n private readGeneration(): number {\n const row = this.stmtSelectGeneration.get();\n return row ? parseInt(row.value, 10) : 0;\n }\n\n private bumpGeneration(): void {\n this.stmtBumpGeneration.run();\n this.knownGeneration = this.readGeneration();\n }\n\n private rawLoadAll(): Observation[] {\n const rows = this.stmtSelectAll.all();\n return rows.map(rowToObs);\n }\n\n private rawGetById(id: number): Observation | undefined {\n const row = this.stmtSelectById.get(id);\n return row ? rowToObs(row) : undefined;\n }\n\n private rawFindByTopicKey(projectId: string, topicKey: string): Observation | undefined {\n const row = this.stmtSelectByTopicKey.get(projectId, topicKey);\n return row ? rowToObs(row) : undefined;\n }\n\n private rawLoadIdCounter(): number {\n const row = this.stmtGetMeta.get('next_id');\n return row ? parseInt(row.value, 10) : 1;\n }\n\n private rawSaveIdCounter(nextId: number): void {\n this.stmtSetMeta.run('next_id', String(nextId));\n }\n\n // ── Migration ────────────────────────────────────────────────────\n\n private async migrateFromJsonIfNeeded(): Promise<void> {\n // Only migrate if table is empty\n const count = this.db.prepare(`SELECT COUNT(*) AS cnt FROM observations`).get();\n if (count.cnt > 0) return;\n\n const jsonPath = path.join(this.dataDir, 'observations.json');\n if (!fs.existsSync(jsonPath)) return;\n\n try {\n const raw = fs.readFileSync(jsonPath, 'utf-8');\n const observations: Observation[] = JSON.parse(raw);\n\n if (observations.length === 0) return;\n\n console.error(`[memorix] Migrating ${observations.length} observations from JSON to SQLite...`);\n\n const insertMany = this.db.transaction((obsList: Observation[]) => {\n for (const obs of obsList) {\n this.stmtInsert.run(obsToRow(obs));\n }\n });\n insertMany(observations);\n\n // Migrate counter\n const counterPath = path.join(this.dataDir, 'counter.json');\n if (fs.existsSync(counterPath)) {\n try {\n const counterData = JSON.parse(fs.readFileSync(counterPath, 'utf-8'));\n const nextId = counterData.nextId ?? counterData.next_id ?? (Math.max(...observations.map(o => o.id)) + 1);\n this.rawSaveIdCounter(nextId);\n } catch {\n // Fallback: derive from max observation ID\n this.rawSaveIdCounter(Math.max(...observations.map(o => o.id)) + 1);\n }\n } else {\n this.rawSaveIdCounter(Math.max(...observations.map(o => o.id)) + 1);\n }\n\n this.bumpGeneration();\n\n console.error(`[memorix] Migration complete. ${observations.length} observations now in SQLite.`);\n } catch (err) {\n console.error(`[memorix] JSON→SQLite migration failed (non-fatal, data preserved in JSON): ${err}`);\n }\n }\n\n // ── Public read ──────────────────────────────────────────────────\n\n async loadAll(): Promise<Observation[]> {\n return this.rawLoadAll();\n }\n\n async loadByProject(\n projectId: string,\n options: { status?: string; limit?: number; offset?: number; afterId?: number } = {},\n ): Promise<Observation[]> {\n const limit = options.limit == null ? -1 : Math.max(1, Math.floor(options.limit));\n const offset = options.offset == null ? 0 : Math.max(0, Math.floor(options.offset));\n const afterId = options.afterId == null ? null : Math.max(0, Math.floor(options.afterId));\n const rows = afterId === null\n ? (options.status\n ? this.stmtSelectByProjectStatus.all(projectId, options.status, limit, offset)\n : this.stmtSelectByProject.all(projectId, limit, offset))\n : (options.status\n ? this.stmtSelectByProjectStatusAfterId.all(projectId, options.status, afterId, limit)\n : this.stmtSelectByProjectAfterId.all(projectId, afterId, limit));\n return rows.map(rowToObs);\n }\n\n async getById(id: number): Promise<Observation | undefined> {\n return this.rawGetById(id);\n }\n\n async countByProject(projectId: string, options: { status?: string } = {}): Promise<number> {\n const row = options.status\n ? this.stmtCountByProjectStatus.get(projectId, options.status)\n : this.stmtCountByProject.get(projectId);\n return Number(row?.count ?? 0);\n }\n\n async loadIdCounter(): Promise<number> {\n return this.rawLoadIdCounter();\n }\n\n // ── Public write (each bumps generation) ─────────────────────────\n\n async insert(obs: Observation): Promise<void> {\n this.stmtInsert.run(obsToRow(obs));\n this.bumpGeneration();\n }\n\n async update(obs: Observation): Promise<void> {\n this.stmtUpdate.run(obsToRow(obs));\n this.bumpGeneration();\n }\n\n async remove(id: number): Promise<void> {\n this.stmtDelete.run(id);\n this.bumpGeneration();\n }\n\n async bulkReplace(obs: Observation[]): Promise<void> {\n const run = this.db.transaction((obsList: Observation[]) => {\n this.db.prepare(`DELETE FROM observations`).run();\n for (const o of obsList) {\n this.stmtInsert.run(obsToRow(o));\n }\n });\n run(obs);\n this.bumpGeneration();\n }\n\n async bulkRemoveByIds(ids: number[]): Promise<void> {\n if (ids.length === 0) return;\n const run = this.db.transaction((idList: number[]) => {\n const stmt = this.db.prepare(`DELETE FROM observations WHERE id = ?`);\n for (const id of idList) {\n stmt.run(id);\n }\n });\n run(ids);\n this.bumpGeneration();\n }\n\n async saveIdCounter(nextId: number): Promise<void> {\n this.rawSaveIdCounter(nextId);\n }\n\n // ── Compound atomic operation ────────────────────────────────────\n\n async atomic<T>(fn: (tx: StoreTransaction) => Promise<T>): Promise<T> {\n // Serialize concurrent atomic() calls via an async queue.\n // better-sqlite3 is single-connection; nested BEGIN is illegal.\n const run = this._atomicQueue\n .catch(() => undefined)\n .then(async () => {\n this.db.prepare('BEGIN IMMEDIATE').run();\n try {\n const tx: StoreTransaction = {\n loadAll: async () => this.rawLoadAll(),\n getById: async (id) => this.rawGetById(id),\n findByTopicKey: async (projectId, topicKey) => this.rawFindByTopicKey(projectId, topicKey),\n loadIdCounter: async () => this.rawLoadIdCounter(),\n insert: async (obs) => { this.stmtInsert.run(obsToRow(obs)); },\n update: async (obs) => { this.stmtUpdate.run(obsToRow(obs)); },\n setStatus: async (id, status, expectedStatus) => {\n const result = expectedStatus === undefined\n ? this.stmtSetStatus.run(status, id)\n : this.stmtSetStatusIfCurrent.run(status, id, expectedStatus);\n return Number(result.changes) > 0;\n },\n remove: async (id) => { this.stmtDelete.run(id); },\n saveAll: async (obs) => {\n this.db.prepare(`DELETE FROM observations`).run();\n for (const o of obs) {\n this.stmtInsert.run(obsToRow(o));\n }\n },\n saveIdCounter: async (nextId) => this.rawSaveIdCounter(nextId),\n getGeneration: async () => this.readGeneration(),\n };\n const result = await fn(tx);\n this.bumpGeneration();\n this.db.prepare('COMMIT').run();\n return result;\n } catch (err) {\n try { this.db.prepare('ROLLBACK').run(); } catch { /* already rolled back */ }\n throw err;\n }\n });\n\n // Keep the queue alive after failures so one bad transaction does not poison\n // all future atomic() calls.\n this._atomicQueue = run.catch(() => undefined);\n return run;\n }\n\n // ── Freshness ────────────────────────────────────────────────────\n\n async ensureFresh(): Promise<boolean> {\n const remoteGen = this.readGeneration();\n if (remoteGen > this.knownGeneration) {\n this.knownGeneration = remoteGen;\n return true; // caller should reload observations[] + rebuild Orama\n }\n return false;\n }\n\n getGeneration(): number {\n return this.knownGeneration;\n }\n\n // ── Diagnostics ──────────────────────────────────────────────────\n\n close(): void {\n // Detach from the shared handle without closing it — other stores\n // (MiniSkillSqliteStore, SessionSqliteStore) may still be using it.\n // Use closeDatabase(dataDir) or closeAllDatabases() for full shutdown.\n this.db = null;\n }\n\n getBackendName(): 'sqlite' | 'degraded' {\n return 'sqlite';\n }\n}\n","/**\n * ObservationStore — unified persistence abstraction for observations.\n *\n * Backends:\n * - SqliteBackend (sqlite-store.ts) — WAL-mode SQLite with generation tracking\n * - DegradedBackend — read-only empty store when SQLite is unavailable\n *\n * JSON is no longer a runtime writable backend.\n * observations.json is only used as a one-time migration source into SQLite.\n *\n * All observation persistence flows through this interface.\n */\n\nimport type { Observation } from '../types.js';\n\n/**\n * Raw transaction handle for compound atomic operations.\n *\n * Inside an `atomic()` block the caller gets a StoreTransaction whose methods\n * operate directly on the underlying storage WITHOUT acquiring their own lock.\n * The outer `atomic()` already holds the lock / transaction.\n */\nexport interface StoreTransaction {\n /** Load all observations (raw, no lock). */\n loadAll(): Promise<Observation[]>;\n /** Load one observation by its globally unique ID (raw, no lock). */\n getById(id: number): Promise<Observation | undefined>;\n /** Find one observation by its project-scoped topic key (raw, no lock). */\n findByTopicKey(projectId: string, topicKey: string): Promise<Observation | undefined>;\n /** Load the ID counter (raw, no lock). */\n loadIdCounter(): Promise<number>;\n /** Insert one observation without independently acquiring a lock. */\n insert(obs: Observation): Promise<void>;\n /** Update one observation without independently acquiring a lock. */\n update(obs: Observation): Promise<void>;\n /** Change only an observation's lifecycle status without replacing its other fields. */\n setStatus(id: number, status: string, expectedStatus?: string): Promise<boolean>;\n /** Remove one observation without independently acquiring a lock. */\n remove(id: number): Promise<void>;\n /** Save all observations (raw, no lock). */\n saveAll(obs: Observation[]): Promise<void>;\n /** Save the ID counter (raw, no lock). */\n saveIdCounter(nextId: number): Promise<void>;\n /** Read the storage generation visible to this transaction. */\n getGeneration(): Promise<number>;\n}\n\nexport interface ObservationStore {\n // ── Lifecycle ──────────────────────────────────────────────────────\n\n /** One-time init: open DB/files, run migration if needed */\n init(dataDir: string): Promise<void>;\n\n // ── Read ───────────────────────────────────────────────────────────\n\n /** Load all observations into memory. Called at startup after init(). */\n loadAll(): Promise<Observation[]>;\n\n /** Load one project's observations without scanning the shared flat store. */\n loadByProject(\n projectId: string,\n options?: { status?: string; limit?: number; offset?: number; afterId?: number },\n ): Promise<Observation[]>;\n\n /** Count one project's observations without materializing the rows. */\n countByProject(projectId: string, options?: { status?: string }): Promise<number>;\n\n /** Load one observation by its globally unique ID. */\n getById(id: number): Promise<Observation | undefined>;\n\n /** Load the current next-ID counter value. */\n loadIdCounter(): Promise<number>;\n\n // ── Write — single mutations ───────────────────────────────────────\n\n /** Insert a new observation. Bumps generation (if applicable). */\n insert(obs: Observation): Promise<void>;\n\n /** Update an existing observation in-place (matched by obs.id). */\n update(obs: Observation): Promise<void>;\n\n /** Remove a single observation by ID. */\n remove(id: number): Promise<void>;\n\n // ── Write — batch ──────────────────────────────────────────────────\n\n /**\n * Replace the entire observation set atomically.\n * Reserved for explicit full-state imports or recovery operations.\n */\n bulkReplace(obs: Observation[]): Promise<void>;\n\n /** Remove multiple observations by ID in one operation. */\n bulkRemoveByIds(ids: number[]): Promise<void>;\n\n /** Persist the next-ID counter. */\n saveIdCounter(nextId: number): Promise<void>;\n\n // ── Compound atomic operations ─────────────────────────────────────\n\n /**\n * Execute fn while holding an exclusive lock (file lock for JSON,\n * transaction for SQLite). The StoreTransaction provides raw load/save\n * methods that operate within the lock scope.\n *\n * Used by storeObservation for compound topicKey-TOCTOU + ID-assignment.\n */\n atomic<T>(fn: (tx: StoreTransaction) => Promise<T>): Promise<T>;\n\n // ── Freshness (cross-process coherence) ────────────────────────────\n\n /**\n * Check if another process has mutated the store since our last read.\n * If yes, the caller should reload observations[] and rebuild the Orama index.\n *\n * - SqliteBackend: compares storage_generation in meta table vs local knownGeneration\n * - DegradedBackend: no-op, returns false (no data to refresh)\n *\n * @returns true if the local cache is stale and was refreshed\n */\n ensureFresh(): Promise<boolean>;\n\n /** Current known generation counter (local). */\n getGeneration(): number;\n\n // ── Lifecycle ─────────────────────────────────────────────────────\n\n /** Close the backend (release DB handles, file locks, etc.). */\n close(): void;\n\n // ── Diagnostics ────────────────────────────────────────────────────\n\n /** Which backend is active: 'sqlite' or 'degraded' (read-only). */\n getBackendName(): 'sqlite' | 'degraded';\n}\n\n// ── Singleton store access ─────────────────────────────────────────\n\nlet _store: ObservationStore | null = null;\nlet _storeDataDir: string | null = null;\n\n/** Get the active ObservationStore singleton. Throws if not yet initialized. */\nexport function getObservationStore(): ObservationStore {\n if (!_store) {\n throw new Error('[memorix] ObservationStore not initialized — call initObservationStore() first');\n }\n return _store;\n}\n\n/** Set the active ObservationStore singleton (called once during startup). */\nexport function setObservationStore(store: ObservationStore): void {\n _store = store;\n}\n\n/** Reset the singleton (for tests only). Detaches from the backend.\n * Call closeAllDatabases() separately if you need to release the shared DB handle. */\nexport function resetObservationStore(): void {\n if (_store) {\n try { _store.close(); } catch { /* best-effort */ }\n }\n _store = null;\n _storeDataDir = null;\n}\n\n/**\n * Create a fresh ObservationStore instance for a specific data directory\n * without touching the process-wide singleton. This is useful for long-lived\n * multi-project hosts (for example serve-http embedded dashboard APIs) where\n * requests may need to read different project data dirs concurrently.\n */\nexport async function createObservationStore(dataDir: string): Promise<ObservationStore> {\n // Try SQLite first (optionalDependencies — may not be installed)\n try {\n const { SqliteBackend } = await import('./sqlite-store.js');\n const store = new SqliteBackend();\n await store.init(dataDir);\n return store;\n } catch (err) {\n console.error(`[memorix] SQLite backend unavailable — degraded mode (read-only): ${err instanceof Error ? err.message : err}`);\n }\n\n // No writable JSON fallback — degraded read-only mode instead\n // observations.json is only used as migration source, not runtime backend\n const store = new DegradedBackend();\n await store.init(dataDir);\n return store;\n}\n\n/**\n * Initialize the ObservationStore singleton for the given data directory.\n *\n * Tries SQLite first. If unavailable, falls back to DegradedBackend (read-only).\n *\n * Idempotent: if already initialized for the same dataDir, returns the existing store.\n */\nexport async function initObservationStore(dataDir: string): Promise<ObservationStore> {\n if (_store && _storeDataDir === dataDir) {\n return _store;\n }\n\n // Close previous store if switching directories\n if (_store) {\n try { _store.close(); } catch { /* best-effort */ }\n _store = null;\n _storeDataDir = null;\n }\n\n const store = await createObservationStore(dataDir);\n _store = store;\n _storeDataDir = dataDir;\n return store;\n}\n\n// ── DegradedBackend (read-only when SQLite unavailable) ──────────\n\n/**\n * DegradedBackend — ObservationStore that is read-only and empty.\n *\n * Used when better-sqlite3 is unavailable. All write operations throw.\n * This ensures the system does not silently fall back to writing observations.json\n * as a runtime canonical store.\n */\nexport class DegradedBackend implements ObservationStore {\n private dataDir: string = '';\n\n async init(dataDir: string): Promise<void> {\n this.dataDir = dataDir;\n }\n\n async loadAll(): Promise<Observation[]> {\n return [];\n }\n\n async loadByProject(_projectId: string, _options?: { status?: string; limit?: number; offset?: number; afterId?: number }): Promise<Observation[]> {\n return [];\n }\n\n async countByProject(_projectId: string, _options?: { status?: string }): Promise<number> {\n return 0;\n }\n\n async getById(_id: number): Promise<Observation | undefined> {\n return undefined;\n }\n\n async loadIdCounter(): Promise<number> {\n return 1;\n }\n\n async insert(_obs: Observation): Promise<void> {\n throw new Error('[memorix] Cannot write observations: SQLite backend unavailable (degraded mode)');\n }\n\n async update(_obs: Observation): Promise<void> {\n throw new Error('[memorix] Cannot write observations: SQLite backend unavailable (degraded mode)');\n }\n\n async remove(_id: number): Promise<void> {\n throw new Error('[memorix] Cannot write observations: SQLite backend unavailable (degraded mode)');\n }\n\n async bulkReplace(_obs: Observation[]): Promise<void> {\n throw new Error('[memorix] Cannot write observations: SQLite backend unavailable (degraded mode)');\n }\n\n async bulkRemoveByIds(_ids: number[]): Promise<void> {\n throw new Error('[memorix] Cannot write observations: SQLite backend unavailable (degraded mode)');\n }\n\n async saveIdCounter(_nextId: number): Promise<void> {\n throw new Error('[memorix] Cannot write observations: SQLite backend unavailable (degraded mode)');\n }\n\n async atomic<T>(_fn: (tx: StoreTransaction) => Promise<T>): Promise<T> {\n throw new Error('[memorix] Cannot write observations: SQLite backend unavailable (degraded mode)');\n }\n\n async ensureFresh(): Promise<boolean> {\n return false;\n }\n\n getGeneration(): number {\n return 0;\n }\n\n close(): void {\n // No resources to release\n }\n\n getBackendName(): 'sqlite' | 'degraded' {\n return 'degraded';\n }\n}\n","/**\n * Memorix Core Types\n *\n * Data model sources:\n * - Entity/Relation/KnowledgeGraph: MCP Official Memory Server (v0.6.3)\n * - Observation/ObservationType: claude-mem Progressive Disclosure\n * - UnifiedRule/RuleSource: Memorix original (rules sync)\n *\n * Designed for extensibility: new agent formats (Kiro, Copilot, Antigravity)\n * can be added by extending RuleSource and adding format adapters.\n */\n\n// ============================================================\n// Knowledge Graph (adopted from MCP Official Memory Server)\n// ============================================================\n\n/** A node in the knowledge graph representing a concept, component, or config */\nexport interface Entity {\n name: string;\n entityType: string;\n observations: string[];\n}\n\n/** A directed edge between two entities */\nexport interface Relation {\n from: string;\n to: string;\n relationType: string;\n}\n\n/** The complete knowledge graph */\nexport interface KnowledgeGraph {\n entities: Entity[];\n relations: Relation[];\n}\n\n// ============================================================\n// Observation (adopted from claude-mem Progressive Disclosure)\n// ============================================================\n\n/**\n * Observation type classification using claude-mem's icon-based legend system.\n *\n * Icon mapping:\n * [SESSION] session-request — User's original goal\n * [GOTCHA] gotcha — Critical pitfall / trap\n * [FIX] problem-solution — Bug fix or workaround\n * [INFO] how-it-works — Technical explanation\n * [CHANGE] what-changed — Code/architecture change\n * [DISCOVERY] discovery — New learning or insight\n * [WHY] why-it-exists — Design rationale\n * [DECISION] decision — Architecture decision\n * [TRADEOFF] trade-off — Deliberate compromise\n * [REASONING] reasoning — Why this approach was chosen (System 2 reasoning trace)\n * [PROBE] probe — Operational heartbeat / connectivity check (short-lived, excluded from default search)\n */\nexport type ObservationType =\n | 'session-request'\n | 'gotcha'\n | 'problem-solution'\n | 'how-it-works'\n | 'what-changed'\n | 'discovery'\n | 'why-it-exists'\n | 'decision'\n | 'trade-off'\n | 'reasoning'\n | 'probe';\n\n/** Map from ObservationType to display icon */\nexport const OBSERVATION_ICONS: Record<ObservationType, string> = {\n 'session-request': '[SESSION]',\n 'gotcha': '[GOTCHA]',\n 'problem-solution': '[FIX]',\n 'how-it-works': '[INFO]',\n 'what-changed': '[CHANGE]',\n 'discovery': '[DISCOVERY]',\n 'why-it-exists': '[WHY]',\n 'decision': '[DECISION]',\n 'trade-off': '[TRADEOFF]',\n 'reasoning': '[REASONING]',\n 'probe': '[PROBE]',\n};\n\n/** Observation lifecycle status */\nexport type ObservationStatus = 'active' | 'resolved' | 'archived';\n\n/**\n * Control-plane admission state for automatically captured observations.\n * Candidate and ephemeral records remain inspectable, but only qualified\n * records are eligible for automatic context delivery. Missing state preserves\n * legacy behavior for observations written before this policy existed.\n */\nexport type ObservationAdmissionState = 'ephemeral' | 'candidate' | 'qualified';\n\n/**\n * Who may retrieve an observation through agent-facing memory surfaces.\n * Missing visibility is a legacy record and resolves to `project`.\n */\nexport type ObservationVisibility = 'personal' | 'project' | 'team';\n\n/**\n * Identity available to an agent-facing retrieval call. Internal maintenance\n * deliberately omits this and may inspect all project records for lifecycle work.\n */\nexport interface ObservationReader {\n /** Bound project for a normal project-scoped call. Omit only for explicit global search. */\n projectId?: string;\n /** Stable coordination identity, available after an explicit team join. */\n agentId?: string;\n /** True only when agentId is an active member of the bound project team. */\n isTeamMember?: boolean;\n}\n\n/** Progress tracking for task/feature observations */\nexport interface ProgressInfo {\n feature: string;\n status: 'in-progress' | 'completed' | 'blocked';\n completion?: number;\n}\n\n/** A rich observation record attached to an entity */\nexport interface Observation {\n id: number;\n entityName: string;\n type: ObservationType;\n title: string;\n narrative: string;\n facts: string[];\n filesModified: string[];\n concepts: string[];\n tokens: number;\n createdAt: string;\n updatedAt?: string;\n projectId: string;\n /** Whether the observation contains causal language (because, due to, etc.) */\n hasCausalLanguage?: boolean;\n /** Optional topic key for upsert — same project+topicKey updates existing observation */\n topicKey?: string;\n /** How many times this observation was revised via topic key upsert (starts at 1) */\n revisionCount?: number;\n /** Session ID this observation belongs to */\n sessionId?: string;\n /** Lifecycle status: active (default) → resolved → archived */\n status?: ObservationStatus;\n /** ID of the observation that superseded this one (set when auto-resolved by topicKey upsert) */\n supersededBy?: number;\n /** Progress tracking for task/feature observations */\n progress?: ProgressInfo;\n /** Origin of this observation: agent (IDE hooks/MCP), git (commit ingest), manual (CLI) */\n source?: 'agent' | 'git' | 'manual';\n /** Git commit hash if source is 'git' */\n commitHash?: string;\n /** Related commit hashes — links reasoning memories to the commits they explain */\n relatedCommits?: string[];\n /** Related entity names — explicit cross-references to other memory entities */\n relatedEntities?: string[];\n /** Provenance detail: how this observation entered the system */\n sourceDetail?: 'explicit' | 'hook' | 'git-ingest';\n /** Value category from formation pipeline evaluation */\n valueCategory?: 'core' | 'contextual' | 'ephemeral';\n /** Control-plane admission state for automatic capture and delivery. */\n admissionState?: ObservationAdmissionState;\n /** Short, sanitized explanation for the latest admission decision. */\n admissionReason?: string;\n /** Retrieval scope. Legacy records without a value remain project-visible. */\n visibility?: ObservationVisibility;\n /** Explicit additional readers for a personal record, used by targeted handoffs. */\n sharedWithAgentIds?: string[];\n /** Phase 4a: Agent ID that created this observation (team attribution) */\n createdByAgentId?: string;\n /** Phase 4a: Monotonic write generation — snapshot of storage_generation at write time (watermark coherence) */\n writeGeneration?: number;\n}\n\n// ============================================================\n// Session Lifecycle (inspired by Engram's session management)\n// ============================================================\n\n/** A coding session tracked by Memorix */\nexport interface Session {\n id: string;\n projectId: string;\n startedAt: string;\n endedAt?: string;\n summary?: string;\n status: 'active' | 'completed';\n /** Agent/IDE that started this session */\n agent?: string;\n}\n\n// ============================================================\n// Compact Engine (adopted from claude-mem 3-layer workflow)\n// ============================================================\n\n/** L1 index entry — lightweight, ~50-100 tokens per result */\nexport interface IndexEntry {\n id: number;\n time: string;\n type: ObservationType;\n icon: string;\n title: string;\n tokens: number;\n /** Relevance score from search (time-decayed). Used by compact engine. */\n score?: number;\n /** Project that owns this observation. Needed to disambiguate global results. */\n projectId?: string;\n /** Origin of the memory for source-aware retrieval and display. */\n source?: 'agent' | 'git' | 'manual';\n /** Provenance detail for source-aware display */\n sourceDetail?: 'explicit' | 'hook' | 'git-ingest';\n /** Value category for source-aware ranking */\n valueCategory?: 'core' | 'contextual' | 'ephemeral';\n /** Control-plane admission state when known. */\n admissionState?: ObservationAdmissionState;\n /** Retrieval scope when known. */\n visibility?: ObservationVisibility;\n /** Explainable recall: why this result matched. */\n matchedFields?: string[];\n /** Entity name — used for entity-affinity scoring and workstream deduplication. */\n entityName?: string;\n /** Document type: observation or mini-skill (Phase 3a) */\n documentType?: DocumentType;\n /** Knowledge layer for layer-aware ranking (Phase 3a) */\n knowledgeLayer?: KnowledgeLayer;\n}\n\n/** Explicit reference to an observation, optionally scoped to a project. */\nexport interface ObservationRef {\n id: number;\n projectId?: string;\n}\n\n/** L2 timeline context — observations around an anchor */\nexport interface TimelineContext {\n anchorId: number;\n anchorEntry: IndexEntry | null;\n before: IndexEntry[];\n after: IndexEntry[];\n}\n\n/** Search options for the compact engine */\nexport interface SearchOptions {\n query: string;\n limit?: number;\n type?: ObservationType;\n projectId?: string;\n since?: string;\n until?: string;\n /** Token budget — trim results to fit within this many tokens (0 = unlimited) */\n maxTokens?: number;\n /** Filter by observation status. Default: 'active' (only show active memories) */\n status?: ObservationStatus | 'all';\n /** Filter by observation source: 'agent', 'git', 'manual', or undefined for all */\n source?: 'agent' | 'git' | 'manual';\n /** Internal observability probes can disable access tracking without affecting normal search behavior. */\n trackAccess?: boolean;\n /** Internal reader context for agent-facing visibility filtering. */\n reader?: ObservationReader;\n}\n\n/** Topic key family heuristics for suggesting stable topic keys */\nexport const TOPIC_KEY_FAMILIES: Record<string, string[]> = {\n 'architecture': ['architecture', 'design', 'adr', 'structure', 'pattern'],\n 'bug': ['bugfix', 'fix', 'error', 'regression', 'crash', 'problem-solution'],\n 'decision': ['decision', 'trade-off', 'choice', 'strategy'],\n 'config': ['config', 'setup', 'env', 'environment', 'deployment'],\n 'discovery': ['discovery', 'learning', 'insight', 'gotcha'],\n 'pattern': ['pattern', 'convention', 'standard', 'best-practice'],\n};\n\n// ============================================================\n// Orama Document Schema\n// ============================================================\n\n/** The document shape stored in Orama */\nexport interface MemorixDocument {\n id: string;\n observationId: number;\n entityName: string;\n type: string;\n title: string;\n narrative: string;\n facts: string;\n filesModified: string;\n concepts: string;\n tokens: number;\n createdAt: string;\n projectId: string;\n /** Number of times this observation was returned in search results */\n accessCount: number;\n /** ISO timestamp of last access via search/detail */\n lastAccessedAt: string;\n /** Lifecycle status: active, resolved, archived */\n status: string;\n /** Origin: agent, git, manual */\n source: string;\n /** Provenance detail: explicit, hook, or git-ingest */\n sourceDetail?: string;\n /** Value category from formation evaluation */\n valueCategory?: string;\n /** Control-plane admission state for automatic capture and delivery. */\n admissionState?: string;\n /** Short, sanitized explanation for the latest admission decision. */\n admissionReason?: string;\n /** Retrieval scope for agent-facing filtering. */\n visibility?: string;\n /** Agent that owns a personal record, or authored a shared record. */\n createdByAgentId?: string;\n /** Explicit readers for a targeted personal record. */\n sharedWithAgentIds?: string;\n /** Optional vector embedding for semantic/hybrid retrieval */\n embedding?: number[];\n /** Document type: observation or mini-skill (Phase 3a) */\n documentType?: DocumentType;\n /** Knowledge layer for layer-aware ranking (Phase 3a) */\n knowledgeLayer?: KnowledgeLayer;\n}\n\n// ============================================================\n// Rules System (Memorix original — extensible for new agents)\n// ============================================================\n\n/**\n * Supported agent/IDE rule sources.\n * All 7 major AI IDEs are supported.\n */\nexport type RuleSource =\n | 'cursor'\n | 'claude-code'\n | 'codex'\n | 'windsurf'\n | 'antigravity'\n | 'gemini-cli'\n | 'copilot'\n | 'kiro'\n | 'trae'\n | 'memorix';\n\n/** A parsed rule in the unified intermediate representation */\nexport interface UnifiedRule {\n id: string;\n content: string;\n description?: string;\n source: RuleSource;\n scope: 'global' | 'project' | 'path-specific';\n paths?: string[];\n alwaysApply?: boolean;\n priority: number;\n hash: string;\n}\n\n/**\n * Format adapter interface — implement this for each agent/IDE.\n * Adding a new agent (e.g., Kiro) only requires implementing this interface.\n */\nexport interface RuleFormatAdapter {\n /** Unique identifier for this agent format */\n readonly source: RuleSource;\n\n /** File paths/globs this adapter can parse */\n readonly filePatterns: string[];\n\n /** Parse rule files into unified representation */\n parse(filePath: string, content: string): UnifiedRule[];\n\n /** Generate rule file content from unified representation */\n generate(rules: UnifiedRule[]): { filePath: string; content: string }[];\n}\n\n// ============================================================\n// Project Identity\n// ============================================================\n\nexport interface ProjectInfo {\n id: string;\n name: string;\n gitRemote?: string;\n rootPath: string;\n}\n\n/**\n * Diagnostic failure info from project detection.\n * Tells callers exactly WHY detection failed so they can report actionable errors.\n */\nexport type DetectionFailureReason =\n | 'path_not_found'\n | 'not_a_directory'\n | 'no_git'\n | 'git_worktree_error'\n | 'git_safe_directory'\n | 'remote_resolve_failed';\n\nexport interface DetectionFailure {\n reason: DetectionFailureReason;\n path: string;\n detail: string;\n}\n\nexport interface DetectionResult {\n project: ProjectInfo | null;\n failure: DetectionFailure | null;\n}\n\n// ============================================================\n// Memorix Server Configuration\n// ============================================================\n\nexport interface MemorixConfig {\n dataDir: string;\n projectId: string;\n projectName: string;\n enableEmbeddings: boolean;\n enableRulesSync: boolean;\n watchRuleFiles: boolean;\n}\n\nexport const DEFAULT_CONFIG: Partial<MemorixConfig> = {\n enableEmbeddings: false,\n enableRulesSync: false,\n watchRuleFiles: false,\n};\n\n// ============================================================\n// Workspace Sync — Cross-Agent workspace migration\n// ============================================================\n\n/** Supported agent targets for workspace sync */\nexport type AgentTarget =\n | 'windsurf'\n | 'cursor'\n | 'claude-code'\n | 'codex'\n | 'copilot'\n | 'antigravity'\n | 'gemini-cli'\n | 'openclaw'\n | 'hermes'\n | 'omp'\n | 'kiro'\n | 'opencode'\n | 'trae';\n\n/** A unified MCP server entry across all agent config formats */\nexport interface MCPServerEntry {\n name: string;\n /** Command for stdio transport */\n command: string;\n /** Args for stdio transport */\n args: string[];\n /** Environment variables */\n env?: Record<string, string> | null;\n /** URL for HTTP/SSE transport (Codex uses `url`, Windsurf uses `serverUrl`) */\n url?: string;\n /** HTTP headers (Windsurf uses `headers` for HTTP transport) */\n headers?: Record<string, string>;\n /** Whether this server is disabled */\n disabled?: boolean;\n /** Claude Code: force small core tool sets to load before the first prompt */\n alwaysLoad?: boolean;\n}\n\n/** Unified workflow entry */\nexport interface WorkflowEntry {\n name: string;\n description: string;\n content: string;\n source: AgentTarget;\n filePath: string;\n}\n\n/** A skill folder discovered from an agent's skills directory */\nexport interface SkillEntry {\n name: string;\n description: string;\n sourcePath: string;\n sourceAgent: AgentTarget;\n}\n\n/** Conflict when two agents have a skill with the same folder name */\nexport interface SkillConflict {\n name: string;\n kept: SkillEntry;\n skipped: SkillEntry;\n}\n\n/** Result of a workspace sync operation */\nexport interface WorkspaceSyncResult {\n mcpServers: {\n scanned: MCPServerEntry[];\n generated: { filePath: string; content: string }[];\n };\n workflows: {\n scanned: WorkflowEntry[];\n generated: { filePath: string; content: string }[];\n };\n rules: {\n scanned: number;\n generated: number;\n };\n skills: {\n scanned: SkillEntry[];\n conflicts: SkillConflict[];\n copied: string[];\n skipped: string[];\n };\n}\n\n// ============================================================\n// Mini-Skills — Promoted memories that never decay\n// ============================================================\n\n/** A mini-skill promoted from one or more observations */\nexport interface MiniSkill {\n id: number;\n /** Observation IDs this mini-skill was derived from (live refs, best-effort) */\n sourceObservationIds: number[];\n /** Entity the source observations belong to */\n sourceEntity: string;\n /** Short title for the skill */\n title: string;\n /** What the agent should do (imperative instruction) */\n instruction: string;\n /** When this skill should be applied (scenario description) */\n trigger: string;\n /** Key facts extracted from source observations */\n facts: string[];\n /** Project this skill belongs to */\n projectId: string;\n /** ISO timestamp */\n createdAt: string;\n /** How many times this skill was injected in session_start */\n usedCount: number;\n /** Classification tags */\n tags: string[];\n /** Frozen source observation content at promote time (JSON, immutable provenance proof) */\n sourceSnapshot?: string;\n /** ISO timestamp of last modification (Phase 3a: set once at creation) */\n updatedAt?: string;\n}\n\n// ============================================================\n// Source Snapshot — immutable provenance proof for promoted knowledge\n// ============================================================\n\n/** A single observation entry within a source snapshot */\nexport interface SnapshotObservation {\n id: number;\n title: string;\n type: string;\n narrative: string;\n facts: string[];\n entityName: string;\n projectId: string;\n createdAt: string;\n /** Frozen source detail for provenance (explicit / hook / git-ingest) */\n sourceDetail?: string;\n}\n\n/** Frozen source content captured at promote time */\nexport interface SourceSnapshot {\n observations: SnapshotObservation[];\n promotedAt: string;\n}\n\n// ============================================================\n// Knowledge Layer — Phase 3a retrieval classification\n// ============================================================\n\n/** Classification of knowledge for layer-aware ranking */\nexport type KnowledgeLayer = 'project-truth' | 'promoted' | 'evidence';\n\n/** Document type discriminator for Orama index */\nexport type DocumentType = 'observation' | 'mini-skill';\n\n// ============================================================\n// Typed Memory Reference — Phase 3a reference protocol\n// ============================================================\n\n/** A typed reference to a memory object (observation or mini-skill) */\nexport interface MemoryRef {\n kind: 'obs' | 'skill';\n id: number;\n projectId?: string;\n}\n\n/** MCP config format adapter interface */\nexport interface MCPConfigAdapter {\n readonly source: AgentTarget;\n /** Parse MCP server entries from a config file */\n parse(content: string): MCPServerEntry[];\n /** Generate config file content from MCP server entries */\n generate(servers: MCPServerEntry[]): string;\n /** Get the default config file path for this agent */\n getConfigPath(projectRoot?: string): string;\n}\n","/**\n * File Lock & Atomic Write Utilities\n *\n * Provides cross-process file locking using .lock files with atomic creation\n * (O_CREAT | O_EXCL), and atomic file writes via temp-file-then-rename.\n *\n * This prevents data corruption when multiple MCP server instances\n * (e.g., Cursor + Windsurf) write to the same project directory simultaneously.\n */\n\nimport { promises as fs } from 'node:fs';\nimport { randomUUID } from 'node:crypto';\nimport path from 'node:path';\n\n/** Lock is considered stale after 10 seconds (process crash recovery) */\nconst LOCK_STALE_MS = 10_000;\n/** Retry interval when waiting for lock */\nconst RETRY_INTERVAL_MS = 50;\n/** Maximum retries before giving up (50ms × 60 = 3 seconds) */\nconst MAX_RETRIES = 60;\nconst atomicWriteTails = new Map<string, Promise<void>>();\n\n/**\n * Acquire a lock file atomically.\n * Uses O_WRONLY | O_CREAT | O_EXCL — fails if file already exists.\n * Handles stale locks from crashed processes.\n */\nexport async function acquireLock(lockPath: string): Promise<void> {\n for (let i = 0; i < MAX_RETRIES; i++) {\n try {\n const fd = await fs.open(lockPath, 'wx');\n await fd.writeFile(JSON.stringify({ pid: process.pid, time: Date.now() }));\n await fd.close();\n return;\n } catch (err: unknown) {\n const code = err instanceof Error && 'code' in err ? (err as NodeJS.ErrnoException).code : undefined;\n if (code === 'EEXIST' || code === 'EPERM') {\n // Lock exists — check if stale\n try {\n const stat = await fs.stat(lockPath);\n if (Date.now() - stat.mtimeMs > LOCK_STALE_MS) {\n await fs.unlink(lockPath).catch(() => {});\n continue;\n }\n } catch {\n continue; // Lock disappeared — retry immediately\n }\n await new Promise(r => setTimeout(r, RETRY_INTERVAL_MS));\n } else {\n throw err;\n }\n }\n }\n // Last resort: force-remove stale lock and try once more\n await fs.unlink(lockPath).catch(() => {});\n try {\n const fd = await fs.open(lockPath, 'wx');\n await fd.writeFile(JSON.stringify({ pid: process.pid, time: Date.now() }));\n await fd.close();\n return;\n } catch {\n throw new Error(`Failed to acquire lock: ${lockPath} (timeout after ${MAX_RETRIES * RETRY_INTERVAL_MS}ms)`);\n }\n}\n\n/**\n * Release a lock file.\n */\nexport async function releaseLock(lockPath: string): Promise<void> {\n await fs.unlink(lockPath).catch(() => {});\n}\n\n/**\n * Execute a function while holding a project-level lock.\n * Ensures only one process writes to the project directory at a time.\n *\n * @param projectDir - The project data directory to lock\n * @param fn - The async function to execute while holding the lock\n * @returns The return value of fn\n */\nexport async function withFileLock<T>(projectDir: string, fn: () => Promise<T>): Promise<T> {\n const lockPath = path.join(projectDir, '.memorix.lock');\n await acquireLock(lockPath);\n try {\n return await fn();\n } finally {\n await releaseLock(lockPath);\n }\n}\n\n/**\n * Write a file atomically: write to .tmp, then rename.\n * Prevents partial writes from corrupting data files on crash.\n *\n * On most filesystems, rename() is atomic within the same directory,\n * so readers always see either the old complete file or the new complete file.\n */\nasync function atomicWriteFileOnce(filePath: string, data: string): Promise<void> {\n const tmpPath = filePath + `.tmp.${process.pid}.${randomUUID()}`;\n try {\n await fs.writeFile(tmpPath, data, 'utf-8');\n await fs.rename(tmpPath, filePath);\n } catch (error) {\n await fs.unlink(tmpPath).catch(() => {});\n throw error;\n }\n}\n\n/**\n * Serialize same-process writes to one target. Windows refuses concurrent\n * replacements of the same path even when each writer has its own temp file.\n */\nexport function atomicWriteFile(filePath: string, data: string): Promise<void> {\n const previous = atomicWriteTails.get(filePath) ?? Promise.resolve();\n const next = previous.catch(() => undefined).then(() => atomicWriteFileOnce(filePath, data));\n atomicWriteTails.set(filePath, next);\n return next.finally(() => {\n if (atomicWriteTails.get(filePath) === next) atomicWriteTails.delete(filePath);\n });\n}\n","/**\n * MiniSkillStore — persistence abstraction for mini-skills.\n *\n * Backends:\n * - MiniSkillSqliteStore — canonical store, uses shared DB handle from sqlite-db.ts\n * - MiniSkillGracefulDegrade — no-op fallback when SQLite is unavailable\n *\n * Phase 2 debt-zero: SQLite is the only canonical store for mini-skills.\n * JSON files are migration source only. No writable JSON fallback exists.\n */\n\nimport type { MiniSkill } from '../types.js';\nimport { getDatabase } from './sqlite-db.js';\nimport {\n loadMiniSkillsJson,\n} from './persistence.js';\nimport path from 'node:path';\nimport fs from 'node:fs';\n\n// ── Interface ───────────────────────────────────────────────────────\n\nexport interface MiniSkillStore {\n init(dataDir: string): Promise<void>;\n loadAll(): Promise<MiniSkill[]>;\n loadByProject(projectId: string): Promise<MiniSkill[]>;\n insert(skill: MiniSkill): Promise<void>;\n update(skill: MiniSkill): Promise<void>;\n remove(id: number): Promise<void>;\n loadIdCounter(): Promise<number>;\n saveIdCounter(nextId: number): Promise<void>;\n /**\n * Atomic create: allocate ID + insert skill + bump counter in one transaction.\n * Prevents concurrent promotes from receiving the same ID.\n */\n atomicInsertWithId(skill: Omit<MiniSkill, 'id'>): Promise<MiniSkill>;\n ensureFresh(): Promise<boolean>;\n getGeneration(): number;\n getBackendName(): 'sqlite' | 'degraded';\n}\n\n// ── Row <-> MiniSkill serialization ─────────────────────────────────\n\nfunction skillToRow(skill: MiniSkill): Record<string, unknown> {\n return {\n id: skill.id,\n sourceObservationIds: JSON.stringify(skill.sourceObservationIds ?? []),\n sourceEntity: skill.sourceEntity ?? 'unknown',\n title: skill.title,\n instruction: skill.instruction ?? '',\n trigger_desc: skill.trigger ?? '',\n facts: JSON.stringify(skill.facts ?? []),\n projectId: skill.projectId,\n createdAt: skill.createdAt,\n usedCount: skill.usedCount ?? 0,\n tags: JSON.stringify(skill.tags ?? []),\n sourceSnapshot: skill.sourceSnapshot ?? '',\n updatedAt: skill.updatedAt ?? null,\n };\n}\n\nfunction rowToSkill(row: any): MiniSkill {\n return {\n id: row.id,\n sourceObservationIds: safeJsonParse(row.sourceObservationIds, []),\n sourceEntity: row.sourceEntity ?? 'unknown',\n title: row.title,\n instruction: row.instruction ?? '',\n trigger: row.trigger_desc ?? '',\n facts: safeJsonParse(row.facts, []),\n projectId: row.projectId,\n createdAt: row.createdAt,\n usedCount: row.usedCount ?? 0,\n tags: safeJsonParse(row.tags, []),\n sourceSnapshot: row.sourceSnapshot || undefined,\n updatedAt: row.updatedAt || undefined,\n };\n}\n\nfunction safeJsonParse(val: string | null | undefined, fallback: any): any {\n if (val == null || val === '') return fallback;\n try { return JSON.parse(val); } catch { return fallback; }\n}\n\n// ── SQLite Backend ──────────────────────────────────────────────────\n\nexport class MiniSkillSqliteStore implements MiniSkillStore {\n private db: any = null;\n private dataDir: string = '';\n private knownGeneration: number = 0;\n\n private stmtInsert: any = null;\n private stmtDelete: any = null;\n private stmtSelectAll: any = null;\n private stmtSelectByProject: any = null;\n private stmtGetMeta: any = null;\n private stmtSetMeta: any = null;\n private stmtSelectGeneration: any = null;\n private stmtBumpGeneration: any = null;\n\n async init(dataDir: string): Promise<void> {\n this.dataDir = dataDir;\n this.db = getDatabase(dataDir);\n\n // Prepare statements\n this.stmtInsert = this.db.prepare(`\n INSERT OR REPLACE INTO mini_skills\n (id, sourceObservationIds, sourceEntity, title, instruction, trigger_desc,\n facts, projectId, createdAt, usedCount, tags, sourceSnapshot, updatedAt)\n VALUES\n (@id, @sourceObservationIds, @sourceEntity, @title, @instruction, @trigger_desc,\n @facts, @projectId, @createdAt, @usedCount, @tags, @sourceSnapshot, @updatedAt)\n `);\n this.stmtDelete = this.db.prepare(`DELETE FROM mini_skills WHERE id = ?`);\n this.stmtSelectAll = this.db.prepare(`SELECT * FROM mini_skills`);\n this.stmtSelectByProject = this.db.prepare(`SELECT * FROM mini_skills WHERE projectId = ?`);\n this.stmtGetMeta = this.db.prepare(`SELECT value FROM meta WHERE key = ?`);\n this.stmtSetMeta = this.db.prepare(`INSERT OR REPLACE INTO meta (key, value) VALUES (?, ?)`);\n this.stmtSelectGeneration = this.db.prepare(`SELECT value FROM meta WHERE key = 'mini_skills_generation'`);\n this.stmtBumpGeneration = this.db.prepare(`UPDATE meta SET value = CAST(CAST(value AS INTEGER) + 1 AS TEXT) WHERE key = 'mini_skills_generation'`);\n\n // Read initial generation\n this.knownGeneration = this.readGeneration();\n\n // One-time migration from mini-skills.json\n await this.migrateFromJsonIfNeeded();\n }\n\n private readGeneration(): number {\n const row = this.stmtSelectGeneration.get();\n return row ? parseInt(row.value, 10) : 0;\n }\n\n private bumpGeneration(): void {\n this.stmtBumpGeneration.run();\n this.knownGeneration = this.readGeneration();\n }\n\n // ── Migration ────────────────────────────────────────────────────\n\n private async migrateFromJsonIfNeeded(): Promise<void> {\n const count = this.db.prepare(`SELECT COUNT(*) AS cnt FROM mini_skills`).get();\n if (count.cnt > 0) return;\n\n const jsonPath = path.join(this.dataDir, 'mini-skills.json');\n if (!fs.existsSync(jsonPath)) return;\n\n try {\n const raw = fs.readFileSync(jsonPath, 'utf-8');\n const skills: MiniSkill[] = JSON.parse(raw);\n if (!Array.isArray(skills) || skills.length === 0) return;\n\n console.error(`[memorix] Migrating ${skills.length} mini-skills from JSON to SQLite...`);\n\n const insertMany = this.db.transaction((list: MiniSkill[]) => {\n for (const skill of list) {\n this.stmtInsert.run(skillToRow(skill));\n }\n });\n insertMany(skills);\n\n // Migrate counter\n const counterPath = path.join(this.dataDir, 'mini-skills-counter.json');\n if (fs.existsSync(counterPath)) {\n try {\n const counterData = JSON.parse(fs.readFileSync(counterPath, 'utf-8'));\n const nextId = counterData.nextId ?? (Math.max(...skills.map(s => s.id)) + 1);\n this.stmtSetMeta.run('mini_skills_next_id', String(nextId));\n } catch {\n this.stmtSetMeta.run('mini_skills_next_id', String(Math.max(...skills.map(s => s.id)) + 1));\n }\n } else {\n this.stmtSetMeta.run('mini_skills_next_id', String(Math.max(...skills.map(s => s.id)) + 1));\n }\n\n this.bumpGeneration();\n console.error(`[memorix] Mini-skills migration complete. ${skills.length} skills now in SQLite.`);\n } catch (err) {\n console.error(`[memorix] Mini-skills JSON->SQLite migration failed (non-fatal): ${err}`);\n }\n }\n\n // ── Public read ──────────────────────────────────────────────────\n\n async loadAll(): Promise<MiniSkill[]> {\n return this.stmtSelectAll.all().map(rowToSkill);\n }\n\n async loadByProject(projectId: string): Promise<MiniSkill[]> {\n return this.stmtSelectByProject.all(projectId).map(rowToSkill);\n }\n\n async loadIdCounter(): Promise<number> {\n const row = this.stmtGetMeta.get('mini_skills_next_id');\n return row ? parseInt(row.value, 10) : 1;\n }\n\n // ── Public write (each bumps generation) ─────────────────────────\n\n async insert(skill: MiniSkill): Promise<void> {\n this.stmtInsert.run(skillToRow(skill));\n this.bumpGeneration();\n }\n\n async update(skill: MiniSkill): Promise<void> {\n this.stmtInsert.run(skillToRow(skill)); // INSERT OR REPLACE\n this.bumpGeneration();\n }\n\n async remove(id: number): Promise<void> {\n this.stmtDelete.run(id);\n this.bumpGeneration();\n }\n\n async saveIdCounter(nextId: number): Promise<void> {\n this.stmtSetMeta.run('mini_skills_next_id', String(nextId));\n }\n\n /**\n * Atomic create: allocate ID + insert + bump counter in a single SQLite transaction.\n * SQLite serializes write transactions, so concurrent calls are safely sequenced.\n */\n async atomicInsertWithId(skillWithoutId: Omit<MiniSkill, 'id'>): Promise<MiniSkill> {\n const result = this.db.transaction(() => {\n // 1. Read current counter inside the transaction\n const row = this.stmtGetMeta.get('mini_skills_next_id');\n const nextId = row ? parseInt(row.value, 10) : 1;\n\n // 2. Build the full skill with the allocated ID\n const skill: MiniSkill = { ...skillWithoutId, id: nextId } as MiniSkill;\n\n // 3. Insert\n this.stmtInsert.run(skillToRow(skill));\n\n // 4. Bump counter\n this.stmtSetMeta.run('mini_skills_next_id', String(nextId + 1));\n\n // 5. Bump generation\n this.stmtBumpGeneration.run();\n this.knownGeneration = this.readGeneration();\n\n return skill;\n })();\n return result;\n }\n\n // ── Freshness ────────────────────────────────────────────────────\n\n async ensureFresh(): Promise<boolean> {\n const remoteGen = this.readGeneration();\n if (remoteGen > this.knownGeneration) {\n this.knownGeneration = remoteGen;\n return true;\n }\n return false;\n }\n\n getGeneration(): number {\n return this.knownGeneration;\n }\n\n getBackendName(): 'sqlite' | 'degraded' {\n return 'sqlite';\n }\n}\n\n// ── Graceful Degrade Fallback ────────────────────────────────────────\n//\n// Phase 2 debt-zero rule: mini-skills have NO writable JSON fallback.\n// In JSON-only environments (no better-sqlite3), reads return empty\n// and writes are no-ops with a warning. This prevents a parallel\n// canonical JSON write path from existing alongside SQLite.\n\nexport class MiniSkillGracefulDegrade implements MiniSkillStore {\n private warned = false;\n\n private warn(): void {\n if (!this.warned) {\n console.error('[memorix] MiniSkillStore: SQLite unavailable — mini-skills are disabled (read-only empty). Install better-sqlite3 for full functionality.');\n this.warned = true;\n }\n }\n\n async init(_dataDir: string): Promise<void> {\n this.warn();\n }\n\n async loadAll(): Promise<MiniSkill[]> { return []; }\n async loadByProject(_projectId: string): Promise<MiniSkill[]> { return []; }\n async loadIdCounter(): Promise<number> { return 1; }\n\n async insert(_skill: MiniSkill): Promise<void> { this.warn(); }\n async update(_skill: MiniSkill): Promise<void> { this.warn(); }\n async remove(_id: number): Promise<void> { this.warn(); }\n async saveIdCounter(_nextId: number): Promise<void> { /* no-op */ }\n async atomicInsertWithId(skillWithoutId: Omit<MiniSkill, 'id'>): Promise<MiniSkill> {\n this.warn();\n return { ...skillWithoutId, id: 0 } as MiniSkill;\n }\n\n async ensureFresh(): Promise<boolean> { return false; }\n getGeneration(): number { return 0; }\n getBackendName(): 'sqlite' | 'degraded' { return 'degraded'; }\n}\n\n// ── Singleton access ────────────────────────────────────────────────\n\nlet _store: MiniSkillStore | null = null;\nlet _storeDataDir: string | null = null;\n\nexport function isMiniSkillStoreInitialized(): boolean {\n return _store !== null;\n}\n\nexport function getMiniSkillStore(): MiniSkillStore {\n if (!_store) {\n throw new Error('[memorix] MiniSkillStore not initialized — call initMiniSkillStore() first');\n }\n return _store;\n}\n\nexport function resetMiniSkillStore(): void {\n _store = null;\n _storeDataDir = null;\n}\n\nexport async function initMiniSkillStore(dataDir: string): Promise<MiniSkillStore> {\n if (_store && _storeDataDir === dataDir) return _store;\n\n _store = null;\n _storeDataDir = null;\n\n // Try SQLite first\n try {\n const store = new MiniSkillSqliteStore();\n await store.init(dataDir);\n _store = store;\n _storeDataDir = dataDir;\n return store;\n } catch (err) {\n console.error(`[memorix] MiniSkillSqliteStore unavailable, running in degraded read-only mode: ${err instanceof Error ? err.message : err}`);\n }\n\n // Fallback: graceful degrade (no writable JSON backend per debt-zero rule)\n const store = new MiniSkillGracefulDegrade();\n await store.init(dataDir);\n _store = store;\n _storeDataDir = dataDir;\n return store;\n}\n","/**\n * Token Budget Manager\n *\n * Provides token counting and budget management for Progressive Disclosure.\n * Source: gpt-tokenizer (737 stars, JS port of OpenAI's tiktoken)\n *\n * Used by the Compact Engine to determine which layer of detail\n * fits within the caller's token budget.\n */\n\nimport { countTokens, isWithinTokenLimit } from 'gpt-tokenizer';\n\n/**\n * Count tokens in a string.\n */\nexport function countTextTokens(text: string): number {\n return countTokens(text);\n}\n\n/**\n * Check if text fits within a token limit.\n * Returns the token count if within limit, false otherwise.\n */\nexport function fitsInBudget(text: string, limit: number): number | false {\n return isWithinTokenLimit(text, limit);\n}\n\n/**\n * Truncate text to fit within a token budget.\n * Truncates at sentence boundaries when possible.\n */\nexport function truncateToTokenBudget(text: string, budget: number): string {\n if (fitsInBudget(text, budget) !== false) {\n return text;\n }\n\n // Binary search for the right length\n const sentences = text.split(/(?<=[.!?])\\s+/);\n let result = '';\n\n for (const sentence of sentences) {\n const candidate = result ? `${result} ${sentence}` : sentence;\n if (fitsInBudget(candidate, budget) === false) {\n break;\n }\n result = candidate;\n }\n\n // If no complete sentence fits, truncate by characters\n if (!result) {\n // Rough estimate: 1 token ≈ 4 chars for English, ≈ 1.5 chars for Chinese\n const estimatedChars = budget * 2;\n result = text.slice(0, estimatedChars);\n // Refine\n while (fitsInBudget(result, budget) === false && result.length > 0) {\n result = result.slice(0, Math.floor(result.length * 0.9));\n }\n if (result.length < text.length) {\n // A character estimate can end halfway through a flag, path, or symbol.\n // Drop the incomplete whitespace-delimited token instead of returning\n // misleading fragments such as `AUTH...`.\n const nextCharacter = text.charAt(result.length);\n if (nextCharacter && !/[\\s.,;:!?)}\\]]/.test(nextCharacter)) {\n const boundary = result.search(/\\s+\\S*$/);\n result = boundary > 0 ? result.slice(0, boundary).trimEnd() : '';\n }\n\n // Keep the suffix inside the stated budget when there is room. An empty\n // prefix is more honest than a partial identifier that appears valid.\n while (result && fitsInBudget(result + '...', budget) === false) {\n const boundary = result.lastIndexOf(' ');\n result = boundary > 0 ? result.slice(0, boundary).trimEnd() : '';\n }\n result = result ? result + '...' : '...';\n }\n }\n\n return result;\n}\n\n/**\n * Estimate the token cost of an IndexEntry line.\n * Used to predict compact index size.\n */\nexport function estimateIndexEntryTokens(title: string): number {\n // Format: \"| #ID | Time | Icon | Title | ~Tokens |\"\n // Overhead is roughly 15 tokens for formatting\n return countTextTokens(title) + 15;\n}\n","/**\n * Mini-Skills Engine — Promoted memories that never decay\n *\n * Converts important observations into permanent, actionable \"mini-skills\"\n * that are automatically injected into agent context during session_start.\n *\n * Unlike generic SKILL.md files from marketplaces, mini-skills are:\n * - Derived from YOUR project's actual memories (gotchas, decisions, fixes)\n * - Immune from retention decay (permanent knowledge)\n * - Auto-injected at session start (agents proactively apply them)\n * - Cross-IDE shared (stored in ~/.memorix/data/ alongside observations)\n *\n * Lifecycle: observation → memorix_promote → mini-skill → session_start injection\n */\n\nimport type { MiniSkill, Observation, SourceSnapshot, SnapshotObservation, KnowledgeLayer, DocumentType, MemorixDocument } from '../types.js';\nimport { getMiniSkillStore } from '../store/mini-skill-store.js';\nimport { countTextTokens } from '../compact/token-budget.js';\n\n// Hard filter: command execution logs are not promotable knowledge\nconst COMMAND_LOG_TITLE = /^(Ran:|Command:|Executed:)\\s/i;\n\n// ── Promote observations to mini-skills ──────────────────────────\n\nexport interface PromoteOptions {\n /** Override auto-generated trigger description */\n trigger?: string;\n /** Override auto-generated instruction */\n instruction?: string;\n /** Extra tags */\n tags?: string[];\n /** Bypass R2 (no command logs) and R3 (has content) validation. Cannot bypass R1 (sources must exist). */\n force?: boolean;\n}\n\n/** Provenance status of a mini-skill relative to its source observations */\nexport type ProvenanceStatus =\n | 'verified' // all source observations exist and are active\n | 'partial' // some source observations exist\n | 'snapshot-only' // no sources available, but snapshot exists\n | 'legacy'; // no snapshot AND no sources (unverifiable)\n\n/**\n * Promote one or more observations into a mini-skill.\n * The source observations are NOT deleted — they remain in the observation store\n * but the mini-skill is the permanent, never-decaying version.\n */\nexport async function promoteToMiniSkill(\n projectDir: string,\n projectId: string,\n observations: Observation[],\n options?: PromoteOptions,\n): Promise<MiniSkill> {\n // ── Promote-time validation ────────────────────────────────────\n // R1a: Sources must exist (cannot be bypassed)\n if (observations.length === 0) {\n throw new Error('Cannot promote: no source observations provided');\n }\n\n // R1b: All sources must be active — stale/archived knowledge must never be\n // permanently promoted. This check is NOT bypassable by force=true.\n const nonActive = observations.filter(o => (o.status ?? 'active') !== 'active');\n if (nonActive.length > 0) {\n throw new Error(\n `Cannot promote: ${nonActive.length} observation(s) are not active. ` +\n `Blocked: ${nonActive.map(o => `#${o.id} (${o.status ?? 'unknown'})`).join(', ')}. ` +\n `Only active observations can be promoted to permanent knowledge.`,\n );\n }\n\n // R1c: Probe observations are operational heartbeats -- never promotable, even with force=true\n const probes = observations.filter(o => o.type === 'probe');\n if (probes.length > 0) {\n throw new Error(\n `Cannot promote probe observations — they are operational heartbeats, not durable knowledge. ` +\n `Blocked: ${probes.map(o => `#${o.id} \"${o.title.substring(0, 60)}\"`).join(', ')}.`,\n );\n }\n\n if (!options?.force) {\n // R2: No command-log noise\n const commandLogs = observations.filter(o => COMMAND_LOG_TITLE.test(o.title));\n if (commandLogs.length > 0) {\n throw new Error(\n `Cannot promote command execution logs — use a knowledge observation instead. ` +\n `Blocked: ${commandLogs.map(o => `#${o.id} \"${o.title.substring(0, 60)}\"`).join(', ')}. ` +\n `Use force=true to override.`,\n );\n }\n\n // R3: Has substantive content\n const hasContent = observations.some(\n o => (o.narrative && o.narrative.trim().length > 0) ||\n (o.facts && o.facts.length > 0 && o.facts.some(f => f.trim().length > 0)),\n );\n if (!hasContent) {\n throw new Error(\n 'Cannot promote: source observations have no substantive content (empty narrative and facts). ' +\n 'Use force=true to override.',\n );\n }\n }\n\n // ── Freeze source snapshot (immutable provenance proof) ────────\n const snapshot = createSourceSnapshot(observations);\n const snapshotJson = JSON.stringify(snapshot);\n\n const store = getMiniSkillStore();\n\n // Auto-generate content from observations\n const title = generateTitle(observations);\n const instruction = options?.instruction || generateInstruction(observations);\n const trigger = options?.trigger || generateTrigger(observations);\n const facts = extractFacts(observations);\n const tags = [\n ...(options?.tags || []),\n ...extractTags(observations),\n ];\n\n const now = new Date().toISOString();\n\n // Atomic: ID allocation + insert + counter bump in a single SQLite transaction.\n // Prevents concurrent promotes from receiving the same ID.\n const skill = await store.atomicInsertWithId({\n sourceObservationIds: observations.map(o => o.id),\n sourceEntity: observations[0]?.entityName || 'unknown',\n title,\n instruction,\n trigger,\n facts,\n projectId,\n createdAt: now,\n usedCount: 0,\n tags: [...new Set(tags)],\n sourceSnapshot: snapshotJson,\n updatedAt: now,\n });\n\n return skill;\n}\n\n// ── Load & query mini-skills ─────────────────────────────────────\n\n/**\n * Load all mini-skills for a project.\n */\nexport async function loadMiniSkills(\n projectDir: string,\n projectId?: string,\n): Promise<MiniSkill[]> {\n const store = getMiniSkillStore();\n if (!projectId) return store.loadAll();\n return store.loadByProject(projectId);\n}\n\n/**\n * Load all mini-skills (unfiltered).\n */\nexport async function loadAllMiniSkills(projectDir: string): Promise<MiniSkill[]> {\n return getMiniSkillStore().loadAll();\n}\n\n/**\n * Delete a mini-skill by ID.\n */\nexport async function deleteMiniSkill(\n projectDir: string,\n skillId: number,\n): Promise<boolean> {\n const store = getMiniSkillStore();\n const all = await store.loadAll();\n const exists = all.some(s => s.id === skillId);\n if (!exists) return false;\n await store.remove(skillId);\n return true;\n}\n\n/**\n * Increment usedCount for skills that were injected in session_start.\n */\nexport async function recordMiniSkillUsage(\n projectDir: string,\n skillIds: number[],\n): Promise<void> {\n if (skillIds.length === 0) return;\n const store = getMiniSkillStore();\n const existing = await store.loadAll();\n for (const skill of existing) {\n if (skillIds.includes(skill.id)) {\n skill.usedCount++;\n await store.update(skill);\n }\n }\n}\n\n// ── Format mini-skills for session injection ─────────────────────\n\n/**\n * Format mini-skills for injection into session_start context.\n * Returns a markdown string ready to append to session context.\n */\nexport function formatMiniSkillsForInjection(skills: MiniSkill[]): string {\n if (skills.length === 0) return '';\n\n const lines = [\n `## [SESSION] Project Mini-Skills (${skills.length} active)`,\n '',\n ];\n\n for (const skill of skills) {\n lines.push(`### ${skill.title}`);\n lines.push(`**Do**: ${skill.instruction}`);\n lines.push(`**When**: ${skill.trigger}`);\n if (skill.facts.length > 0) {\n for (const fact of skill.facts) {\n lines.push(`- ${fact}`);\n }\n }\n lines.push('');\n }\n\n return lines.join('\\n');\n}\n\n// ── Auto-generation helpers ──────────────────────────────────────\n\nfunction generateTitle(observations: Observation[]): string {\n if (observations.length === 1) {\n return observations[0].title;\n }\n // Multiple observations — use the first one's title as base\n return observations[0].title;\n}\n\nfunction generateInstruction(observations: Observation[]): string {\n // Convert narrative into imperative instruction\n const obs = observations[0];\n const narrative = obs.narrative || '';\n\n // For gotchas, flip to \"avoid\" instruction\n if (obs.type === 'gotcha') {\n return `Avoid: ${narrative.split('\\n')[0]}`;\n }\n // For decisions, state the chosen approach\n if (obs.type === 'decision') {\n return `Follow: ${narrative.split('\\n')[0]}`;\n }\n // For problem-solution, state the solution\n if (obs.type === 'problem-solution') {\n return `Apply fix: ${narrative.split('\\n')[0]}`;\n }\n // Default: use narrative as-is\n return narrative.split('\\n')[0] || obs.title;\n}\n\nfunction generateTrigger(observations: Observation[]): string {\n const obs = observations[0];\n\n // Use entity name + file paths as trigger context\n const parts: string[] = [];\n if (obs.entityName && obs.entityName !== 'unknown') {\n parts.push(`Working on ${obs.entityName}`);\n }\n if (obs.filesModified.length > 0) {\n parts.push(`touching ${obs.filesModified.slice(0, 3).join(', ')}`);\n }\n if (obs.concepts.length > 0) {\n parts.push(`involving ${obs.concepts.slice(0, 3).join(', ')}`);\n }\n\n return parts.length > 0 ? parts.join('; ') : `Related to ${obs.title}`;\n}\n\nfunction extractFacts(observations: Observation[]): string[] {\n const facts = new Set<string>();\n for (const obs of observations) {\n for (const f of obs.facts) {\n facts.add(f);\n }\n }\n return [...facts].slice(0, 10);\n}\n\nfunction extractTags(observations: Observation[]): string[] {\n const tags = new Set<string>();\n for (const obs of observations) {\n tags.add(obs.type);\n for (const c of obs.concepts) {\n if (c.length <= 30) tags.add(c.toLowerCase());\n }\n }\n return [...tags].slice(0, 10);\n}\n\n// ── Provenance helpers (Phase 3a) ────────────────────────────────\n\n/**\n * Create an immutable source snapshot from observations at promote time.\n * Contains the minimum field set needed for self-contained provenance proof.\n */\nfunction createSourceSnapshot(observations: Observation[]): SourceSnapshot {\n return {\n observations: observations.map((o): SnapshotObservation => ({\n id: o.id,\n title: o.title,\n type: o.type,\n narrative: o.narrative,\n facts: [...o.facts],\n entityName: o.entityName,\n projectId: o.projectId,\n createdAt: o.createdAt,\n sourceDetail: o.sourceDetail,\n })),\n promotedAt: new Date().toISOString(),\n };\n}\n\n/**\n * Resolve the provenance status of a mini-skill by checking whether its\n * source observations still exist.\n *\n * @param skill The mini-skill to check\n * @param getObservationById Lookup function: (id) => Observation | undefined\n */\nexport function resolveProvenanceStatus(\n skill: MiniSkill,\n getObservationById: (id: number) => { id: number; status?: string } | undefined,\n): ProvenanceStatus {\n const ids = skill.sourceObservationIds;\n if (ids.length === 0) {\n return skill.sourceSnapshot ? 'snapshot-only' : 'legacy';\n }\n const found = ids.filter(id => {\n const obs = getObservationById(id);\n return obs && (obs.status ?? 'active') === 'active';\n });\n if (found.length === ids.length) return 'verified';\n if (found.length > 0) return 'partial';\n return skill.sourceSnapshot ? 'snapshot-only' : 'legacy';\n}\n\n// ── Knowledge Layer helpers (Phase 3a) ───────────────────────────\n\n/**\n * Resolve the knowledge layer for a document based on its type and source.\n * This is computed at index time — NOT stored in SQLite.\n */\nexport function resolveKnowledgeLayer(\n documentType: DocumentType,\n sourceDetail?: string,\n source?: string,\n): KnowledgeLayer {\n if (documentType === 'mini-skill') return 'promoted';\n if (sourceDetail === 'git-ingest' || source === 'git') return 'evidence';\n return 'project-truth';\n}\n\n/**\n * Convert a MiniSkill into a MemorixDocument for Orama indexing.\n * The document carries documentType='mini-skill' and knowledgeLayer='promoted'.\n */\nexport function miniSkillToDocument(skill: MiniSkill): MemorixDocument {\n const content = skill.instruction + '\\n' + skill.facts.join('\\n');\n return {\n id: `skill:${encodeURIComponent(skill.projectId)}:${skill.id}`,\n observationId: skill.id,\n entityName: skill.sourceEntity,\n type: 'mini-skill',\n title: skill.title,\n narrative: skill.instruction,\n facts: skill.facts.join('\\n'),\n filesModified: '',\n concepts: skill.tags.join(', '),\n tokens: countTextTokens(content),\n createdAt: skill.createdAt,\n projectId: skill.projectId,\n accessCount: skill.usedCount,\n lastAccessedAt: '',\n status: 'active',\n source: 'agent',\n sourceDetail: 'explicit',\n valueCategory: 'core',\n documentType: 'mini-skill',\n knowledgeLayer: 'promoted',\n };\n}\n","import type { ObservationReader, ObservationVisibility } from '../types.js';\n\n/** Minimal common shape shared by persisted observations and Orama documents. */\nexport interface VisibilityRecord {\n projectId: string;\n visibility?: ObservationVisibility | string;\n createdByAgentId?: string;\n sharedWithAgentIds?: string[] | string;\n}\n\n/**\n * Pre-control-plane records were intentionally project-shared. Preserve that\n * behavior so an upgrade does not make a user's historical memory disappear.\n */\nexport function resolveObservationVisibility(record: Pick<VisibilityRecord, 'visibility'>): ObservationVisibility {\n switch (record.visibility) {\n case 'personal':\n case 'team':\n case 'project':\n return record.visibility;\n default:\n return 'project';\n }\n}\n\nfunction sharedAgentIds(record: VisibilityRecord): string[] {\n if (Array.isArray(record.sharedWithAgentIds)) return record.sharedWithAgentIds;\n if (typeof record.sharedWithAgentIds !== 'string' || !record.sharedWithAgentIds) return [];\n try {\n const parsed = JSON.parse(record.sharedWithAgentIds);\n return Array.isArray(parsed) ? parsed.filter((id): id is string => typeof id === 'string') : [];\n } catch {\n return [];\n }\n}\n\n/**\n * The policy is intentionally fail-closed for personal and team scopes. A\n * missing actor never turns a private record into a project-wide result.\n * `undefined` is reserved for trusted internal maintenance, not MCP delivery.\n */\nexport function canReadObservation(record: VisibilityRecord, reader?: ObservationReader): boolean {\n if (!reader) return true;\n\n const sameProject = reader.projectId === record.projectId;\n const visibility = resolveObservationVisibility(record);\n // An explicit global search may inspect project-visible facts across projects,\n // but it never gains a team or personal scope without a bound project.\n if (visibility === 'project') return !reader.projectId || sameProject;\n if (!sameProject || !reader.agentId) return false;\n\n if (visibility === 'team') return reader.isTeamMember === true;\n return record.createdByAgentId === reader.agentId || sharedAgentIds(record).includes(reader.agentId);\n}\n\n/**\n * Reading a targeted handoff does not grant the recipient permission to alter\n * it. Project evidence is jointly maintainable; personal records stay owned by\n * their creator; team records require an active team member.\n */\nexport function canManageObservation(record: VisibilityRecord, reader?: ObservationReader): boolean {\n if (!reader) return true;\n if (!reader.projectId || reader.projectId !== record.projectId) return false;\n\n switch (resolveObservationVisibility(record)) {\n case 'project':\n return true;\n case 'team':\n return reader.isTeamMember === true;\n case 'personal':\n return Boolean(reader.agentId && record.createdByAgentId === reader.agentId);\n }\n}\n\nexport function filterReadableObservations<T extends VisibilityRecord>(\n observations: readonly T[],\n reader?: ObservationReader,\n): T[] {\n return reader ? observations.filter((observation) => canReadObservation(observation, reader)) : [...observations];\n}\n","/**\n * FastEmbed Provider\n *\n * Local ONNX-based embedding using fastembed (Qdrant).\n * Model: BAAI/bge-small-en-v1.5 (384 dimensions, ~30MB)\n *\n * This is an optional dependency — if fastembed is not installed,\n * the provider module gracefully falls back to fulltext-only search.\n *\n * Persistent disk cache: embeddings are saved to ~/.memorix/data/.embedding-cache.json\n * so server restarts don't need to regenerate them (saves minutes of CPU on 500+ obs).\n */\n\nimport { createHash } from 'node:crypto';\nimport { readFile, writeFile, mkdir } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\nimport type { EmbeddingProvider } from './provider.js';\n\nconst CACHE_DIR = process.env.MEMORIX_DATA_DIR || join(homedir(), '.memorix', 'data');\nconst CACHE_FILE = join(CACHE_DIR, '.embedding-cache.json');\n\n// In-memory cache keyed by text hash → embedding\nconst cache = new Map<string, number[]>();\nconst MAX_CACHE_SIZE = 5000;\nlet diskCacheDirty = false;\n\nfunction textHash(text: string): string {\n return createHash('sha256').update(text).digest('hex').slice(0, 16);\n}\n\nasync function loadDiskCache(): Promise<void> {\n try {\n const raw = await readFile(CACHE_FILE, 'utf-8');\n const entries: [string, number[]][] = JSON.parse(raw);\n for (const [k, v] of entries) cache.set(k, v);\n console.error(`[memorix] Loaded ${entries.length} cached embeddings from disk`);\n } catch {\n // No cache file or corrupt — start fresh\n }\n}\n\nasync function saveDiskCache(): Promise<void> {\n if (!diskCacheDirty) return;\n try {\n await mkdir(CACHE_DIR, { recursive: true });\n const entries = Array.from(cache.entries());\n await writeFile(CACHE_FILE, JSON.stringify(entries));\n diskCacheDirty = false;\n } catch {\n // Ignore write errors — cache is an optimization, not critical\n }\n}\n\nexport class FastEmbedProvider implements EmbeddingProvider {\n readonly name = 'fastembed-bge-small';\n readonly dimensions = 384;\n\n private model: { embed: (docs: string[], batchSize?: number) => AsyncGenerator<number[][]>; queryEmbed: (query: string) => Promise<number[]> };\n\n private constructor(model: FastEmbedProvider['model']) {\n this.model = model;\n }\n\n /**\n * Initialize the FastEmbed provider.\n * Downloads model on first use (~30MB), cached locally after.\n * Loads persistent embedding cache from disk.\n */\n static async create(): Promise<FastEmbedProvider> {\n // Dynamic import — throws if fastembed is not installed\n const { EmbeddingModel, FlagEmbedding } = await import('fastembed');\n const model = await FlagEmbedding.init({\n model: EmbeddingModel.BGESmallENV15,\n });\n // Load disk cache before returning — subsequent embedBatch calls will hit cache\n await loadDiskCache();\n return new FastEmbedProvider(model);\n }\n\n async embed(text: string): Promise<number[]> {\n const hash = textHash(text);\n const cached = cache.get(hash);\n if (cached) return cached;\n\n const raw = await this.model.queryEmbed(text);\n // Ensure plain number[] (fastembed may return Float32Array)\n const result = Array.from(raw) as number[];\n if (result.length !== this.dimensions) {\n throw new Error(`Expected ${this.dimensions}d embedding, got ${result.length}d`);\n }\n this.cacheSet(hash, result);\n return result;\n }\n\n async embedBatch(texts: string[]): Promise<number[][]> {\n const results: number[][] = new Array(texts.length);\n const uncachedIndices: number[] = [];\n const uncachedTexts: string[] = [];\n\n // Check cache for each text (by hash)\n for (let i = 0; i < texts.length; i++) {\n const hash = textHash(texts[i]);\n const cached = cache.get(hash);\n if (cached) {\n results[i] = cached;\n } else {\n uncachedIndices.push(i);\n uncachedTexts.push(texts[i]);\n }\n }\n\n // Batch embed uncached texts\n if (uncachedTexts.length > 0) {\n console.error(`[memorix] Embedding ${uncachedTexts.length}/${texts.length} uncached texts (${texts.length - uncachedTexts.length} from cache)`);\n let batchIdx = 0;\n for await (const batch of this.model.embed(uncachedTexts, 64)) {\n for (const vec of batch) {\n const originalIdx = uncachedIndices[batchIdx];\n const plain = Array.from(vec) as number[];\n results[originalIdx] = plain;\n this.cacheSet(textHash(uncachedTexts[batchIdx]), plain);\n batchIdx++;\n }\n }\n // Persist cache to disk after batch operations\n await saveDiskCache();\n }\n\n return results;\n }\n\n private cacheSet(hash: string, value: number[]): void {\n // Evict oldest entries if cache is full\n if (cache.size >= MAX_CACHE_SIZE) {\n const firstKey = cache.keys().next().value;\n if (firstKey !== undefined) cache.delete(firstKey);\n }\n cache.set(hash, value);\n diskCacheDirty = true;\n }\n}\n","/**\n * Transformers.js Provider\n *\n * Pure JavaScript embedding using @huggingface/transformers (HuggingFace).\n * Model: Xenova/all-MiniLM-L6-v2 (384 dimensions, ~22MB quantized)\n *\n * Key advantages over fastembed:\n * - No native ONNX binding required (pure JS / WASM)\n * - Works out-of-the-box on Windows, macOS, Linux\n * - Supports quantized models (q8, q4) for smaller footprint\n *\n * This is an optional dependency — if @huggingface/transformers is not\n * installed, the provider module gracefully falls back to the next option.\n *\n * Inspired by Mem0's multi-provider embedding architecture.\n */\n\nimport type { EmbeddingProvider } from './provider.js';\n\n// In-memory LRU cache\nconst cache = new Map<string, number[]>();\nconst MAX_CACHE_SIZE = 5000;\n\nexport class TransformersProvider implements EmbeddingProvider {\n readonly name = 'transformers-minilm';\n readonly dimensions = 384;\n\n private extractor: any; // Pipeline instance\n\n private constructor(extractor: any) {\n this.extractor = extractor;\n }\n\n /**\n * Initialize the Transformers.js provider.\n * Downloads model on first use (~22MB quantized), cached locally after.\n */\n static async create(): Promise<TransformersProvider> {\n // Dynamic import — throws if @huggingface/transformers is not installed\n const { pipeline } = await import('@huggingface/transformers');\n const extractor = await pipeline(\n 'feature-extraction',\n 'Xenova/all-MiniLM-L6-v2',\n { dtype: 'q8' }, // Quantized for small footprint\n );\n return new TransformersProvider(extractor);\n }\n\n async embed(text: string): Promise<number[]> {\n // Check cache first\n const cached = cache.get(text);\n if (cached) return cached;\n\n const output = await this.extractor(text, {\n pooling: 'mean',\n normalize: true,\n });\n\n // output.tolist() returns [[...384 floats]]\n const result: number[] = Array.from(output.tolist()[0]);\n if (result.length !== this.dimensions) {\n throw new Error(`Expected ${this.dimensions}d embedding, got ${result.length}d`);\n }\n\n this.cacheSet(text, result);\n return result;\n }\n\n async embedBatch(texts: string[]): Promise<number[][]> {\n const results: number[][] = new Array(texts.length);\n const uncachedIndices: number[] = [];\n const uncachedTexts: string[] = [];\n\n // Check cache for each text\n for (let i = 0; i < texts.length; i++) {\n const cached = cache.get(texts[i]);\n if (cached) {\n results[i] = cached;\n } else {\n uncachedIndices.push(i);\n uncachedTexts.push(texts[i]);\n }\n }\n\n // Batch embed uncached texts\n if (uncachedTexts.length > 0) {\n const output = await this.extractor(uncachedTexts, {\n pooling: 'mean',\n normalize: true,\n });\n const allVecs: number[][] = output.tolist();\n\n for (let i = 0; i < allVecs.length; i++) {\n const vec = Array.from(allVecs[i]) as number[];\n const originalIdx = uncachedIndices[i];\n results[originalIdx] = vec;\n this.cacheSet(uncachedTexts[i], vec);\n }\n }\n\n return results;\n }\n\n private cacheSet(key: string, value: number[]): void {\n if (cache.size >= MAX_CACHE_SIZE) {\n const firstKey = cache.keys().next().value;\n if (firstKey !== undefined) cache.delete(firstKey);\n }\n cache.set(key, value);\n }\n}\n","/**\n * API Embedding Provider\n *\n * Remote embedding via any OpenAI-compatible /v1/embeddings endpoint.\n * Works with OpenAI, DashScope/Qwen, Ollama-compatible gateways, and similar providers.\n */\n\nimport { createHash } from 'node:crypto';\nimport { readFile, writeFile, mkdir } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\nimport type { EmbeddingProvider } from './provider.js';\n\nconst CACHE_DIR = process.env.MEMORIX_DATA_DIR || join(homedir(), '.memorix', 'data');\nconst CACHE_FILE = join(CACHE_DIR, '.embedding-api-cache.json');\nconst DIMS_CACHE_FILE = join(CACHE_DIR, '.embedding-dims-cache.json');\nconst CACHE_META_FILE = join(CACHE_DIR, '.embedding-api-cache-meta.json');\n\nconst cache = new Map<string, number[]>();\nconst MAX_CACHE_SIZE = 10000;\nlet diskCacheDirty = false;\nlet diskSaveTimer: ReturnType<typeof setTimeout> | null = null;\nlet diskCacheLoaded = false;\nlet diskCacheLoadPromise: Promise<void> | null = null;\n\nconst MAX_INPUT_CHARS = 32000;\nconst MAX_CONCURRENCY = 4;\nconst DISK_SAVE_DEBOUNCE_MS = 5000;\n\nconst DEFAULT_MAX_BATCH_SIZE = 2048;\nconst DASHSCOPE_MAX_BATCH_SIZE = 10;\nconst MAX_RETRIES = 3;\nconst BASE_DELAY_MS = 500;\n\nfunction normalizeText(text: string): string {\n return text.replace(/\\s+/g, ' ').trim().slice(0, MAX_INPUT_CHARS);\n}\n\nfunction cacheNamespace(config: Pick<APIEmbeddingConfig, 'baseUrl' | 'model' | 'requestedDimensions'>): string {\n return [\n 'v2',\n config.baseUrl.replace(/\\/+$/, ''),\n config.model,\n config.requestedDimensions ?? 'native',\n ].join('|');\n}\n\nfunction textHash(text: string, namespace: string): string {\n return createHash('sha256').update(`${namespace}\\u0000${text}`).digest('hex').slice(0, 16);\n}\n\nasync function loadDiskCache(): Promise<void> {\n if (diskCacheLoaded) return;\n try {\n const raw = await readFile(CACHE_FILE, 'utf-8');\n const entries: [string, number[]][] = JSON.parse(raw);\n for (const [k, v] of entries) cache.set(k, v);\n console.error(`[memorix] Loaded ${entries.length} cached API embeddings from disk`);\n } catch {\n // No cache file or corrupt cache; start fresh.\n }\n diskCacheLoaded = true;\n}\n\n/** Start loading disk cache in background (non-blocking). */\nfunction startDiskCacheLoad(): void {\n if (diskCacheLoaded || diskCacheLoadPromise) return;\n diskCacheLoadPromise = loadDiskCache().catch(() => {});\n}\n\n/** Ensure disk cache is loaded (await if still in progress). */\nasync function ensureDiskCacheLoaded(): Promise<void> {\n if (diskCacheLoaded) return;\n if (diskCacheLoadPromise) { await diskCacheLoadPromise; return; }\n await loadDiskCache();\n}\n\nfunction dimsCacheKey(config: Pick<APIEmbeddingConfig, 'baseUrl' | 'model' | 'requestedDimensions'>): string {\n return [\n config.baseUrl.replace(/\\/+$/, ''),\n config.model,\n config.requestedDimensions ?? 'native',\n ].join('|');\n}\n\ninterface CacheMetadataEntry {\n namespace: string;\n dimensions: number;\n ts: number;\n}\n\nfunction isValidDimension(value: unknown): value is number {\n return typeof value === 'number' && Number.isInteger(value) && value > 0;\n}\n\n/**\n * The vector cache keeps a tiny, redundant namespace → dimensions map. It lets\n * cache-first startup recover when the separate dimensions cache is missing.\n */\nasync function loadCachedVectorDimensions(\n config: Pick<APIEmbeddingConfig, 'baseUrl' | 'model' | 'requestedDimensions'>,\n): Promise<number | null> {\n try {\n const raw = await readFile(CACHE_META_FILE, 'utf-8');\n const data = JSON.parse(raw);\n const namespace = cacheNamespace(config);\n if (!Array.isArray(data?.entries)) return null;\n const entry = data.entries.find((candidate: unknown) =>\n typeof candidate === 'object' &&\n candidate !== null &&\n (candidate as { namespace?: unknown }).namespace === namespace &&\n isValidDimension((candidate as { dimensions?: unknown }).dimensions),\n ) as CacheMetadataEntry | undefined;\n return entry?.dimensions ?? null;\n } catch {\n return null;\n }\n}\n\nasync function saveCachedVectorDimensions(\n config: Pick<APIEmbeddingConfig, 'baseUrl' | 'model' | 'requestedDimensions'>,\n dimensions: number,\n): Promise<void> {\n if (!isValidDimension(dimensions)) return;\n try {\n await mkdir(CACHE_DIR, { recursive: true });\n let entries: CacheMetadataEntry[] = [];\n try {\n const raw = await readFile(CACHE_META_FILE, 'utf-8');\n const data = JSON.parse(raw);\n if (Array.isArray(data?.entries)) {\n entries = data.entries.filter((candidate: unknown): candidate is CacheMetadataEntry =>\n typeof candidate === 'object' &&\n candidate !== null &&\n typeof (candidate as { namespace?: unknown }).namespace === 'string' &&\n isValidDimension((candidate as { dimensions?: unknown }).dimensions) &&\n typeof (candidate as { ts?: unknown }).ts === 'number',\n );\n }\n } catch {\n // The cache metadata is a best-effort acceleration layer.\n }\n\n const namespace = cacheNamespace(config);\n entries = entries.filter((entry) => entry.namespace !== namespace);\n entries.push({ namespace, dimensions, ts: Date.now() });\n await writeFile(CACHE_META_FILE, JSON.stringify({ version: 1, entries }));\n } catch {\n // A missing or read-only cache must never block embedding requests.\n }\n}\n\n/** Load cached probe dimensions from disk. Returns null if not cached. */\nasync function loadCachedDims(config: Pick<APIEmbeddingConfig, 'baseUrl' | 'model' | 'requestedDimensions'>): Promise<number | null> {\n try {\n const raw = await readFile(DIMS_CACHE_FILE, 'utf-8');\n const data = JSON.parse(raw);\n\n const key = dimsCacheKey(config);\n\n if (Array.isArray(data.entries)) {\n const entry = data.entries.find((candidate: unknown) =>\n typeof candidate === 'object' &&\n candidate !== null &&\n 'key' in candidate &&\n 'dimensions' in candidate &&\n (candidate as { key?: string }).key === key &&\n typeof (candidate as { dimensions?: unknown }).dimensions === 'number',\n ) as { dimensions: number } | undefined;\n if (entry) return entry.dimensions;\n }\n\n if (\n data.baseUrl === config.baseUrl &&\n data.model === config.model &&\n typeof data.dimensions === 'number' &&\n (data.requestedDimensions ?? null) === (config.requestedDimensions ?? null)\n ) {\n return data.dimensions;\n }\n\n if (\n data.baseUrl === config.baseUrl &&\n data.model === config.model &&\n typeof data.dimensions === 'number' &&\n (config.requestedDimensions ?? null) === null &&\n !('requestedDimensions' in data)\n ) {\n return data.dimensions;\n }\n } catch { /* no cache or corrupt */ }\n return null;\n}\n\n/** Persist probe dimensions for fast subsequent starts. */\nasync function saveCachedDims(config: Pick<APIEmbeddingConfig, 'baseUrl' | 'model' | 'requestedDimensions'>, dimensions: number): Promise<void> {\n try {\n await mkdir(CACHE_DIR, { recursive: true });\n const key = dimsCacheKey(config);\n let entries: Array<{ key: string; baseUrl: string; model: string; requestedDimensions: number | null; dimensions: number; ts: number }> = [];\n\n try {\n const raw = await readFile(DIMS_CACHE_FILE, 'utf-8');\n const data = JSON.parse(raw);\n if (Array.isArray(data.entries)) {\n entries = data.entries.filter((entry: unknown) =>\n typeof entry === 'object' &&\n entry !== null &&\n 'key' in entry &&\n typeof (entry as { key?: unknown }).key === 'string',\n ) as typeof entries;\n } else if (\n data &&\n typeof data === 'object' &&\n typeof data.baseUrl === 'string' &&\n typeof data.model === 'string' &&\n typeof data.dimensions === 'number'\n ) {\n entries = [{\n key: dimsCacheKey({\n baseUrl: data.baseUrl,\n model: data.model,\n requestedDimensions: data.requestedDimensions ?? null,\n }),\n baseUrl: data.baseUrl,\n model: data.model,\n requestedDimensions: data.requestedDimensions ?? null,\n dimensions: data.dimensions,\n ts: typeof data.ts === 'number' ? data.ts : Date.now(),\n }];\n }\n } catch {\n // no existing cache\n }\n\n const nextEntry = {\n key,\n baseUrl: config.baseUrl,\n model: config.model,\n requestedDimensions: config.requestedDimensions ?? null,\n dimensions,\n ts: Date.now(),\n };\n\n entries = entries.filter((entry) => entry.key !== key);\n entries.push(nextEntry);\n\n await writeFile(DIMS_CACHE_FILE, JSON.stringify({ entries }));\n } catch { /* best-effort */ }\n await saveCachedVectorDimensions(config, dimensions);\n}\n\nasync function saveDiskCacheNow(): Promise<void> {\n if (!diskCacheDirty) return;\n try {\n await mkdir(CACHE_DIR, { recursive: true });\n const entries = Array.from(cache.entries());\n await writeFile(CACHE_FILE, JSON.stringify(entries));\n diskCacheDirty = false;\n } catch {\n // Cache persistence is best-effort only.\n }\n}\n\nfunction scheduleDiskSave(): void {\n if (diskSaveTimer) clearTimeout(diskSaveTimer);\n diskSaveTimer = setTimeout(() => {\n saveDiskCacheNow().catch(() => {});\n diskSaveTimer = null;\n }, DISK_SAVE_DEBOUNCE_MS);\n}\n\nfunction cacheSet(hash: string, value: number[]): void {\n if (cache.size >= MAX_CACHE_SIZE) {\n const firstKey = cache.keys().next().value;\n if (firstKey !== undefined) cache.delete(firstKey);\n }\n cache.set(hash, value);\n diskCacheDirty = true;\n}\n\ninterface EmbeddingAPIResponse {\n object: string;\n data: Array<{\n object: string;\n index: number;\n embedding: number[];\n }>;\n model: string;\n usage?: {\n prompt_tokens: number;\n total_tokens: number;\n };\n}\n\ninterface APIEmbeddingConfig {\n apiKey: string;\n baseUrl: string;\n model: string;\n requestedDimensions: number | null;\n}\n\nexport interface APIEmbeddingProviderCreateOptions {\n /**\n * When false, only previously persisted dimension metadata may initialize\n * the provider. This keeps startup/cache hydration off the remote API path.\n */\n allowNetworkProbe?: boolean;\n}\n\nfunction resolveEnvEmbeddingApiKey(): string | undefined {\n return process.env.MEMORIX_EMBEDDING_API_KEY;\n}\n\nfunction getPreferredBatchSize(config: APIEmbeddingConfig): number {\n if (/dashscope\\.aliyuncs\\.com/i.test(config.baseUrl)) {\n return DASHSCOPE_MAX_BATCH_SIZE;\n }\n return DEFAULT_MAX_BATCH_SIZE;\n}\n\nfunction parseBatchLimit(error: unknown): number | null {\n if (!(error instanceof Error)) return null;\n\n const explicit = error.message.match(/should not be larger than\\s+(\\d+)/i);\n if (explicit) return parseInt(explicit[1], 10);\n\n if (/batch size/i.test(error.message)) {\n const fallback = error.message.match(/(\\d+)/);\n if (fallback) return parseInt(fallback[1], 10);\n }\n\n return null;\n}\n\nexport class APIEmbeddingProvider implements EmbeddingProvider {\n readonly name: string;\n readonly dimensions: number;\n\n private config: APIEmbeddingConfig;\n private readonly cacheKeyNamespace: string;\n private totalTokensUsed = 0;\n private totalApiCalls = 0;\n\n private constructor(config: APIEmbeddingConfig, detectedDimensions: number) {\n this.config = config;\n this.cacheKeyNamespace = cacheNamespace(config);\n this.dimensions = detectedDimensions;\n this.name = `api-${config.model.replace(/\\//g, '-')}`;\n }\n\n static async create(): Promise<APIEmbeddingProvider>;\n static async create(options: APIEmbeddingProviderCreateOptions & { allowNetworkProbe: false }): Promise<APIEmbeddingProvider | null>;\n static async create(options: APIEmbeddingProviderCreateOptions): Promise<APIEmbeddingProvider | null>;\n static async create(options: APIEmbeddingProviderCreateOptions = {}): Promise<APIEmbeddingProvider | null> {\n const config = APIEmbeddingProvider.resolveConfig();\n const allowNetworkProbe = options.allowNetworkProbe !== false;\n\n // Try cached dimensions first to avoid a network probe on cold start\n let probeDimensions = await loadCachedDims(config);\n let dimensionSource: 'dims-cache' | 'vector-cache' | 'probe' = 'dims-cache';\n if (probeDimensions === null) {\n probeDimensions = await loadCachedVectorDimensions(config);\n if (probeDimensions !== null) dimensionSource = 'vector-cache';\n }\n if (probeDimensions !== null) {\n console.error(`[memorix] API embedding: ${config.model} @ ${config.baseUrl} (${probeDimensions}d) [${dimensionSource}]`);\n if (dimensionSource === 'dims-cache') {\n void saveCachedVectorDimensions(config, probeDimensions);\n }\n } else {\n if (!allowNetworkProbe) return null;\n probeDimensions = await APIEmbeddingProvider.probeAPI(config);\n console.error(`[memorix] API embedding: ${config.model} @ ${config.baseUrl} (${probeDimensions}d)`);\n // Persist for next cold start\n saveCachedDims(config, probeDimensions).catch(() => {});\n }\n if (config.requestedDimensions) {\n console.error(`[memorix] Dimension shortening: ${config.requestedDimensions}d requested`);\n }\n\n // The cache can only be used after dimensions are known. In cache-only\n // startup with no metadata, skip parsing the potentially large cache file\n // altogether and stay lexical until a normal embedding lane is needed.\n startDiskCacheLoad();\n\n return new APIEmbeddingProvider(config, probeDimensions);\n }\n\n private static resolveConfig(): APIEmbeddingConfig {\n let apiKey: string | undefined;\n let baseUrl: string;\n let model: string;\n let requestedDimensions: number | null;\n\n try {\n let cfg: {\n getEmbeddingApiKey: () => string | undefined;\n getEmbeddingBaseUrl: () => string;\n getEmbeddingModel: () => string;\n getEmbeddingDimensions: () => number | null;\n };\n try {\n cfg = require('../config.ts');\n } catch {\n cfg = require('../config.js');\n }\n baseUrl = cfg.getEmbeddingBaseUrl();\n apiKey = cfg.getEmbeddingApiKey();\n model = cfg.getEmbeddingModel();\n requestedDimensions = cfg.getEmbeddingDimensions();\n } catch {\n baseUrl =\n process.env.MEMORIX_EMBEDDING_BASE_URL ||\n 'https://api.openai.com/v1';\n apiKey = resolveEnvEmbeddingApiKey();\n model = process.env.MEMORIX_EMBEDDING_MODEL || 'text-embedding-3-small';\n const dimStr = process.env.MEMORIX_EMBEDDING_DIMENSIONS;\n requestedDimensions = dimStr ? parseInt(dimStr, 10) : null;\n }\n\n if (!apiKey) {\n throw new Error(\n 'No API key for embedding. Set MEMORIX_EMBEDDING_API_KEY or configure embedding.apiKey in memorix.yml / ~/.memorix/config.json.',\n );\n }\n\n baseUrl = baseUrl.replace(/\\/+$/, '');\n\n return { apiKey, baseUrl, model, requestedDimensions };\n }\n\n private static async probeAPI(config: APIEmbeddingConfig): Promise<number> {\n const body: Record<string, unknown> = {\n model: config.model,\n input: 'dimension probe',\n };\n if (config.requestedDimensions) {\n body.dimensions = config.requestedDimensions;\n }\n\n const response = await fetchWithRetry(\n `${config.baseUrl}/embeddings`,\n config.apiKey,\n body,\n );\n\n if (response.data.length === 0 || !response.data[0].embedding) {\n throw new Error('API probe returned no embeddings; check model name and API key');\n }\n\n return response.data[0].embedding.length;\n }\n\n async embed(text: string): Promise<number[]> {\n const normalized = normalizeText(text);\n const hash = textHash(normalized, this.cacheKeyNamespace);\n\n // Fast path: cache already loaded (warm process) — instant lookup\n if (diskCacheLoaded) {\n const cached = cache.get(hash);\n if (cached) return cached;\n }\n\n // Cold-start path: cache is still loading in background.\n // Race the cache completion (may have a hit) against the API call.\n // Whichever resolves first with a valid embedding wins.\n const apiCall = async (): Promise<number[]> => {\n const body: Record<string, unknown> = {\n model: this.config.model,\n input: normalized,\n };\n if (this.config.requestedDimensions) {\n body.dimensions = this.config.requestedDimensions;\n }\n const response = await fetchWithRetry(\n `${this.config.baseUrl}/embeddings`,\n this.config.apiKey,\n body,\n );\n const embedding = response.data[0].embedding;\n if (embedding.length !== this.dimensions) {\n throw new Error(`Expected ${this.dimensions}d, got ${embedding.length}d; dimension mismatch`);\n }\n this.trackUsage(response);\n return embedding;\n };\n\n let embedding: number[];\n\n if (!diskCacheLoaded && diskCacheLoadPromise) {\n // Race: cache load + lookup vs API call\n const cacheRace = diskCacheLoadPromise.then(() => {\n const cached = cache.get(hash);\n if (cached) return cached;\n return null; // miss — let API win\n });\n\n const result = await Promise.race([\n cacheRace,\n apiCall().then(v => ({ __api: true, v } as const)),\n ]);\n\n if (result && typeof result === 'object' && '__api' in result) {\n // API finished first\n embedding = result.v;\n } else if (result) {\n // Cache hit won the race\n return result as number[];\n } else {\n // Cache loaded but missed — await the API call\n embedding = await apiCall();\n }\n } else {\n // No cache loading — just call API\n embedding = await apiCall();\n }\n\n cacheSet(hash, embedding);\n scheduleDiskSave();\n return embedding;\n }\n\n async embedBatch(texts: string[]): Promise<number[][]> {\n await ensureDiskCacheLoaded();\n const normalizedTexts = texts.map(normalizeText);\n const results: number[][] = new Array(texts.length);\n const uncachedIndices: number[] = [];\n const uncachedTexts: string[] = [];\n\n for (let i = 0; i < normalizedTexts.length; i++) {\n const hash = textHash(normalizedTexts[i], this.cacheKeyNamespace);\n const cached = cache.get(hash);\n if (cached) {\n results[i] = cached;\n } else {\n uncachedIndices.push(i);\n uncachedTexts.push(normalizedTexts[i]);\n }\n }\n\n if (uncachedTexts.length === 0) return results;\n\n const cacheHitRate = ((texts.length - uncachedTexts.length) / texts.length * 100).toFixed(1);\n console.error(\n `[memorix] API embedding ${uncachedTexts.length}/${texts.length} texts (cache hit: ${cacheHitRate}%)`,\n );\n\n const processChunk = async (chunkTexts: string[], chunkIndices: number[]): Promise<void> => {\n if (chunkTexts.length === 0) return;\n\n const body: Record<string, unknown> = {\n model: this.config.model,\n input: chunkTexts,\n };\n if (this.config.requestedDimensions) {\n body.dimensions = this.config.requestedDimensions;\n }\n\n try {\n const response = await fetchWithRetry(\n `${this.config.baseUrl}/embeddings`,\n this.config.apiKey,\n body,\n );\n\n this.trackUsage(response);\n\n for (const item of response.data) {\n const originalIdx = chunkIndices[item.index];\n results[originalIdx] = item.embedding;\n cacheSet(textHash(normalizedTexts[originalIdx], this.cacheKeyNamespace), item.embedding);\n }\n } catch (error) {\n const providerLimit = parseBatchLimit(error);\n const fallbackSize = providerLimit ?? Math.ceil(chunkTexts.length / 2);\n\n if (chunkTexts.length > 1 && fallbackSize < chunkTexts.length) {\n console.error(\n `[memorix] Embedding batch too large for provider, retrying in chunks of ${fallbackSize}`,\n );\n for (let start = 0; start < chunkTexts.length; start += fallbackSize) {\n await processChunk(\n chunkTexts.slice(start, start + fallbackSize),\n chunkIndices.slice(start, start + fallbackSize),\n );\n }\n return;\n }\n\n throw error;\n }\n };\n\n const preferredBatchSize = getPreferredBatchSize(this.config);\n const chunks: { texts: string[]; indices: number[] }[] = [];\n for (let batchStart = 0; batchStart < uncachedTexts.length; batchStart += preferredBatchSize) {\n chunks.push({\n texts: uncachedTexts.slice(batchStart, batchStart + preferredBatchSize),\n indices: uncachedIndices.slice(batchStart, batchStart + preferredBatchSize),\n });\n }\n\n for (let ci = 0; ci < chunks.length; ci += MAX_CONCURRENCY) {\n const concurrentChunks = chunks.slice(ci, ci + MAX_CONCURRENCY);\n await Promise.all(concurrentChunks.map((chunk) => processChunk(chunk.texts, chunk.indices)));\n }\n\n scheduleDiskSave();\n return results;\n }\n\n async getCachedEmbeddings(texts: string[]): Promise<(number[] | null)[]> {\n await ensureDiskCacheLoaded();\n return texts.map((text) => {\n const hash = textHash(normalizeText(text), this.cacheKeyNamespace);\n return cache.get(hash) ?? null;\n });\n }\n\n getStats(): { totalTokens: number; totalApiCalls: number; cacheSize: number } {\n return {\n totalTokens: this.totalTokensUsed,\n totalApiCalls: this.totalApiCalls,\n cacheSize: cache.size,\n };\n }\n\n private trackUsage(response: EmbeddingAPIResponse): void {\n this.totalApiCalls++;\n if (response.usage) {\n this.totalTokensUsed += response.usage.total_tokens;\n }\n }\n}\n\nasync function fetchWithRetry(\n url: string,\n apiKey: string,\n body: Record<string, unknown>,\n attempt = 0,\n): Promise<EmbeddingAPIResponse> {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), 10_000);\n let response: Response;\n try {\n response = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${apiKey}`,\n },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n } catch (err: unknown) {\n clearTimeout(timeout);\n if (err instanceof Error && err.name === 'AbortError') {\n throw new Error(`Embedding API timeout after 10s: ${url}`);\n }\n throw err;\n }\n clearTimeout(timeout);\n\n if (response.ok) {\n return response.json() as Promise<EmbeddingAPIResponse>;\n }\n\n if ((response.status === 429 || response.status >= 500) && attempt < MAX_RETRIES) {\n const delay = BASE_DELAY_MS * Math.pow(2, attempt);\n const retryAfter = response.headers.get('retry-after');\n const waitMs = retryAfter ? parseInt(retryAfter, 10) * 1000 : delay;\n console.error(`[memorix] Embedding API ${response.status}, retry ${attempt + 1}/${MAX_RETRIES} in ${waitMs}ms`);\n await new Promise(resolve => setTimeout(resolve, waitMs));\n return fetchWithRetry(url, apiKey, body, attempt + 1);\n }\n\n const errorText = await response.text().catch(() => 'unknown error');\n throw new Error(`Embedding API error (${response.status}): ${errorText}`);\n}\n","/**\n * Embedding Provider — Abstraction Layer\n *\n * Extensible embedding interface. **Disabled by default** to minimize resource usage.\n *\n * Environment variable MEMORIX_EMBEDDING controls which provider to use:\n * - MEMORIX_EMBEDDING=off (default) → no embedding, BM25 fulltext search only (~50MB RAM)\n * - MEMORIX_EMBEDDING=fastembed → local ONNX inference (384-dim bge-small, ~300MB RAM)\n * - MEMORIX_EMBEDDING=transformers → pure JS WASM inference (384-dim MiniLM, ~500MB RAM)\n * - MEMORIX_EMBEDDING=api → remote API via OpenAI-compatible /v1/embeddings (zero local RAM)\n * - MEMORIX_EMBEDDING=auto → try configured API → fastembed → transformers → off\n *\n * API mode env vars (MEMORIX_EMBEDDING=api):\n * - MEMORIX_EMBEDDING_API_KEY → embedding API key\n * - MEMORIX_EMBEDDING_BASE_URL → base URL (default: https://api.openai.com/v1)\n * - MEMORIX_EMBEDDING_MODEL → model (default: text-embedding-3-small)\n * - MEMORIX_EMBEDDING_DIMENSIONS → optional dimension override\n *\n * Resource impact of local embedding:\n * - First load: 90%+ CPU for 5-30 seconds (model initialization)\n * - Steady state: 300-500MB RAM (model in memory)\n * - Per-query: 10-50ms CPU (embedding generation)\n *\n * Most users don't need vector search — BM25 fulltext is sufficient for keyword matching.\n * Vector search is useful for semantic similarity (e.g., \"auth\" matches \"authentication\").\n *\n * Architecture inspired by Mem0's multi-provider embedding design.\n */\n\nexport interface EmbeddingProvider {\n /** Provider name for logging/cache keys */\n readonly name: string;\n /** Vector dimensions (e.g., 384 for bge-small) */\n readonly dimensions: number;\n /** Generate embedding for a single text */\n embed(text: string): Promise<number[]>;\n /** Generate embeddings for multiple texts (batch) */\n embedBatch(texts: string[]): Promise<number[][]>;\n /** Return already-persisted embeddings without generating new vectors. */\n getCachedEmbeddings?(texts: string[]): Promise<(number[] | null)[]>;\n}\n\nexport interface GetEmbeddingProviderOptions {\n /** Avoid remote API dimension probes while preparing a startup index. */\n allowNetworkProbe?: boolean;\n}\n\n/** Singleton provider instance (null = not available) */\nlet provider: EmbeddingProvider | null = null;\nlet initPromise: Promise<EmbeddingProvider | null> | null = null;\n\ntype EmbeddingMode = 'off' | 'fastembed' | 'transformers' | 'api' | 'auto';\ntype ProviderKind = 'api' | 'fastembed' | 'transformers' | 'unknown';\n\n/**\n * Tracks whether the last init attempt resulted in a temporary failure\n * (mode != 'off' but provider returned null). When true, the next\n * getEmbeddingProvider() call will retry instead of returning cached null.\n */\nlet lastInitWasTemporaryFailure = false;\nlet lastEmbeddingWarning = '';\nlet lastEmbeddingWarningAt = 0;\nconst WARNING_COOLDOWN_MS = 30_000;\n\nfunction warnOnce(message: string): void {\n const now = Date.now();\n if (message === lastEmbeddingWarning && now - lastEmbeddingWarningAt < WARNING_COOLDOWN_MS) {\n return;\n }\n lastEmbeddingWarning = message;\n lastEmbeddingWarningAt = now;\n console.error(message);\n}\n\n/**\n * Get configured embedding mode from environment.\n * Default is 'off' to minimize resource usage.\n */\nfunction getEmbeddingMode(): EmbeddingMode {\n // Unified: env vars > config.json > 'off'\n try {\n let cfg: { getEmbeddingMode: () => EmbeddingMode };\n try {\n cfg = require('../config.ts');\n } catch {\n cfg = require('../config.js');\n }\n const { getEmbeddingMode: cfgMode } = cfg;\n return cfgMode();\n } catch {\n // Fallback if config module not available\n const env = process.env.MEMORIX_EMBEDDING?.toLowerCase()?.trim();\n if (env === 'fastembed' || env === 'transformers' || env === 'api' || env === 'auto') return env;\n return 'off';\n }\n}\n\nfunction hasAPIEmbeddingConfig(): boolean {\n try {\n let cfg: {\n getEmbeddingApiKey: () => string | undefined;\n getEmbeddingBaseUrl: () => string | undefined;\n getEmbeddingModel: () => string | undefined;\n };\n try {\n cfg = require('../config.ts');\n } catch {\n cfg = require('../config.js');\n }\n const {\n getEmbeddingApiKey,\n getEmbeddingBaseUrl,\n getEmbeddingModel,\n } = cfg;\n\n return Boolean(\n getEmbeddingApiKey?.() &&\n getEmbeddingBaseUrl?.() &&\n getEmbeddingModel?.(),\n );\n } catch {\n return Boolean(process.env.MEMORIX_EMBEDDING_API_KEY);\n }\n}\n\nfunction getProviderKind(candidate: EmbeddingProvider): ProviderKind {\n if (candidate.name.startsWith('api-')) return 'api';\n if (candidate.name.startsWith('fastembed-')) return 'fastembed';\n if (candidate.name.startsWith('transformers-')) return 'transformers';\n return 'unknown';\n}\n\nfunction isTemporaryEmbeddingFailure(error: unknown): boolean {\n if (!(error instanceof Error)) return false;\n return (\n /embedding api error \\(401\\)/i.test(error.message) ||\n /invalid_api_key/i.test(error.message) ||\n /incorrect api key/i.test(error.message) ||\n /unauthorized/i.test(error.message) ||\n /embedding api timeout/i.test(error.message) ||\n /embedding api error \\((402|429|5\\d\\d)\\)/i.test(error.message) ||\n /quota exceeded/i.test(error.message) ||\n /account balance/i.test(error.message) ||\n /fetch failed/i.test(error.message) ||\n /econnreset/i.test(error.message) ||\n /econnrefused/i.test(error.message) ||\n /temporarily unavailable/i.test(error.message)\n );\n}\n\nfunction markTemporaryFailure(reason: unknown): void {\n provider = null;\n initPromise = null;\n lastInitWasTemporaryFailure = true;\n lastFailureTimestamp = Date.now();\n const message = reason instanceof Error ? reason.message : String(reason);\n warnOnce(`[memorix] Embedding provider temporarily unavailable at runtime: ${message}`);\n}\n\nasync function createFastEmbedProvider(): Promise<EmbeddingProvider | null> {\n try {\n const { FastEmbedProvider } = await import('./fastembed-provider.js');\n return await FastEmbedProvider.create();\n } catch (e) {\n warnOnce(`[memorix] Failed to load fastembed: ${e instanceof Error ? e.message : e}`);\n warnOnce('[memorix] Install with: npm install fastembed');\n return null;\n }\n}\n\nasync function createTransformersProvider(): Promise<EmbeddingProvider | null> {\n try {\n const { TransformersProvider } = await import('./transformers-provider.js');\n return await TransformersProvider.create();\n } catch (e) {\n warnOnce(`[memorix] Failed to load transformers: ${e instanceof Error ? e.message : e}`);\n warnOnce('[memorix] Install with: npm install @huggingface/transformers');\n return null;\n }\n}\n\nasync function createAPIProvider(options?: GetEmbeddingProviderOptions): Promise<EmbeddingProvider | null> {\n try {\n const { APIEmbeddingProvider } = await import('./api-provider.js');\n return await APIEmbeddingProvider.create(options ?? {});\n } catch (e) {\n warnOnce(`[memorix] Failed to init API embedding: ${e instanceof Error ? e.message : e}`);\n return null;\n }\n}\n\nasync function createLocalFallbackProvider(): Promise<EmbeddingProvider | null> {\n const fastembed = await createFastEmbedProvider();\n if (fastembed) return fastembed;\n\n const transformers = await createTransformersProvider();\n if (transformers) return transformers;\n\n return null;\n}\n\nfunction wrapProvider(candidate: EmbeddingProvider): EmbeddingProvider {\n const kind = getProviderKind(candidate);\n\n return {\n name: candidate.name,\n dimensions: candidate.dimensions,\n async embed(text: string): Promise<number[]> {\n try {\n return await candidate.embed(text);\n } catch (error) {\n if (kind === 'api' && getEmbeddingMode() === 'auto' && isTemporaryEmbeddingFailure(error)) {\n warnOnce('[memorix] API embedding temporarily unavailable — switching to local fallback provider');\n const fallback = await createLocalFallbackProvider();\n if (fallback) {\n provider = wrapProvider(fallback);\n warnOnce(`[memorix] Embedding fallback activated: ${provider.name} (${provider.dimensions}d)`);\n return provider.embed(text);\n }\n }\n\n if (isTemporaryEmbeddingFailure(error)) {\n markTemporaryFailure(error);\n }\n throw error;\n }\n },\n async embedBatch(texts: string[]): Promise<number[][]> {\n try {\n return await candidate.embedBatch(texts);\n } catch (error) {\n if (kind === 'api' && getEmbeddingMode() === 'auto' && isTemporaryEmbeddingFailure(error)) {\n warnOnce('[memorix] API embedding temporarily unavailable — switching to local fallback provider');\n const fallback = await createLocalFallbackProvider();\n if (fallback) {\n provider = wrapProvider(fallback);\n warnOnce(`[memorix] Embedding fallback activated: ${provider.name} (${provider.dimensions}d)`);\n return provider.embedBatch(texts);\n }\n }\n\n if (isTemporaryEmbeddingFailure(error)) {\n markTemporaryFailure(error);\n }\n throw error;\n }\n },\n ...(candidate.getCachedEmbeddings\n ? {\n async getCachedEmbeddings(texts: string[]): Promise<(number[] | null)[]> {\n return candidate.getCachedEmbeddings!(texts);\n },\n }\n : {}),\n };\n}\n\n/** Minimum interval between retry attempts after a temporary failure (ms). */\nconst RETRY_COOLDOWN_MS = 30_000;\nlet lastFailureTimestamp = 0;\n\n/**\n * Get the embedding provider. Returns null if disabled or unavailable.\n * Lazy-initialized on first call. Concurrent callers share the same Promise.\n *\n * Recovery semantics:\n * - mode === 'off' → permanently null (no retry)\n * - mode === 'auto' and NO local provider installed → permanently null (no retry)\n * - provider init failed due to network/API/temp error → retry after cooldown\n *\n * Controlled by MEMORIX_EMBEDDING environment variable (default: off).\n */\nexport async function getEmbeddingProvider(\n options: GetEmbeddingProviderOptions = {},\n): Promise<EmbeddingProvider | null> {\n // If we already have a successfully initialized provider, return it immediately\n if (provider) return provider;\n\n // Startup hydration is allowed to use API vectors already described by local\n // dimension metadata, but it must never turn a missing cache into a network\n // probe. A normal retrieval/write path will initialize the provider later.\n if (options.allowNetworkProbe === false) {\n const mode = getEmbeddingMode();\n if (mode !== 'api' && !(mode === 'auto' && hasAPIEmbeddingConfig())) {\n return null;\n }\n const cached = await createAPIProvider({ allowNetworkProbe: false });\n return cached ? wrapProvider(cached) : null;\n }\n\n // If a previous attempt failed temporarily, allow retry after cooldown\n if (lastInitWasTemporaryFailure) {\n const elapsed = Date.now() - lastFailureTimestamp;\n if (elapsed < RETRY_COOLDOWN_MS) {\n // Still within cooldown — return cached null without retrying\n return null;\n }\n // Cooldown expired — clear cached promise to allow retry\n initPromise = null;\n lastInitWasTemporaryFailure = false;\n }\n\n if (initPromise) return initPromise;\n\n initPromise = (async () => {\n const mode = getEmbeddingMode();\n\n // Explicit OFF — skip all embedding initialization (permanent, no retry)\n if (mode === 'off') {\n warnOnce('[memorix] Embedding disabled (MEMORIX_EMBEDDING=off) — using BM25 fulltext search');\n return null;\n }\n\n // Explicit fastembed\n if (mode === 'fastembed') {\n const initialized = await createFastEmbedProvider();\n if (!initialized) return null;\n provider = wrapProvider(initialized);\n warnOnce(`[memorix] Embedding provider: ${provider.name} (${provider.dimensions}d)`);\n return provider;\n }\n\n // Explicit transformers\n if (mode === 'transformers') {\n const initialized = await createTransformersProvider();\n if (!initialized) return null;\n provider = wrapProvider(initialized);\n warnOnce(`[memorix] Embedding provider: ${provider.name} (${provider.dimensions}d)`);\n return provider;\n }\n\n // API mode: remote embedding via OpenAI-compatible endpoint\n if (mode === 'api') {\n const initialized = await createAPIProvider();\n if (!initialized) return null;\n provider = wrapProvider(initialized);\n warnOnce(`[memorix] Embedding provider: ${provider.name} (${provider.dimensions}d)`);\n return provider;\n }\n\n // Auto mode: try configured API first, then local fallbacks\n if (hasAPIEmbeddingConfig()) {\n const initialized = await createAPIProvider();\n if (initialized) {\n provider = wrapProvider(initialized);\n warnOnce(`[memorix] Embedding provider: ${provider.name} (${provider.dimensions}d)`);\n return provider;\n }\n }\n\n const localFallback = await createLocalFallbackProvider();\n if (localFallback) {\n provider = wrapProvider(localFallback);\n warnOnce(`[memorix] Embedding provider: ${provider.name} (${provider.dimensions}d)`);\n return provider;\n }\n\n warnOnce('[memorix] No embedding provider available — using BM25 fulltext search');\n return null;\n })();\n\n // After the init promise resolves, decide whether to cache or allow retry\n const result = await initPromise;\n if (result === null && !isEmbeddingExplicitlyDisabled()) {\n // Temporary failure — mark for retry and record timestamp\n const mode = getEmbeddingMode();\n // 'auto' mode with no local providers installed is permanent (not retryable)\n if (mode === 'api' || mode === 'fastembed' || mode === 'transformers') {\n lastInitWasTemporaryFailure = true;\n lastFailureTimestamp = Date.now();\n warnOnce(`[memorix] Embedding provider temporarily unavailable — will retry after ${RETRY_COOLDOWN_MS / 1000}s`);\n }\n // 'auto' with no providers → permanent null, no retry needed\n }\n\n return result;\n}\n\n/**\n * Check if vector search is available.\n */\nexport async function isVectorSearchAvailable(): Promise<boolean> {\n const p = await getEmbeddingProvider();\n return p !== null;\n}\n\n/**\n * Check if embedding is explicitly disabled by configuration (mode === 'off').\n *\n * When true, there is no provider to backfill from and observations can be\n * safely removed from the vector-missing queue.\n *\n * When false, the provider MAY still be null due to initialization failure,\n * API error, or missing dependencies — in those cases the observation should\n * stay in the backfill queue for later retry.\n */\nexport function isEmbeddingExplicitlyDisabled(): boolean {\n return getEmbeddingMode() === 'off';\n}\n\n/**\n * Reset provider (for testing).\n */\nexport function resetProvider(): void {\n provider = null;\n initPromise = null;\n lastInitWasTemporaryFailure = false;\n lastFailureTimestamp = 0;\n lastEmbeddingWarning = '';\n lastEmbeddingWarningAt = 0;\n}\n","/**\n * Project Affinity Scoring\n *\n * Prevents cross-project memory pollution by scoring search results\n * based on how well they match the current project context.\n *\n * Inspired by mcp-memory-service's memory-scorer.js:\n * - High affinity: content mentions project name → full score\n * - Medium affinity: related concepts but no direct mention → 0.7x\n * - Low affinity: no project reference → 0.3x (heavily penalized)\n *\n * This runs AFTER projectId filtering, as a second layer of defense\n * against memories that were stored under the correct projectId but\n * contain content about a different project (e.g., discussing Memorix\n * development while in a test project workspace).\n */\n\nexport interface AffinityContext {\n /** Current project name (e.g., \"for_memmcp_test\", \"memorix\") */\n projectName: string;\n /** Current project ID (e.g., \"local/for_memmcp_test\", \"AVIDS2/memorix\") */\n projectId: string;\n /** Optional: keywords that indicate project relevance */\n projectKeywords?: string[];\n}\n\nexport interface MemoryContent {\n title: string;\n narrative?: string;\n facts?: string[];\n concepts?: string[];\n entityName?: string;\n filesModified?: string[];\n}\n\nexport interface AffinityResult {\n /** Affinity score 0-1 (1 = high affinity, 0 = no affinity) */\n score: number;\n /** Affinity level for debugging */\n level: 'high' | 'medium' | 'low' | 'none';\n /** Reason for the score */\n reason: string;\n}\n\n/**\n * Calculate project affinity score for a memory.\n *\n * @param memory - The memory content to evaluate\n * @param context - Current project context\n * @returns AffinityResult with score, level, and reason\n */\nexport function calculateProjectAffinity(\n memory: MemoryContent,\n context: AffinityContext,\n): AffinityResult {\n const projectName = context.projectName.toLowerCase();\n const projectId = context.projectId.toLowerCase();\n \n // Extract base name from projectId (e.g., \"memorix\" from \"AVIDS2/memorix\")\n const projectBaseName = projectId.split('/').pop() ?? projectName;\n \n // Build searchable content string\n const contentParts = [\n memory.title,\n memory.narrative ?? '',\n memory.entityName ?? '',\n ...(memory.facts ?? []),\n ...(memory.concepts ?? []),\n ...(memory.filesModified ?? []),\n ];\n const content = contentParts.join(' ').toLowerCase();\n \n // Check for direct project name mention\n if (content.includes(projectName) || content.includes(projectBaseName)) {\n return { score: 1.0, level: 'high', reason: 'project_name_in_content' };\n }\n \n // Check for project keywords (if provided)\n if (context.projectKeywords && context.projectKeywords.length > 0) {\n const keywordsLower = context.projectKeywords.map(k => k.toLowerCase());\n const matchedKeywords = keywordsLower.filter(k => content.includes(k));\n if (matchedKeywords.length >= 2) {\n return { score: 0.9, level: 'high', reason: `keywords_matched: ${matchedKeywords.join(', ')}` };\n }\n if (matchedKeywords.length === 1) {\n return { score: 0.7, level: 'medium', reason: `keyword_matched: ${matchedKeywords[0]}` };\n }\n }\n \n // Check for file paths that suggest project relevance\n const files = memory.filesModified ?? [];\n if (files.some(f => f.toLowerCase().includes(projectName) || f.toLowerCase().includes(projectBaseName))) {\n return { score: 0.85, level: 'high', reason: 'project_in_file_path' };\n }\n \n // Check entity name\n if (memory.entityName) {\n const entityLower = memory.entityName.toLowerCase();\n if (entityLower.includes(projectName) || entityLower.includes(projectBaseName)) {\n return { score: 0.8, level: 'high', reason: 'project_in_entity' };\n }\n }\n \n // Check concepts for project-related terms\n const concepts = memory.concepts ?? [];\n if (concepts.some(c => c.toLowerCase().includes(projectName) || c.toLowerCase().includes(projectBaseName))) {\n return { score: 0.75, level: 'medium', reason: 'project_in_concepts' };\n }\n \n // No project reference found — this memory might be about a different project\n // Apply penalty but don't completely filter (might still be relevant)\n return { score: 0.65, level: 'low', reason: 'no_project_reference' };\n}\n\n/**\n * Apply project affinity scoring to search results.\n *\n * @param results - Search results with scores\n * @param memories - Full memory content for each result (keyed by ID)\n * @param context - Current project context\n * @param options - Scoring options\n * @returns Results with adjusted scores, sorted by affinity-weighted score\n */\nexport function applyProjectAffinity<T extends { id: number; score: number }>(\n results: T[],\n memories: Map<number, MemoryContent>,\n context: AffinityContext,\n options: {\n /** Minimum affinity score to include (default: 0, include all) */\n minAffinity?: number;\n /** Whether to filter out low-affinity results entirely (default: false) */\n filterLowAffinity?: boolean;\n } = {},\n): T[] {\n const { minAffinity = 0, filterLowAffinity = false } = options;\n \n // Calculate affinity for each result\n const withAffinity = results.map(result => {\n const memory = memories.get(result.id);\n if (!memory) {\n // No memory content available — assume medium affinity\n return { ...result, affinity: 0.5, affinityLevel: 'medium' as const };\n }\n \n const { score: affinityScore, level } = calculateProjectAffinity(memory, context);\n return {\n ...result,\n score: result.score * affinityScore, // Apply affinity as multiplier\n affinity: affinityScore,\n affinityLevel: level,\n };\n });\n \n // Filter by minimum affinity if requested\n let filtered = withAffinity;\n if (filterLowAffinity) {\n filtered = withAffinity.filter(r => r.affinity >= 0.5);\n } else if (minAffinity > 0) {\n filtered = withAffinity.filter(r => r.affinity >= minAffinity);\n }\n \n // Re-sort by affinity-weighted score\n filtered.sort((a, b) => b.score - a.score);\n \n // Return without the extra affinity fields (keep original shape)\n return filtered.map(({ affinity: _, affinityLevel: __, ...rest }) => rest as T);\n}\n\n/**\n * Extract project keywords from project name and common patterns.\n * Used to improve affinity detection for projects with distinctive names.\n */\nexport function extractProjectKeywords(projectName: string, projectId: string): string[] {\n const keywords: string[] = [projectName];\n \n // Add base name from projectId\n const baseName = projectId.split('/').pop();\n if (baseName && baseName !== projectName) {\n keywords.push(baseName);\n }\n \n // Add common variations\n const variations = [\n projectName.replace(/-/g, '_'),\n projectName.replace(/_/g, '-'),\n projectName.replace(/[_-]/g, ''),\n ];\n for (const v of variations) {\n if (v !== projectName && !keywords.includes(v)) {\n keywords.push(v);\n }\n }\n \n return keywords.filter(k => k.length > 2);\n}\n","/**\n * Intent-Aware Recall — Query Intent Detection\n *\n * Detects the underlying intent of a search query (why/when/how/what)\n * and returns type-specific boosting factors to improve recall precision.\n *\n * Inspired by MemCP's intent routing architecture.\n * Uses fast keyword/pattern matching (no LLM needed).\n */\n\nimport type { ObservationType } from '../types.js';\n\n// ─── Types ───\n\nexport type QueryIntent = 'why' | 'when' | 'how' | 'what_changed' | 'problem' | 'general';\n\nexport interface IntentResult {\n /** Detected intent category */\n intent: QueryIntent;\n /** Confidence score 0-1 */\n confidence: number;\n /** Observation type → boost multiplier (applied to search scores) */\n typeBoosts: Partial<Record<ObservationType, number>>;\n /** Field weight overrides for Orama search (optional) */\n fieldBoosts?: Record<string, number>;\n /** Whether to prefer chronological ordering over relevance */\n preferChronological: boolean;\n /** Source → boost multiplier for source-aware retrieval */\n sourceBoosts?: Partial<Record<'agent' | 'git' | 'manual', number>>;\n}\n\n// ─── Intent Patterns ───\n\ninterface IntentPattern {\n intent: QueryIntent;\n patterns: RegExp[];\n /** Higher weight = stronger match when multiple intents match */\n weight: number;\n}\n\nconst INTENT_PATTERNS: IntentPattern[] = [\n {\n intent: 'why',\n patterns: [\n /\\bwhy\\b/i,\n /\\breason(?:s|ing)?\\b/i,\n /\\brationale\\b/i,\n /\\bmotivat(?:ion|ed)\\b/i,\n /\\bjustif(?:y|ication)\\b/i,\n /\\bchose|chosen|picked\\b/i,\n /\\bdecid(?:e[ds]?|ing)\\b/i,\n /\\btrade-?off\\b/i,\n /为什么/,\n /原因/,\n /理由/,\n /为何/,\n ],\n weight: 1.0,\n },\n {\n intent: 'when',\n patterns: [\n /\\bwhen\\b/i,\n /\\btimeline\\b/i,\n /\\bhistory\\b/i,\n /\\blast\\s+(week|month|time|session)\\b/i,\n /\\brecent(?:ly)?\\b/i,\n /\\byesterday\\b/i,\n /\\btoday\\b/i,\n /\\bchronolog/i,\n /什么时候/,\n /何时/,\n /最近/,\n /上次/,\n ],\n weight: 0.9,\n },\n {\n intent: 'how',\n patterns: [\n /\\bhow\\s+(does|do|to|is|can|did|should|would)\\b/i,\n /\\barchitecture\\b/i,\n /\\bmechanism\\b/i,\n /\\bimplement(?:ation|ed|ing)?\\b/i,\n /\\bwork(?:s|ing|ed)?\\b/i,\n /\\bexplain\\b/i,\n /\\bunderstand\\b/i,\n /怎么/,\n /如何/,\n /机制/,\n /原理/,\n /架构/,\n ],\n weight: 0.85,\n },\n {\n intent: 'what_changed',\n patterns: [\n /\\bwhat\\s+changed\\b/i,\n /\\bwhat\\s+was\\s+(modified|updated|changed)\\b/i,\n /\\bdiff(?:erence)?\\b/i,\n /\\bchangelog\\b/i,\n /\\bmodifi(?:ed|cation)\\b/i,\n /\\bupdat(?:e[ds]?|ing)\\b/i,\n /\\brefactor(?:ed|ing)?\\b/i,\n /改了/,\n /修改/,\n /变更/,\n /变化/,\n ],\n weight: 0.8,\n },\n {\n intent: 'problem',\n patterns: [\n /\\bbug(?:s|gy)?\\b/i,\n /\\berror(?:s)?\\b/i,\n /\\bfix(?:e[ds]|ing)?\\b/i,\n /\\bissue(?:s)?\\b/i,\n /\\bproblem(?:s)?\\b/i,\n /\\bcrash(?:e[ds]|ing)?\\b/i,\n /\\bfail(?:e[ds]|ure|ing)?\\b/i,\n /\\bbroken\\b/i,\n /\\bgotcha\\b/i,\n /\\bpitfall\\b/i,\n /\\bworkaround\\b/i,\n /\\btroubleshoot/i,\n /\\bdebug(?:ging)?\\b/i,\n /报错/,\n /问题/,\n /修复/,\n /故障/,\n /异常/,\n ],\n weight: 0.9,\n },\n];\n\n// ─── Type Boost Maps ───\n\nconst INTENT_TYPE_BOOSTS: Record<QueryIntent, Partial<Record<ObservationType, number>>> = {\n why: {\n 'decision': 3.0,\n 'why-it-exists': 3.0,\n 'trade-off': 2.5,\n 'how-it-works': 1.2,\n },\n when: {\n // Temporal queries don't strongly prefer any type — they prefer recency\n 'what-changed': 1.5,\n 'session-request': 1.3,\n },\n how: {\n 'how-it-works': 3.0,\n 'discovery': 2.0,\n 'decision': 1.3,\n },\n what_changed: {\n 'what-changed': 3.0,\n 'discovery': 1.5,\n 'session-request': 1.2,\n },\n problem: {\n 'problem-solution': 3.0,\n 'gotcha': 2.5,\n 'discovery': 1.3,\n },\n general: {\n // No special boosting\n },\n};\n\n// ─── Source Boost Maps ───\n// Maps intent to preferred memory sources for source-aware retrieval.\n// git source = ground truth (commits), agent source = reasoning/decisions.\n\nconst INTENT_SOURCE_BOOSTS: Partial<Record<QueryIntent, Partial<Record<'agent' | 'git' | 'manual', number>>>> = {\n what_changed: {\n git: 2.0, // \"what changed\" → prefer commit-derived ground truth\n agent: 0.8,\n },\n when: {\n git: 1.8, // Temporal queries → git has precise timestamps\n agent: 1.0,\n },\n why: {\n agent: 2.0, // \"why\" → prefer reasoning/decision memories\n git: 0.7, // commits rarely explain WHY\n },\n how: {\n agent: 1.5, // \"how\" → prefer explanations\n git: 1.0,\n },\n problem: {\n git: 1.5, // Bug fixes often in commit history\n agent: 1.5, // But also in problem-solution memories\n },\n};\n\nconst INTENT_FIELD_BOOSTS: Partial<Record<QueryIntent, Record<string, number>>> = {\n why: {\n title: 2,\n entityName: 1.5,\n narrative: 2.5, // WHY queries need narrative context\n facts: 1.5,\n concepts: 1,\n filesModified: 0.3,\n },\n problem: {\n title: 3,\n entityName: 2,\n narrative: 2,\n facts: 2, // Bug details often in facts\n concepts: 1,\n filesModified: 1.5, // File paths help find the right bug fix\n },\n};\n\n// ─── Detection ───\n\n/**\n * Detect the intent of a search query.\n *\n * Returns the best matching intent with confidence score and\n * type-specific boosting factors to apply during search.\n */\nexport function detectQueryIntent(query: string): IntentResult {\n if (!query || query.length < 2) {\n return {\n intent: 'general',\n confidence: 0,\n typeBoosts: {},\n preferChronological: false,\n };\n }\n\n let bestIntent: QueryIntent = 'general';\n let bestScore = 0;\n let totalMatches = 0;\n\n for (const { intent, patterns, weight } of INTENT_PATTERNS) {\n let matchCount = 0;\n for (const pattern of patterns) {\n if (pattern.test(query)) matchCount++;\n }\n if (matchCount > 0) {\n const score = matchCount * weight;\n totalMatches += matchCount;\n if (score > bestScore) {\n bestScore = score;\n bestIntent = intent;\n }\n }\n }\n\n // Confidence: how strongly did we match vs. random noise\n const confidence = totalMatches === 0\n ? 0\n : Math.min(1, bestScore / 2); // 2+ pattern matches → high confidence\n\n return {\n intent: bestIntent,\n confidence,\n typeBoosts: INTENT_TYPE_BOOSTS[bestIntent],\n fieldBoosts: INTENT_FIELD_BOOSTS[bestIntent],\n sourceBoosts: INTENT_SOURCE_BOOSTS[bestIntent],\n preferChronological: bestIntent === 'when',\n };\n}\n\n/**\n * Apply intent-based type boosting to a search result's score.\n *\n * @param score Original search score\n * @param type Observation type of the result\n * @param intentResult Detected intent from detectQueryIntent()\n * @returns Boosted score\n */\nexport function applyIntentBoost(\n score: number,\n type: string,\n intentResult: IntentResult,\n): number {\n if (intentResult.confidence < 0.3) return score; // Low confidence → no boost\n const boost = intentResult.typeBoosts[type as ObservationType] ?? 1.0;\n // Scale boost by confidence: full boost at confidence=1, partial at lower\n const effectiveBoost = 1 + (boost - 1) * intentResult.confidence;\n return score * effectiveBoost;\n}\n","import { callLLM, initLLM, isLLMEnabled } from '../llm/provider.js';\n\nconst CJK_PATTERN = /[\\u4e00-\\u9fff\\u3040-\\u309f\\u30a0-\\u30ff\\uac00-\\ud7af]/g;\nconst COMMAND_LIKE_QUERY = /\\b(git|npm|npx|pnpm|yarn|node|bash|powershell|curl|memorix)\\b/i;\n\nconst QUERY_EXPANSION_PROMPT = `You rewrite coding-memory search queries for retrieval.\n\nRules:\n- Input may be Chinese, Japanese, or Korean\n- Output one short English search phrase only\n- Keep the technical meaning\n- Prefer wording that would match engineering notes or memory titles\n- No bullets, no JSON, no explanation, no quotes\n- 4 to 12 words is ideal`;\n\nfunction isCjkHeavy(query: string): boolean {\n const cjkCount = (query.match(CJK_PATTERN) || []).length;\n return query.length > 0 && cjkCount / query.length > 0.3;\n}\n\nfunction normalizeExpansion(text: string): string {\n return text\n .trim()\n .replace(/^[-*]\\s*/, '')\n .replace(/^[\"'`]+|[\"'`]+$/g, '')\n .split(/\\r?\\n/)[0]\n .trim();\n}\n\nexport async function maybeExpandSearchQuery(query: string): Promise<string> {\n if (!query || !isCjkHeavy(query) || COMMAND_LIKE_QUERY.test(query)) {\n return query;\n }\n\n if (!isLLMEnabled()) {\n initLLM();\n }\n\n if (!isLLMEnabled()) {\n return query;\n }\n\n try {\n const response = await callLLM(QUERY_EXPANSION_PROMPT, query);\n const expanded = normalizeExpansion(response.content);\n if (!expanded) return query;\n if (expanded.toLowerCase() === query.toLowerCase()) return query;\n return `${query} ${expanded}`.slice(0, 500);\n } catch {\n return query;\n }\n}\n","/**\n * Project Alias Registry\n *\n * Solves the \"project identity split\" problem: the same project gets different\n * projectIds depending on which IDE detects it (git remote vs local path vs placeholder).\n *\n * Maintains a registry file (~/.memorix/data/.project-aliases.json) that groups\n * all known IDs for the same physical project under one canonical ID.\n *\n * Canonical ID priority: git remote > local > placeholder\n *\n * Matching heuristics (any match → same project):\n * 1. Same normalized rootPath\n * 2. Same git remote URL\n */\n\nimport { promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport os from 'node:os';\nimport type { ProjectInfo } from '../types.js';\n\nconst DEFAULT_DATA_DIR = process.env.MEMORIX_DATA_DIR || path.join(os.homedir(), '.memorix', 'data');\nconst ALIAS_FILE = '.project-aliases.json';\n\n/** A group of project IDs that all refer to the same physical project */\nexport interface AliasGroup {\n /** The best-known ID for this project (git remote > local > placeholder) */\n canonical: string;\n /** All known IDs including canonical */\n aliases: string[];\n /** All known root paths (normalized) for this project */\n rootPaths: string[];\n /** Git remote URL if known */\n gitRemote?: string;\n}\n\ninterface AliasRegistry {\n version: 1;\n groups: AliasGroup[];\n}\n\n/** In-memory cache of the registry */\nlet registryCache: AliasRegistry | null = null;\nlet registryDir: string | null = null;\n\n/**\n * Normalize a root path for comparison.\n * - Forward slashes\n * - Lowercase on Windows\n * - No trailing slash\n */\nfunction normalizePath(p: string): string {\n let normalized = p.replace(/\\\\/g, '/').replace(/\\/+$/, '');\n if (process.platform === 'win32') {\n normalized = normalized.toLowerCase();\n }\n return normalized;\n}\n\n/**\n * Determine the priority of a project ID prefix.\n * Higher = better canonical candidate.\n */\nfunction idPriority(id: string): number {\n if (id.startsWith('untracked/')) return 0;\n if (id.startsWith('local/')) return 1;\n // Git remote-based IDs (e.g., \"user/repo\") have no prefix → highest priority\n return 2;\n}\n\n/**\n * Get the alias registry file path.\n */\nfunction getRegistryPath(baseDir?: string): string {\n return path.join(baseDir ?? registryDir ?? DEFAULT_DATA_DIR, ALIAS_FILE);\n}\n\n/**\n * Load the alias registry from disk.\n */\nasync function loadRegistry(baseDir?: string): Promise<AliasRegistry> {\n if (registryCache) return registryCache;\n try {\n const data = await fs.readFile(getRegistryPath(baseDir), 'utf-8');\n const parsed = JSON.parse(data);\n if (parsed.version === 1 && Array.isArray(parsed.groups)) {\n registryCache = parsed;\n return registryCache!;\n }\n } catch { /* file doesn't exist yet */ }\n registryCache = { version: 1, groups: [] };\n return registryCache;\n}\n\n/**\n * Save the alias registry to disk.\n */\nasync function saveRegistry(baseDir?: string): Promise<void> {\n if (!registryCache) return;\n const filePath = getRegistryPath(baseDir);\n await fs.mkdir(path.dirname(filePath), { recursive: true });\n await fs.writeFile(filePath, JSON.stringify(registryCache, null, 2), 'utf-8');\n}\n\n/**\n * Find an existing alias group that matches the given project info.\n *\n * Match criteria (any one is sufficient):\n * 1. Group already contains this exact ID\n * 2. Group has a matching normalized rootPath\n * 3. Group has a matching gitRemote\n */\nfunction findMatchingGroup(\n registry: AliasRegistry,\n projectInfo: ProjectInfo,\n): AliasGroup | null {\n const normalizedRoot = normalizePath(projectInfo.rootPath);\n\n for (const group of registry.groups) {\n // Match by ID\n if (group.aliases.includes(projectInfo.id)) return group;\n\n // Match by rootPath\n if (group.rootPaths.some((rp) => rp === normalizedRoot)) return group;\n\n // Match by git remote\n if (projectInfo.gitRemote && group.gitRemote && group.gitRemote === projectInfo.gitRemote) {\n return group;\n }\n }\n\n return null;\n}\n\n/**\n * Select the best canonical ID from a list of aliases.\n * Priority: git remote-based > local > placeholder\n */\nfunction selectCanonical(aliases: string[]): string {\n return [...aliases].sort((a, b) => idPriority(b) - idPriority(a))[0];\n}\n\n/**\n * Register a detected project in the alias registry.\n *\n * If the project matches an existing group, merges the new ID/rootPath into it.\n * If not, creates a new group.\n *\n * Returns the **canonical** project ID that should be used for storage and search.\n *\n * @param projectInfo - The detected project info from detectProject()\n * @param baseDir - Override data directory (for testing)\n * @returns The canonical project ID\n */\nexport async function registerAlias(projectInfo: ProjectInfo, baseDir?: string): Promise<string> {\n const registry = await loadRegistry(baseDir);\n const normalizedRoot = normalizePath(projectInfo.rootPath);\n\n const existingGroup = findMatchingGroup(registry, projectInfo);\n\n if (existingGroup) {\n // Merge into existing group\n let changed = false;\n\n if (!existingGroup.aliases.includes(projectInfo.id)) {\n existingGroup.aliases.push(projectInfo.id);\n changed = true;\n }\n\n if (!existingGroup.rootPaths.includes(normalizedRoot)) {\n existingGroup.rootPaths.push(normalizedRoot);\n changed = true;\n }\n\n if (projectInfo.gitRemote && !existingGroup.gitRemote) {\n existingGroup.gitRemote = projectInfo.gitRemote;\n changed = true;\n }\n\n // Re-evaluate canonical (maybe we just learned a git remote ID)\n const newCanonical = selectCanonical(existingGroup.aliases);\n if (newCanonical !== existingGroup.canonical) {\n existingGroup.canonical = newCanonical;\n changed = true;\n }\n\n if (changed) {\n await saveRegistry(baseDir);\n }\n\n return existingGroup.canonical;\n }\n\n // Create new group\n const newGroup: AliasGroup = {\n canonical: projectInfo.id,\n aliases: [projectInfo.id],\n rootPaths: [normalizedRoot],\n ...(projectInfo.gitRemote ? { gitRemote: projectInfo.gitRemote } : {}),\n };\n registry.groups.push(newGroup);\n await saveRegistry(baseDir);\n\n return newGroup.canonical;\n}\n\n/**\n * Resolve all known aliases for a project ID.\n *\n * Used in search to expand the projectId filter so that observations stored\n * under any alias are found regardless of which IDE stored them.\n *\n * @returns Array of all known IDs for the same project, or [projectId] if no aliases found.\n */\nexport async function resolveAliases(projectId: string, baseDir?: string): Promise<string[]> {\n const registry = await loadRegistry(baseDir);\n\n for (const group of registry.groups) {\n if (group.aliases.includes(projectId) || group.canonical === projectId) {\n return [...group.aliases];\n }\n }\n\n return [projectId];\n}\n\n/**\n * Get the canonical ID for a project ID.\n *\n * @returns The canonical ID, or the input ID if no alias group found.\n */\nexport async function getCanonicalId(projectId: string, baseDir?: string): Promise<string> {\n const registry = await loadRegistry(baseDir);\n\n for (const group of registry.groups) {\n if (group.aliases.includes(projectId) || group.canonical === projectId) {\n return group.canonical;\n }\n }\n\n return projectId;\n}\n\n/**\n * Get all alias groups (for dashboard/debug).\n */\nexport async function getAllAliasGroups(baseDir?: string): Promise<AliasGroup[]> {\n const registry = await loadRegistry(baseDir);\n return registry.groups;\n}\n\n/**\n * Auto-merge obvious alias groups by scanning existing observation projectIds.\n *\n * Detects project IDs that share the same base name but have different prefixes:\n * - placeholder/foo + local/foo → merge under the higher-priority one\n * - AVIDS2/test-repo + local/test-repo → merge under AVIDS2/test-repo\n *\n * Called once during server startup after observations are loaded.\n *\n * @param observedIds - All unique projectIds found in observations data\n * @returns Number of new merges performed\n */\nexport async function autoMergeByBaseName(\n observedIds: string[],\n baseDir?: string,\n): Promise<number> {\n if (observedIds.length <= 1) return 0;\n\n const registry = await loadRegistry(baseDir);\n\n // Group observed IDs by their base name (the part after the last /)\n const byBaseName = new Map<string, string[]>();\n for (const id of observedIds) {\n const baseName = id.split('/').pop() ?? id;\n if (!byBaseName.has(baseName)) byBaseName.set(baseName, []);\n byBaseName.get(baseName)!.push(id);\n }\n\n let mergeCount = 0;\n\n for (const [_baseName, ids] of byBaseName) {\n if (ids.length <= 1) continue;\n\n // Check if these IDs are already in the same alias group\n const existingGroups = new Set<number>();\n const ungroupedIds: string[] = [];\n\n for (const id of ids) {\n const groupIdx = registry.groups.findIndex(\n g => g.aliases.includes(id) || g.canonical === id,\n );\n if (groupIdx >= 0) {\n existingGroups.add(groupIdx);\n } else {\n ungroupedIds.push(id);\n }\n }\n\n // If all IDs are already in the same group, skip\n if (existingGroups.size <= 1 && ungroupedIds.length === 0) continue;\n\n // Merge: pick the best canonical from all IDs\n const allIdsInGroup = [...ids];\n const canonical = selectCanonical(allIdsInGroup);\n\n if (existingGroups.size > 0) {\n // Merge into the first existing group\n const primaryIdx = [...existingGroups][0];\n const primaryGroup = registry.groups[primaryIdx];\n\n // Add all IDs to primary group\n for (const id of allIdsInGroup) {\n if (!primaryGroup.aliases.includes(id)) {\n primaryGroup.aliases.push(id);\n }\n }\n\n // Absorb other existing groups into primary\n const otherIdxs = [...existingGroups].slice(1).sort((a, b) => b - a);\n for (const idx of otherIdxs) {\n const other = registry.groups[idx];\n for (const alias of other.aliases) {\n if (!primaryGroup.aliases.includes(alias)) {\n primaryGroup.aliases.push(alias);\n }\n }\n for (const rp of other.rootPaths) {\n if (!primaryGroup.rootPaths.includes(rp)) {\n primaryGroup.rootPaths.push(rp);\n }\n }\n if (other.gitRemote && !primaryGroup.gitRemote) {\n primaryGroup.gitRemote = other.gitRemote;\n }\n registry.groups.splice(idx, 1);\n }\n\n // Re-evaluate canonical\n primaryGroup.canonical = selectCanonical(primaryGroup.aliases);\n mergeCount++;\n } else {\n // All ungrouped — create new group\n registry.groups.push({\n canonical,\n aliases: allIdsInGroup,\n rootPaths: [],\n });\n mergeCount++;\n }\n }\n\n if (mergeCount > 0) {\n await saveRegistry(baseDir);\n }\n\n return mergeCount;\n}\n\n/**\n * Initialize the alias registry with a data directory.\n * Should be called once during server startup.\n */\nexport function initAliasRegistry(dataDir: string): void {\n registryDir = dataDir;\n registryCache = null; // Force reload from new location\n}\n\n/**\n * Reset the in-memory cache (for testing).\n */\nexport function resetAliasCache(): void {\n registryCache = null;\n}\n","/**\n * LLM Quality Enhancements\n *\n * Premium memory quality features powered by LLM:\n * 1. Narrative Compression — compress verbose narratives into concise core knowledge\n * 2. Search Reranking — rerank search results by relevance to current task context\n *\n * Both features gracefully degrade: when LLM is not configured, they return\n * the original data unchanged.\n *\n * Performance targets:\n * - Compression: ~60% token reduction per stored memory\n * - Reranking: ~40% improvement in Top-5 precision\n */\n\nimport { callLLM, isLLMEnabled } from './provider.js';\n\n// ── Narrative Compression ────────────────────────────────────────\n\nconst COMPRESS_PROMPT = `You are a memory compression engine for a coding assistant.\n\nCompress the given narrative while preserving ALL technical facts and reasoning.\n\nRules:\n- Remove: filler words, debugging journey, repeated info already in facts\n- Keep: specific values, file paths, error messages, version numbers, config keys, causal relationships, design reasoning\n- Merge related points into dense sentences\n- If facts are provided separately, do NOT repeat them in the compressed narrative\n- Output the compressed text ONLY, no explanation or wrapper\n\nExamples:\nInput: \"我在调试过程中发现JWT token的refresh机制存在问题,具体来说是因为服务端没有实现自动续签,导致用户在24小时后会遇到静默的认证失败,之前我一直以为是网络问题但后来排查发现是token过期了\"\nOutput: \"JWT refresh无自动续签→24h后静默认证失败(非网络问题)\"\n\nInput: \"Final deployment model for shadcn-blog is stable: GitHub Actions build locally, SCP artifacts to VPS, systemd manages the process. Docker was considered but rejected due to complexity overhead for a simple blog. The whole pipeline takes about 2 minutes from push to live.\"\nOutput: \"shadcn-blog部署: GH Actions构建→SCP到VPS→systemd管理, 弃Docker(复杂度过高), push到上线~2min\"`;\n\n/** Gentler prompt for high-value types where reasoning context matters */\nconst COMPRESS_PROMPT_GENTLE = `You are a memory compression engine for a coding assistant.\n\nLightly compress the given narrative — preserve reasoning, trade-offs, and \"why\" context.\n\nRules:\n- Only remove: obvious filler, debugging detours, info already in the separate facts list\n- PRESERVE: design reasoning, rejected alternatives, trade-off analysis, causal chains\n- Aim for ~70-80% of original length, NOT aggressive compression\n- If facts are provided separately, do NOT repeat them in the compressed narrative\n- Output the compressed text ONLY, no explanation or wrapper`;\n\n/**\n * Compress a narrative to its essential core using LLM.\n *\n * Returns the original narrative if:\n * - LLM is not enabled\n * - Narrative is already short (≤80 chars)\n * - Narrative is already concise (commands, file paths, git operations)\n * - LLM call fails\n */\nexport async function compressNarrative(\n narrative: string,\n facts?: string[],\n type?: string,\n): Promise<{ compressed: string; saved: number; usedLLM: boolean }> {\n const originalTokens = estimateTokens(narrative);\n\n // Skip compression for short narratives (≤150 chars is already concise)\n if (!isLLMEnabled() || narrative.length <= 150) {\n return { compressed: narrative, saved: 0, usedLLM: false };\n }\n\n // Skip compression for already-concise content that LLM can't meaningfully compress\n if (shouldSkipCompression(narrative, type)) {\n return { compressed: narrative, saved: 0, usedLLM: false };\n }\n\n try {\n const factsContext = facts && facts.length > 0\n ? `\\n\\nSeparate facts (already stored, don't repeat): ${facts.join('; ')}`\n : '';\n\n // Use gentler compression for high-value types where reasoning matters\n const HIGH_VALUE_TYPES = new Set(['decision', 'trade-off', 'why-it-exists', 'how-it-works']);\n const prompt = (type && HIGH_VALUE_TYPES.has(type)) ? COMPRESS_PROMPT_GENTLE : COMPRESS_PROMPT;\n const response = await callLLM(prompt, narrative + factsContext);\n const compressed = response.content.trim();\n\n // Sanity check: compressed should be shorter and non-empty\n if (!compressed || compressed.length >= narrative.length) {\n return { compressed: narrative, saved: 0, usedLLM: true };\n }\n\n const compressedTokens = estimateTokens(compressed);\n return {\n compressed,\n saved: originalTokens - compressedTokens,\n usedLLM: true,\n };\n } catch {\n return { compressed: narrative, saved: 0, usedLLM: false };\n }\n}\n\n// ── Search Reranking ─────────────────────────────────────────────\n\n/** Minimal search result for reranking */\nexport interface RerankCandidate {\n id: string;\n title: string;\n type: string;\n score: number;\n narrative?: string;\n}\n\nconst RERANK_PROMPT = `You are a memory relevance ranker for a coding assistant.\n\nGiven a QUERY (what the user/agent is looking for) and a list of CANDIDATE memories,\nrerank them by relevance to the query.\n\nRules:\n- Consider semantic relevance, not just keyword overlap\n- Gotchas and decisions related to the query topic should rank higher\n- Recent problem-solutions for the same component should rank higher\n- 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\n- Generic or loosely related memories should rank lower\n- Output ONLY a JSON array of IDs in order of relevance (most relevant first)\n- Include ALL candidate IDs, just reorder them\n\nExample output: [\"r1\", \"r3\", \"r2\"]`;\n\n/**\n * Rerank search results using LLM contextual understanding.\n *\n * Takes Orama's initial ranking and improves it by considering\n * semantic relevance to the current query/task context.\n *\n * Returns original order if LLM is not enabled or call fails.\n */\nexport async function rerankResults(\n query: string,\n candidates: RerankCandidate[],\n): Promise<{ reranked: RerankCandidate[]; usedLLM: boolean }> {\n // Skip if too few results or LLM not available\n if (!isLLMEnabled() || candidates.length <= 2) {\n return { reranked: candidates, usedLLM: false };\n }\n\n // Only rerank top-N to save LLM tokens (reranking 20+ is wasteful)\n const MAX_RERANK = 10;\n const toRerank = candidates.slice(0, MAX_RERANK);\n const rest = candidates.slice(MAX_RERANK);\n\n try {\n const candidateList = toRerank.map(c =>\n `[ID: ${c.id}] (${c.type}) ${c.title}${c.narrative ? ` — ${c.narrative.substring(0, 100)}` : ''}`,\n ).join('\\n');\n\n const response = await callLLM(RERANK_PROMPT, `QUERY: ${query}\\n\\nCANDIDATES:\\n${candidateList}`);\n\n // Parse response — handle markdown code blocks\n let content = response.content.trim();\n if (content.startsWith('```')) {\n content = content.replace(/^```(?:json)?\\s*/, '').replace(/\\s*```$/, '');\n }\n\n const rankedIds = JSON.parse(content) as string[];\n\n // Validate: must be an array of IDs matching our candidates\n if (!Array.isArray(rankedIds) || rankedIds.length === 0) {\n return { reranked: candidates, usedLLM: true };\n }\n\n // Build reranked list preserving original scores for display\n const idMap = new Map(toRerank.map(c => [c.id, c]));\n const reranked: RerankCandidate[] = [];\n const seen = new Set<string>();\n\n // Add IDs in LLM-reranked order\n for (const id of rankedIds) {\n const candidate = idMap.get(id);\n if (candidate && !seen.has(id)) {\n reranked.push(candidate);\n seen.add(id);\n }\n }\n\n // Add any candidates the LLM missed (safety: never lose results)\n for (const c of toRerank) {\n if (!seen.has(c.id)) {\n reranked.push(c);\n }\n }\n\n // Append non-reranked tail\n reranked.push(...rest);\n\n return { reranked, usedLLM: true };\n } catch {\n return { reranked: candidates, usedLLM: false };\n }\n}\n\n// ── Smart Compression Filtering ──────────────────────────────────\n\n/** Patterns that indicate already-concise content not worth compressing */\nconst SKIP_PATTERNS = [\n /^(?:Command|Run|Execute):\\s/i, // Shell commands\n /^(?:File|Edit|Changed):\\s/i, // File change descriptions\n /^git\\s+(?:add|commit|push|pull|log)/i, // Git operations\n /^(?:npm|npx|pnpm|yarn|bun)\\s/i, // Package manager commands\n /^(?:Remove-Item|New-Item|Set-Content)/i, // PowerShell commands\n /^[A-Za-z]:\\\\[\\w\\\\]/, // Windows file paths\n /^\\/(?:usr|home|var|etc|opt)\\//, // Unix file paths\n];\n\n/** Low-value observation types that hooks auto-capture (usually already terse) */\nconst LOW_COMPRESSION_TYPES = new Set(['what-changed', 'discovery', 'session-request']);\n\n/**\n * Determine if a narrative should skip LLM compression.\n *\n * Skip when:\n * - Content starts with command/path patterns (already structured, not prose)\n * - Type is hooks-auto-captured AND narrative is relatively short\n * - Narrative is mostly code/paths (high ratio of special chars)\n */\nfunction shouldSkipCompression(narrative: string, type?: string): boolean {\n // Skip command/path-like content\n const firstLine = narrative.split('\\n')[0];\n if (SKIP_PATTERNS.some(p => p.test(firstLine))) return true;\n\n // Skip short auto-captured observations (hooks produce terse what-changed)\n if (type && LOW_COMPRESSION_TYPES.has(type) && narrative.length < 200) return true;\n\n // Skip if narrative is mostly code/structured data (high special char ratio)\n const specialChars = (narrative.match(/[{}()\\[\\]<>:;=|\\\\\\/\\-_\\.@#$%^&*+~`\"']/g) || []).length;\n if (specialChars / narrative.length > 0.35) return true;\n\n return false;\n}\n\n// ── Utility ──────────────────────────────────────────────────────\n\n/** Rough token estimate: ~4 chars per token for English, ~2 for CJK */\nfunction estimateTokens(text: string): number {\n const cjkChars = (text.match(/[\\u4e00-\\u9fff\\u3040-\\u309f\\u30a0-\\u30ff\\uac00-\\ud7af]/g) || []).length;\n const otherChars = text.length - cjkChars;\n return Math.ceil(cjkChars / 1.5 + otherChars / 4);\n}\n","/**\n * Unified Freshness Gate (Phase 3a)\n *\n * Replaces withFreshObservations() as the public API for all retrieval\n * surfaces. Checks both observation and mini-skill generation counters\n * to ensure the Orama index is fully up-to-date before any read.\n *\n * withFreshObservations() remains in observations.ts as @internal —\n * only called by this module and legacy test code.\n */\n\nimport { ensureFreshObservations } from './observations.js';\nimport { getMiniSkillStore, isMiniSkillStoreInitialized } from '../store/mini-skill-store.js';\nimport { miniSkillToDocument } from '../skills/mini-skills.js';\nimport { insert, remove } from '@orama/orama';\n\n// ── Mini-skill index state ──────────────────────────────────────\n\nlet lastMiniSkillGeneration = -1;\n\n/**\n * Check if mini-skills have changed since our last index sync.\n * If stale, reindex all mini-skills in Orama.\n *\n * Returns true if the index was refreshed.\n */\nexport async function ensureFreshMiniSkills(): Promise<boolean> {\n // Skip silently when the store has not been initialized yet —\n // observation-only paths never call initMiniSkillStore().\n if (!isMiniSkillStoreInitialized()) return false;\n\n try {\n const store = getMiniSkillStore();\n const wasStale = await store.ensureFresh();\n const currentGen = store.getGeneration();\n\n if (wasStale || currentGen !== lastMiniSkillGeneration) {\n await reindexMiniSkills();\n lastMiniSkillGeneration = currentGen;\n return true;\n }\n } catch (err) {\n // Best-effort — don't crash the read path, but log for diagnostics\n console.warn(`[memorix] ensureFreshMiniSkills failed: ${err instanceof Error ? err.message : err}`);\n }\n return false;\n}\n\n// Deterministic tracking of indexed mini-skill doc IDs — avoids empty-term search\nconst indexedSkillDocIds = new Set<string>();\n\n/**\n * Reindex all mini-skills into the Orama database.\n * Uses deterministic doc ID tracking instead of empty-term search to ensure\n * all stale documents are removed reliably.\n */\nexport async function reindexMiniSkills(): Promise<number> {\n // Lazy import to avoid circular dependency\n const { getDb } = await import('../store/orama-store.js');\n const database = await getDb();\n\n // Remove previously tracked mini-skill documents by their known IDs\n for (const docId of indexedSkillDocIds) {\n try { await remove(database, docId); } catch { /* already removed or never existed */ }\n }\n indexedSkillDocIds.clear();\n\n // Load and index all current mini-skills\n const store = getMiniSkillStore();\n const skills = await store.loadAll();\n let indexed = 0;\n\n for (const skill of skills) {\n try {\n const doc = miniSkillToDocument(skill);\n await insert(database, doc);\n indexedSkillDocIds.add(doc.id);\n indexed++;\n } catch (err) {\n console.error(`[memorix] Failed to index mini-skill ${skill.id}: ${err instanceof Error ? err.message : err}`);\n }\n }\n\n return indexed;\n}\n\n// ── Unified gate ────────────────────────────────────────────────\n\n/**\n * Ensure both observations and mini-skills are fresh in the Orama index.\n * Returns true if any data source was refreshed.\n */\nexport async function ensureFreshIndex(): Promise<boolean> {\n let anyStale = false;\n const obsStale = await ensureFreshObservations();\n if (obsStale) anyStale = true;\n const skillsStale = await ensureFreshMiniSkills();\n if (skillsStale) anyStale = true;\n return anyStale;\n}\n\n/**\n * Centralized freshness gate — wraps a read-facing function with\n * ensureFreshIndex() so callers cannot forget the freshness check.\n *\n * Usage:\n * return withFreshIndex(async () => { ... read from Orama ... });\n *\n * Phase 3a: replaces withFreshObservations() at all retrieval call sites.\n */\nexport async function withFreshIndex<T>(fn: () => T | Promise<T>): Promise<T> {\n await ensureFreshIndex();\n return fn();\n}\n\n/**\n * Reset mini-skill freshness tracking. Used in tests.\n */\nexport function resetMiniSkillFreshness(): void {\n lastMiniSkillGeneration = -1;\n indexedSkillDocIds.clear();\n}\n","/**\n * Orama Store\n *\n * Full-text + vector + hybrid search engine backed by Orama.\n * Source: @orama/orama (10.1K stars, <2KB, pure JS, zero deps)\n *\n * Schema designed to store Observations with all searchable fields.\n * Vector search (embeddings) will be added in P1 phase.\n */\n\nimport { create, insert, search, remove, update, count, getByID, type AnyOrama } from '@orama/orama';\nimport type { MemorixDocument, SearchOptions, IndexEntry, KnowledgeLayer, ObservationReader } from '../types.js';\nimport { OBSERVATION_ICONS, type ObservationType } from '../types.js';\nimport { resolveKnowledgeLayer } from '../skills/mini-skills.js';\nimport { canReadObservation } from '../memory/visibility.js';\nimport { getEmbeddingProvider, type EmbeddingProvider } from '../embedding/provider.js';\nimport { calculateProjectAffinity, extractProjectKeywords, type AffinityContext, type MemoryContent } from './project-affinity.js';\nimport { detectQueryIntent, applyIntentBoost } from '../search/intent-detector.js';\nimport { maybeExpandSearchQuery } from '../search/query-expansion.js';\n\nlet db: AnyOrama | null = null;\nlet dbInitPromise: Promise<AnyOrama> | null = null;\nlet dbGeneration = 0;\nlet embeddingEnabled = false;\nlet embeddingDimensions: number | null = null;\nlet indexEmbeddingProvider: EmbeddingProvider | null = null;\nlet deferredCachedVectorHydration: Promise<void> | null = null;\nconst docByObservationKey = new Map<string, MemorixDocument>();\nconst NON_CJK_HYBRID_SIMILARITY = 0.45;\nconst lastSearchModeByProject = new Map<string, string>();\nconst SEARCH_MODE_DEFAULT_KEY = '__global__';\nexport function getLastSearchMode(projectId?: string): string {\n return lastSearchModeByProject.get(projectId ?? SEARCH_MODE_DEFAULT_KEY) ?? 'fulltext';\n}\n// Hard filter: titles starting with these are command execution logs, not knowledge.\n// They are excluded from results entirely (not just demoted) unless the query is command-like.\nconst COMMAND_LOG_TITLE = /^(Ran:|Command:|Executed:)\\s/i;\n// Soft demotion: titles containing shell-specific patterns get a score penalty.\nconst COMMAND_STYLE_TITLE = /(\\bfindstr\\b|\\bSelect-String\\b|\\bGet-Content\\b|\\bnpx\\s+vitest\\b|\\bnpx\\s+tsc\\b|\\b2>&1\\b)/i;\nconst COMMAND_LIKE_QUERY = /\\b(git|npm|npx|pnpm|yarn|node|bash|powershell|curl|memorix)\\b/i;\n// Stricter pattern: query IS a command (tool word at start, e.g. \"git status\", \"npm install\").\n// Does NOT match natural language like \"why is memorix search slow\".\nconst COMMAND_INTENT_QUERY = /^\\s*(git|npm|npx|pnpm|yarn|node|bash|powershell|curl|memorix)\\s/i;\n// Natural language markers — if ANY of these appear in the query, it is NOT a pure command.\n// Covers: question words, problem descriptors, reasoning words.\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;\n\n/**\n * Build a globally unique Orama document ID for an observation.\n * observationId is only unique within a project, so projectId must be included.\n */\nexport function makeOramaObservationId(projectId: string, observationId: number): string {\n return `obs-${encodeURIComponent(projectId)}-${observationId}`;\n}\n\nfunction makeEntryKey(projectId: string | undefined, observationId: number): string {\n return `${projectId ?? ''}::${observationId}`;\n}\n\nfunction rememberObservationDoc(doc: MemorixDocument): MemorixDocument {\n const publicDoc = { ...doc };\n delete publicDoc.embedding;\n if (doc.projectId && typeof doc.observationId === 'number') {\n docByObservationKey.set(makeEntryKey(doc.projectId, doc.observationId), publicDoc);\n }\n return publicDoc;\n}\n\nfunction isCommandLikeQuery(query: string): boolean {\n return COMMAND_LIKE_QUERY.test(query);\n}\n\n/**\n * Resolve the effective source label for intent-boost purposes.\n * Phase 1 introduced sourceDetail='git-ingest' as a more precise signal than\n * source='git'. Treat them as equivalent so intent-based source boosts\n * (e.g. what_changed → git: 2.0) apply to both representations.\n * Used in the source-aware retrieval path only — not stored or exported.\n */\nfunction effectiveSource(\n source: 'agent' | 'git' | 'manual',\n sourceDetail?: 'explicit' | 'hook' | 'git-ingest',\n): 'agent' | 'git' | 'manual' {\n return sourceDetail === 'git-ingest' ? 'git' : source;\n}\n\n/** True when the query IS a command (tool word leads), not just mentioning a tool. */\nfunction isCommandIntentQuery(query: string): boolean {\n if (!COMMAND_INTENT_QUERY.test(query)) return false;\n // If the query contains natural language markers (question words, problem\n // descriptors), it is a human question about a tool, not a CLI invocation.\n if (NATURAL_LANGUAGE_MARKERS.test(query)) return false;\n return true;\n}\n\n/** @internal Exported for testing only. */\nexport { classifyQueryTier as _classifyQueryTier };\n\n/**\n * Query tier classification for performance-aware search.\n * - 'fast': short/exact/command queries → fulltext only, no embedding, no rerank\n * - 'standard': normal queries → fulltext + embedding, no rerank\n * - 'heavy': CJK or long ambiguous queries → expansion + embedding + rerank\n */\ntype QueryTier = 'fast' | 'standard' | 'heavy';\n\nfunction classifyQueryTier(query: string): QueryTier {\n if (!query || query.trim().length === 0) return 'fast';\n // CJK-heavy queries must be checked FIRST — CJK text has no word-separating\n // spaces, so word-count heuristics would misclassify them as \"fast\".\n const cjkCount = (query.match(/[\\u4e00-\\u9fff\\u3040-\\u309f\\u30a0-\\u30ff\\uac00-\\ud7af]/g) || []).length;\n if (cjkCount / query.length > 0.3) return 'heavy';\n // Single-word or very short queries: fast path\n const words = query.trim().split(/\\s+/);\n if (words.length <= 1 && query.length <= 20) return 'fast';\n // Command-intent queries: fast path (\"git status\", \"npm install\")\n // NOT triggered by natural language mentioning a tool (\"why is memorix search slow\")\n if (isCommandIntentQuery(query)) return 'fast';\n // Long multi-word queries: heavy path\n if (words.length >= 5) return 'heavy';\n // Everything else: standard\n return 'standard';\n}\n\nfunction isCommandLogEntry(title: string): boolean {\n return COMMAND_LOG_TITLE.test(title);\n}\n\nfunction isCommandStyleEntry(title: string): boolean {\n return COMMAND_STYLE_TITLE.test(title);\n}\n\nfunction isVectorDimensionMismatchError(error: unknown): boolean {\n if (!(error instanceof Error)) return false;\n return (\n /declared as a \\d+-dimensional vector, but got a \\d+-dimensional vector/i.test(error.message) ||\n /dimension mismatch/i.test(error.message)\n );\n}\n\nfunction stripVectorSearchParams(params: Record<string, unknown>): Record<string, unknown> {\n const { mode, vector, similarity, hybridWeights, ...rest } = params;\n return rest;\n}\n\n/**\n * Initialize or return the Orama database instance.\n * Schema conditionally includes vector field based on embedding provider.\n * Graceful degradation: no provider → fulltext only, provider → hybrid.\n */\nasync function initializeDb(\n options: { allowNetworkProbe?: boolean },\n generation: number,\n): Promise<AnyOrama> {\n // Check if embedding provider is available.\n const provider = await getEmbeddingProvider({ allowNetworkProbe: options.allowNetworkProbe });\n const nextEmbeddingEnabled = provider !== null;\n const nextEmbeddingDimensions = provider?.dimensions ?? null;\n\n const baseSchema = {\n id: 'string' as const,\n observationId: 'number' as const,\n entityName: 'string' as const,\n type: 'string' as const,\n title: 'string' as const,\n narrative: 'string' as const,\n facts: 'string' as const,\n filesModified: 'string' as const,\n concepts: 'string' as const,\n tokens: 'number' as const,\n createdAt: 'string' as const,\n projectId: 'string' as const,\n accessCount: 'number' as const,\n lastAccessedAt: 'string' as const,\n status: 'string' as const,\n source: 'string' as const,\n sourceDetail: 'string' as const,\n valueCategory: 'string' as const,\n admissionState: 'string' as const,\n admissionReason: 'string' as const,\n visibility: 'string' as const,\n createdByAgentId: 'string' as const,\n sharedWithAgentIds: 'string' as const,\n documentType: 'string' as const,\n knowledgeLayer: 'string' as const,\n };\n\n // Dynamic vector dimensions based on provider (384 for local, 1024+ for API)\n const dims = nextEmbeddingDimensions ?? 384;\n const schema = nextEmbeddingEnabled\n ? { ...baseSchema, embedding: `vector[${dims}]` as const }\n : baseSchema;\n\n const nextDb = await create({ schema });\n\n // resetDb() may have started a new lifecycle while the provider was loading.\n // Discard this obsolete instance rather than letting it overwrite the new one.\n if (generation !== dbGeneration) {\n return getDb(options);\n }\n\n indexEmbeddingProvider = provider;\n embeddingEnabled = nextEmbeddingEnabled;\n embeddingDimensions = nextEmbeddingDimensions;\n db = nextDb;\n\n return nextDb;\n}\n\nexport async function getDb(options: { allowNetworkProbe?: boolean } = {}): Promise<AnyOrama> {\n if (db) return db;\n if (dbInitPromise) return dbInitPromise;\n\n const initPromise = initializeDb(options, dbGeneration);\n dbInitPromise = initPromise;\n\n try {\n return await initPromise;\n } finally {\n if (dbInitPromise === initPromise) {\n dbInitPromise = null;\n }\n }\n}\n\n/**\n * Reset the database instance (useful for testing).\n */\nexport async function resetDb(): Promise<void> {\n dbGeneration++;\n db = null;\n dbInitPromise = null;\n embeddingEnabled = false;\n embeddingDimensions = null;\n indexEmbeddingProvider = null;\n deferredCachedVectorHydration = null;\n lastSearchModeByProject.clear();\n docByObservationKey.clear();\n}\n\n/**\n * Check if embedding/vector search is active.\n */\nexport function isEmbeddingEnabled(): boolean {\n return embeddingEnabled;\n}\n\n/**\n * Current vector dimensions for the active Orama index.\n * Returns null when vector search is disabled for this process.\n */\nexport function getVectorDimensions(): number | null {\n return embeddingEnabled ? embeddingDimensions : null;\n}\n\n/**\n * Generate embedding for text content using the available provider.\n * Returns null if no provider is available.\n */\nexport async function generateEmbedding(text: string): Promise<number[] | null> {\n const provider = await getEmbeddingProvider();\n if (!provider) return null;\n return provider.embed(text);\n}\n\n/**\n * Batch-generate embeddings for multiple texts.\n * Much faster than individual calls — ONNX processes batches of 64 in parallel.\n * Returns null entries for texts that fail.\n */\nexport async function batchGenerateEmbeddings(texts: string[]): Promise<(number[] | null)[]> {\n const provider = await getEmbeddingProvider();\n if (!provider || texts.length === 0) return texts.map(() => null);\n try {\n const results = await provider.embedBatch(texts);\n return results;\n } catch (error) {\n console.error(\n `[memorix] Batch embedding failed, falling back to null vectors: ${error instanceof Error ? error.message : error}`,\n );\n return texts.map(() => null);\n }\n}\n\nasync function getCachedEmbeddings(texts: string[]): Promise<(number[] | null)[]> {\n if (!embeddingEnabled || texts.length === 0) return texts.map(() => null);\n const provider = indexEmbeddingProvider;\n if (!provider?.getCachedEmbeddings) return texts.map(() => null);\n try {\n return await provider.getCachedEmbeddings(texts);\n } catch {\n // Cached vectors are an optimization. Missing entries use background recovery.\n return texts.map(() => null);\n }\n}\n\n/**\n * Hydrate the Orama index from persisted observations.\n * Must be called before searching if the index was freshly created (TUI / CLI startup).\n * Skips observations already in the index (idempotent).\n */\nexport interface HydrateIndexOptions {\n /** Do not issue an API dimension probe while building the startup index. */\n allowNetworkProbe?: boolean;\n /** Attach cached vectors after lexical hydration instead of awaiting cache I/O. */\n deferCachedVectors?: boolean;\n}\n\ntype HydrationCandidate = { observation: any; id: string };\n\nfunction observationEmbeddingText(observation: any): string {\n return [\n observation.title ?? '',\n observation.narrative ?? '',\n ...(Array.isArray(observation.facts) ? observation.facts : []),\n ].join(' ');\n}\n\nfunction documentEmbeddingText(document: Pick<MemorixDocument, 'title' | 'narrative' | 'facts'>): string {\n return [document.title ?? '', document.narrative ?? '', document.facts ?? ''].join(' ');\n}\n\nfunction isCompatibleCachedVector(vector: number[] | null): vector is number[] {\n return Boolean(\n vector &&\n embeddingDimensions !== null &&\n vector.length === embeddingDimensions &&\n vector.every(Number.isFinite),\n );\n}\n\nasync function attachCachedVectors(\n database: AnyOrama,\n candidates: HydrationCandidate[],\n): Promise<void> {\n const cachedVectors = await getCachedEmbeddings(\n candidates.map(({ observation }) => observationEmbeddingText(observation)),\n );\n\n // A reset or project switch created a new index while the cache was loading.\n // Do not attach stale vectors to that new index.\n if (db !== database) return;\n\n for (let index = 0; index < candidates.length; index++) {\n const vector = cachedVectors[index];\n if (!isCompatibleCachedVector(vector)) continue;\n const existing = getByID(database, candidates[index].id) as MemorixDocument | undefined;\n if (!existing || documentEmbeddingText(existing) !== observationEmbeddingText(candidates[index].observation)) continue;\n try {\n await update(database, candidates[index].id, { ...existing, embedding: vector });\n } catch {\n // Vector cache hydration is best-effort. The normal backfill lane owns misses.\n }\n }\n}\n\nexport async function hydrateIndex(\n observations: any[],\n options: HydrateIndexOptions = {},\n): Promise<number> {\n const database = await getDb({ allowNetworkProbe: options.allowNetworkProbe });\n\n const candidates: HydrationCandidate[] = [];\n for (const observation of observations) {\n if (!observation || !observation.id || !observation.projectId) continue;\n const id = makeOramaObservationId(observation.projectId, observation.id);\n if (getByID(database, id)) continue;\n candidates.push({ observation, id });\n }\n\n const deferCachedVectors = options.deferCachedVectors === true && Boolean(indexEmbeddingProvider?.getCachedEmbeddings);\n const cachedVectors = deferCachedVectors\n ? candidates.map(() => null)\n : await getCachedEmbeddings(candidates.map(({ observation }) => observationEmbeddingText(observation)));\n\n let inserted = 0;\n for (let index = 0; index < candidates.length; index++) {\n const { observation: obs, id } = candidates[index];\n try {\n const vector = cachedVectors[index];\n const compatibleVector = isCompatibleCachedVector(vector) ? vector : null;\n const doc: MemorixDocument = {\n id,\n observationId: obs.id,\n entityName: obs.entityName || '',\n type: obs.type || 'discovery',\n title: obs.title || '',\n narrative: obs.narrative || '',\n facts: Array.isArray(obs.facts) ? obs.facts.join(' ') : '',\n filesModified: Array.isArray(obs.filesModified) ? obs.filesModified.join(' ') : '',\n concepts: Array.isArray(obs.concepts) ? obs.concepts.join(' ') : '',\n tokens: obs.tokens ?? 0,\n createdAt: obs.createdAt || '',\n projectId: obs.projectId,\n accessCount: obs.accessCount ?? 0,\n lastAccessedAt: obs.lastAccessedAt || '',\n status: obs.status ?? 'active',\n source: obs.source || 'agent',\n sourceDetail: obs.sourceDetail ?? '',\n valueCategory: obs.valueCategory ?? '',\n admissionState: obs.admissionState ?? '',\n admissionReason: obs.admissionReason ?? '',\n visibility: obs.visibility ?? 'project',\n createdByAgentId: obs.createdByAgentId ?? '',\n sharedWithAgentIds: JSON.stringify(obs.sharedWithAgentIds ?? []),\n documentType: 'observation',\n knowledgeLayer: resolveKnowledgeLayer('observation', obs.sourceDetail, obs.source),\n ...(compatibleVector ? { embedding: compatibleVector } : {}),\n };\n await insert(database, doc);\n rememberObservationDoc(doc);\n inserted++;\n } catch { /* skip malformed entries */ }\n }\n\n deferredCachedVectorHydration = deferCachedVectors\n ? attachCachedVectors(database, candidates).catch(() => {})\n : null;\n return inserted;\n}\n\n/**\n * Prepare the lexical index without probing a remote embedding API. Cached\n * vectors attach after the disk cache is ready, outside the startup path.\n */\nexport async function hydrateIndexForStartup(observations: any[]): Promise<number> {\n return hydrateIndex(observations, {\n allowNetworkProbe: false,\n deferCachedVectors: true,\n });\n}\n\n/**\n * Returns the background cache-only hydration started by the most recent\n * startup index pass. It never makes an embedding API call.\n */\nexport function getDeferredCachedVectorHydration(): Promise<void> | null {\n return deferredCachedVectorHydration;\n}\n\n/** Return whether the current in-memory index already has a usable vector. */\nexport function hasObservationVector(projectId: string, observationId: number): boolean {\n if (!db || !embeddingEnabled || embeddingDimensions === null) return false;\n const document = getByID(db, makeOramaObservationId(projectId, observationId)) as MemorixDocument | undefined;\n return Array.isArray(document?.embedding) &&\n document.embedding.length === embeddingDimensions &&\n document.embedding.every(Number.isFinite);\n}\n\n/**\n * Insert an observation document into the store.\n */\nexport async function insertObservation(doc: MemorixDocument): Promise<void> {\n const database = await getDb();\n await insert(database, doc);\n rememberObservationDoc(doc);\n}\n\n/**\n * Update retrieval metadata without rebuilding an embedding. Admission is\n * deliberately metadata-only: promotion must not create another embedding\n * request or delay a background qualification job.\n */\nexport async function updateObservationMetadata(\n projectId: string,\n observationId: number,\n patch: Partial<Pick<MemorixDocument, 'admissionState' | 'admissionReason' | 'visibility' | 'createdByAgentId' | 'sharedWithAgentIds'>>,\n): Promise<boolean> {\n const database = await getDb();\n const id = makeOramaObservationId(projectId, observationId);\n const existing = getByID(database, id) as MemorixDocument | undefined;\n if (!existing) return false;\n const next = { ...existing, ...patch };\n await update(database, id, next);\n rememberObservationDoc(next);\n return true;\n}\n\n/**\n * Remove an observation document by its Orama internal ID.\n */\nexport async function removeObservation(oramaId: string): Promise<void> {\n const database = await getDb();\n await remove(database, oramaId);\n for (const [key, doc] of docByObservationKey.entries()) {\n if (doc.id === oramaId) {\n docByObservationKey.delete(key);\n break;\n }\n }\n}\n\n/**\n * Search observations using Orama full-text search.\n * Returns L1 IndexEntry array (compact, ~50-100 tokens per result).\n *\n * Progressive Disclosure Layer 1 — adopted from claude-mem.\n */\nexport async function searchObservations(options: SearchOptions): Promise<IndexEntry[]> {\n const perf = !!process.env.MEMORIX_PERF;\n const t0 = perf ? performance.now() : 0;\n const mark = (label: string) => { if (perf) { const now = performance.now(); process.stderr.write(` [search-perf] ${label}: ${(now - t0).toFixed(0)}ms\\n`); } };\n const modeKey = options.projectId ?? SEARCH_MODE_DEFAULT_KEY;\n lastSearchModeByProject.set(modeKey, embeddingEnabled ? 'hybrid' : 'fulltext');\n const database = await getDb();\n\n // Resolve project aliases — safety net for observations not yet migrated to canonical ID.\n // After migration, this is typically a single-element array matching options.projectId.\n let projectIds: string[] | null = null;\n if (options.projectId) {\n try {\n const { resolveAliases } = await import('../project/aliases.js');\n projectIds = await resolveAliases(options.projectId);\n } catch {\n projectIds = [options.projectId];\n }\n }\n\n const filters: Record<string, unknown> = {};\n if (projectIds && projectIds.length === 1) {\n filters['projectId'] = projectIds[0];\n }\n // If multiple aliases exist, we skip the Orama projectId filter and post-filter instead\n if (options.type) {\n filters['type'] = options.type;\n }\n if (options.source) {\n filters['source'] = options.source;\n }\n\n // Determine search mode: hybrid (with vector) or fulltext (default)\n const hasQuery = options.query && options.query.trim().length > 0;\n const originalQuery = options.query;\n const tier = hasQuery ? classifyQueryTier(originalQuery!) : 'fast' as QueryTier;\n mark(`tier=${tier}`);\n\n // Query expansion: only for heavy-tier (CJK) queries\n const expandedEmbeddingQuery = tier === 'heavy' ? await maybeExpandSearchQuery(options.query!) : options.query;\n mark('queryExpansion');\n\n // ── Intent-Aware Recall ──────────────────────────────────────\n // Detect query intent (why/when/how/what/problem) and adjust\n // field weights and type boosting accordingly.\n const intentResult = hasQuery ? detectQueryIntent(originalQuery!) : null;\n\n // Orama's vector/hybrid search can leak cross-project hits even when `where`\n // is present, so always keep enough headroom for a deterministic post-filter.\n const requestLimit = projectIds\n ? (options.limit ?? 20) * 3\n : (options.limit ?? 20);\n\n // Default field boosts — overridden by intent-specific boosts when detected\n const defaultBoost: Record<string, number> = {\n title: 3,\n entityName: 2,\n concepts: 1.5,\n narrative: 1,\n facts: 1,\n filesModified: 0.5,\n };\n const fieldBoost = (intentResult?.confidence ?? 0) > 0.3 && intentResult?.fieldBoosts\n ? intentResult.fieldBoosts\n : defaultBoost;\n\n let searchParams: Record<string, unknown> = {\n term: originalQuery,\n limit: requestLimit,\n includeVectors: true,\n ...(Object.keys(filters).length > 0 ? { where: filters } : {}),\n // Search specific fields (not tokens, accessCount, etc.)\n properties: ['title', 'entityName', 'narrative', 'facts', 'concepts', 'filesModified'],\n // Field boosting: intent-aware or default\n boost: fieldBoost,\n // Fuzzy tolerance: allow 1-char typos for short queries, 2 for longer\n ...(hasQuery ? { tolerance: originalQuery!.length > 6 ? 2 : 1 } : {}),\n };\n\n // If embedding provider is available and query tier warrants it, use hybrid search\n // Fast-tier queries skip embedding entirely (fulltext is sufficient)\n let queryVector: number[] | null = null;\n if (embeddingEnabled && hasQuery && tier !== 'fast') {\n try {\n const provider = await getEmbeddingProvider();\n if (provider) {\n const activeVectorDimensions = getVectorDimensions();\n if (activeVectorDimensions !== null && provider.dimensions !== activeVectorDimensions) {\n lastSearchModeByProject.set(\n modeKey,\n `fulltext (embedding dimension mismatch: provider ${provider.dimensions}d vs index ${activeVectorDimensions}d)`,\n );\n console.error(\n `[memorix] Embedding provider dimension mismatch (${provider.dimensions}d provider vs ${activeVectorDimensions}d index); using fulltext search`,\n );\n } else {\n // Embedding timeout: 15 seconds\n const EMBEDDING_TIMEOUT_MS = 15000;\n const embedPromise = provider.embed(expandedEmbeddingQuery!);\n const timeoutPromise = new Promise<never>((_, reject) =>\n setTimeout(() => reject(new Error(`Embedding timeout after ${EMBEDDING_TIMEOUT_MS}ms`)), EMBEDDING_TIMEOUT_MS)\n );\n queryVector = await Promise.race([embedPromise, timeoutPromise]);\n mark('embedding');\n // Detect CJK-heavy queries: BM25 can't tokenize Chinese/Japanese/Korean well\n const cjkRatio = (originalQuery!.match(/[\\u4e00-\\u9fff\\u3040-\\u309f\\u30a0-\\u30ff\\uac00-\\ud7af]/g) || []).length / originalQuery!.length;\n const isCJKHeavy = cjkRatio > 0.3;\n lastSearchModeByProject.set(modeKey, 'hybrid');\n searchParams = {\n ...searchParams,\n mode: 'hybrid',\n vector: {\n value: queryVector,\n property: 'embedding',\n },\n // English paraphrase queries were getting clipped just below 0.5\n // even when vector-only search could already find the right memory.\n similarity: isCJKHeavy ? 0.3 : NON_CJK_HYBRID_SIMILARITY,\n hybridWeights: isCJKHeavy\n ? { text: 0.2, vector: 0.8 } // CJK: trust vector over BM25\n : { text: 0.6, vector: 0.4 },\n };\n }\n }\n } catch (error) {\n // Fallback to fulltext if embedding fails or times out\n lastSearchModeByProject.set(modeKey, 'fulltext (embedding unavailable)');\n console.error('[memorix] Embedding failed or timed out, falling back to fulltext search');\n }\n }\n\n mark('preSearch');\n let results;\n try {\n results = await search(database, searchParams);\n } catch (error) {\n if (queryVector && isVectorDimensionMismatchError(error)) {\n lastSearchModeByProject.set(modeKey, 'fulltext (embedding dimension mismatch)');\n console.error('[memorix] Vector search dimension mismatch detected, retrying without embeddings');\n results = await search(database, stripVectorSearchParams(searchParams));\n } else {\n throw error;\n }\n }\n mark('oramaSearch');\n\n // Fallback: if hybrid returned nothing but we have a vector, retry with vector-only\n if (results.count === 0 && queryVector && embeddingEnabled) {\n try {\n const vectorOnlyParams: Record<string, unknown> = {\n term: '',\n limit: requestLimit,\n includeVectors: true,\n ...(Object.keys(filters).length > 0 ? { where: filters } : {}),\n mode: 'vector',\n vector: {\n value: queryVector,\n property: 'embedding',\n },\n similarity: 0.25,\n };\n lastSearchModeByProject.set(modeKey, 'vector-only (hybrid empty fallback)');\n results = await search(database, vectorOnlyParams);\n } catch {\n // Keep original empty results\n }\n }\n\n // Status filter: default to 'active' only\n const statusFilter = options.status ?? 'active';\n\n // Build intermediate results with rawTime for temporal filtering\n let intermediate = results.hits\n // Always post-filter by projectIds. Vector/hybrid search can leak hits even when\n // the `where` clause is present, so this keeps project isolation deterministic.\n .filter((hit) => {\n if (!projectIds) return true;\n const doc = hit.document as unknown as MemorixDocument;\n return projectIds.includes(doc.projectId);\n })\n // Visibility is enforced before scoring/ranking so private records cannot\n // affect result order, fallback behavior, or downstream detail reads.\n .filter((hit) => canReadObservation(hit.document as unknown as MemorixDocument, options.reader))\n // Post-filter by status (active/resolved/archived)\n .filter((hit) => {\n if (statusFilter === 'all') return true;\n const doc = hit.document as unknown as MemorixDocument;\n return (doc.status || 'active') === statusFilter;\n })\n // Post-filter: exclude probe observations from default search.\n // Probe is operational memory (heartbeats, connectivity checks) — not durable knowledge.\n // Only included when the caller explicitly requests type: 'probe'.\n .filter((hit) => {\n if (options.type === 'probe') return true;\n const doc = hit.document as unknown as MemorixDocument;\n return doc.type !== 'probe';\n })\n .map((hit) => {\n const doc = hit.document as unknown as MemorixDocument;\n const obsType = doc.type as ObservationType;\n // Time decay: newer memories get higher boost\n const ageMs = Date.now() - new Date(doc.createdAt).getTime();\n const DAY = 86_400_000;\n let recencyBoost: number;\n if (ageMs < 1 * DAY) recencyBoost = 1.0;\n else if (ageMs < 7 * DAY) recencyBoost = 0.85;\n else if (ageMs < 30 * DAY) recencyBoost = 0.6;\n else recencyBoost = 0.35;\n\n return {\n id: doc.observationId,\n time: formatTime(doc.createdAt),\n rawTime: doc.createdAt,\n type: obsType,\n icon: OBSERVATION_ICONS[obsType] ?? '[UNKNOWN]',\n title: doc.title,\n tokens: doc.tokens,\n score: (hit.score ?? 1) * recencyBoost,\n projectId: doc.projectId,\n source: (doc.source || 'agent') as 'agent' | 'git' | 'manual',\n sourceDetail: (doc.sourceDetail || undefined) as 'explicit' | 'hook' | 'git-ingest' | undefined,\n valueCategory: (doc.valueCategory || undefined) as 'core' | 'contextual' | 'ephemeral' | undefined,\n admissionState: (doc.admissionState || undefined) as IndexEntry['admissionState'],\n visibility: (doc.visibility || undefined) as IndexEntry['visibility'],\n entityName: doc.entityName || undefined,\n documentType: (doc.documentType || 'observation') as 'observation' | 'mini-skill',\n knowledgeLayer: (doc.knowledgeLayer || 'project-truth') as KnowledgeLayer,\n _isCommandLog: isCommandLogEntry(doc.title),\n };\n });\n\n // ── Knowledge-Layer Boost (Phase 3a, step 3) ─────────────────\n // Explicit layer-aware ranking: promoted knowledge gets a mild boost\n // for general queries, evidence gets a boost for evidence-seeking queries.\n // This is the dedicated layer signal — NOT borrowed from valueCategory.\n {\n const isEvidenceSeeking = intentResult?.intent === 'what_changed' ||\n (hasQuery && /\\b(evidence|verify|proof|git|commit)\\b/i.test(originalQuery!));\n const layerBoosts: Record<string, number> = isEvidenceSeeking\n ? { promoted: 1.10, 'project-truth': 1.00, evidence: 1.15 }\n : { promoted: 1.20, 'project-truth': 1.00, evidence: 0.90 };\n intermediate = intermediate.map(entry => ({\n ...entry,\n score: entry.score * (layerBoosts[(entry as any).knowledgeLayer] ?? 1.0),\n }));\n }\n\n // ── Intent-Aware Type Boosting ───────────────────────────────\n // Boost scores for observation types that match the query intent\n if (intentResult && intentResult.confidence > 0.3) {\n intermediate = intermediate.map(entry => ({\n ...entry,\n score: applyIntentBoost(entry.score, entry.type, intentResult),\n }));\n }\n\n // ── Source-Aware Retrieval ─────────────────────────────────────\n // Boost scores based on memory source matching query intent.\n // e.g., \"what changed\" queries boost git-derived memories,\n // \"why\" queries boost agent-authored reasoning memories.\n if (intentResult && intentResult.confidence > 0.3 && intentResult.sourceBoosts) {\n const srcBoosts = intentResult.sourceBoosts;\n intermediate = intermediate.map(entry => {\n const boost = srcBoosts[effectiveSource(entry.source, entry.sourceDetail)] ?? 1.0;\n const effectiveBoost = 1 + (boost - 1) * intentResult.confidence;\n return { ...entry, score: entry.score * effectiveBoost };\n });\n }\n\n // ── Command-log noise suppression (two-pass) ────────────────\n // 73% of observations are Ran:/Command:/Executed: hook logs. When the query\n // is NOT command-like, we first try excluding them entirely. If that would\n // leave 0 real results (the query only matched command logs), we fall back to\n // keeping them with a very aggressive 0.05x demotion so SOMETHING is returned\n // but noise never dominates when real results exist.\n if (hasQuery && !isCommandLikeQuery(originalQuery!)) {\n const nonCommandEntries = intermediate.filter(e => !(e as any)._isCommandLog);\n if (nonCommandEntries.length > 0) {\n // Enough real results — drop command logs entirely\n intermediate = nonCommandEntries;\n } else {\n // Only command logs matched — keep them but demote heavily\n intermediate = intermediate.map(entry => ({\n ...entry,\n score: (entry as any)._isCommandLog ? entry.score * 0.05 : entry.score,\n }));\n }\n // Also soft-demote shell-specific patterns in remaining results\n intermediate = intermediate.map(entry => ({\n ...entry,\n score: isCommandStyleEntry(entry.title) ? entry.score * 0.3 : entry.score,\n }));\n }\n\n // Automatic capture is useful as an audit trail, but unqualified evidence\n // should not crowd out durable project knowledge in ordinary retrieval.\n // Keep it available as a fallback when it is all the project has.\n if (hasQuery) {\n const qualifiedEntries = intermediate.filter(\n (entry) => entry.admissionState !== 'candidate' && entry.admissionState !== 'ephemeral',\n );\n if (qualifiedEntries.length > 0) intermediate = qualifiedEntries;\n }\n\n // Re-sort: chronological for WHEN queries, relevance for others\n if (intentResult?.preferChronological) {\n intermediate.sort((a, b) => new Date(b.rawTime).getTime() - new Date(a.rawTime).getTime());\n } else {\n intermediate.sort((a, b) => b.score - a.score);\n }\n\n // ─── Project Affinity Scoring (mcp-memory-service style) ───\n // Penalize memories that don't reference the current project to prevent\n // cross-project pollution (e.g., discussing Memorix in a test project workspace)\n if (options.projectId && intermediate.length > 0) {\n const projectName = options.projectId.split('/').pop() ?? options.projectId;\n const affinityContext: AffinityContext = {\n projectName,\n projectId: options.projectId,\n projectKeywords: extractProjectKeywords(projectName, options.projectId),\n };\n\n // Build a map of memory content for affinity calculation\n const memoryContentMap = new Map<number, MemoryContent>();\n for (const hit of results.hits) {\n const doc = hit.document as unknown as MemorixDocument;\n memoryContentMap.set(doc.observationId, {\n title: doc.title,\n narrative: doc.narrative,\n facts: doc.facts?.split?.('\\n') ?? (Array.isArray(doc.facts) ? doc.facts : []),\n concepts: doc.concepts?.split?.('\\n') ?? (Array.isArray(doc.concepts) ? doc.concepts : []),\n entityName: doc.entityName,\n filesModified: doc.filesModified?.split?.('\\n') ?? (Array.isArray(doc.filesModified) ? doc.filesModified : []),\n });\n }\n\n // Apply affinity scoring to each result\n intermediate = intermediate.map(entry => {\n const memory = memoryContentMap.get(entry.id);\n if (!memory) return entry;\n\n const { score: affinityScore } = calculateProjectAffinity(memory, affinityContext);\n return {\n ...entry,\n score: entry.score * affinityScore, // Apply affinity as multiplier\n };\n });\n\n // Re-sort after affinity adjustment\n intermediate.sort((a, b) => b.score - a.score);\n }\n\n // Temporal filtering: since/until date range\n if (options.since) {\n const sinceDate = new Date(options.since).getTime();\n intermediate = intermediate.filter(e => new Date(e.rawTime).getTime() >= sinceDate);\n }\n if (options.until) {\n const untilDate = new Date(options.until).getTime();\n intermediate = intermediate.filter(e => new Date(e.rawTime).getTime() <= untilDate);\n }\n\n // Apply original limit after post-filtering (we intentionally over-requested when project filtering is active)\n if (projectIds) {\n intermediate = intermediate.slice(0, options.limit ?? 20);\n }\n\n // ── Provenance Tiebreaker (standard tier only) ──────────────────\n // When Orama scores converge — a common outcome in standard-tier queries\n // where both fulltext and embedding are used — this pass gives a tiny\n // preference to repository-backed and core memories within the top-K\n // results whose scores fall within a 20% window of the highest score.\n // Amplitudes are intentionally small: the tiebreaker must never reverse\n // a meaningful score gap, only resolve genuine ambiguity.\n // git-ingest / source=git → ×1.06 (repository evidence)\n // valueCategory=core → ×1.03 (explicitly classified durable memory)\n // Constraints:\n // - Standard tier only (fast has no ambiguity; heavy has LLM rerank)\n // - Top-8 results only (doesn't affect long tail)\n // - 20% score window from top score (score ≥ topScore × 0.80)\n if (tier === 'standard' && intermediate.length > 1) {\n const TIEBREAK_TOP_K = 8;\n const TIEBREAK_WINDOW = 0.20;\n const topScore = intermediate[0]?.score ?? 0;\n const threshold = topScore * (1 - TIEBREAK_WINDOW);\n let changed = false;\n for (let i = 0; i < Math.min(TIEBREAK_TOP_K, intermediate.length); i++) {\n const entry = intermediate[i];\n if (entry.score < threshold) break; // outside tiebreak window, stop\n const isGitEvidence = effectiveSource(entry.source, entry.sourceDetail) === 'git';\n const isCore = entry.valueCategory === 'core';\n if (isGitEvidence) {\n intermediate[i] = { ...entry, score: entry.score * 1.06 };\n changed = true;\n } else if (isCore) {\n intermediate[i] = { ...entry, score: entry.score * 1.03 };\n changed = true;\n }\n }\n if (changed) intermediate.sort((a, b) => b.score - a.score);\n }\n\n // ── Entity-affinity hint (standard + heavy tier only) ──────────────\n // When query tokens (4+ chars) match some entity names in results but not\n // others, mildly boost the matching entities (×1.08). This helps queries\n // like \"blog VPS deployment\" surface blog-vps observations over api-relay\n // observations stored in the same project bucket.\n // Gates:\n // - standard or heavy tier only (fast tier is single-word, too noisy)\n // - only fires when some but not all entity names match the query\n // - top-8 and within the 20% window of the top score\n // - cannot reverse a meaningful score gap (amplitude ×1.08)\n if ((tier === 'standard' || tier === 'heavy') && intermediate.length > 1 && hasQuery) {\n const affTokens = originalQuery!\n .toLowerCase()\n .split(/\\s+/)\n .map(t => t.replace(/[_-]/g, ''))\n .filter(t => t.length >= 4);\n\n if (affTokens.length > 0) {\n const entityNames = [...new Set(intermediate.map(e => e.entityName).filter((n): n is string => !!n))];\n const matchedEntities = new Set(\n entityNames.filter(name => {\n const norm = name.toLowerCase().replace(/[_-]/g, '');\n return affTokens.some(t => norm.includes(t));\n }),\n );\n\n if (matchedEntities.size > 0 && matchedEntities.size < entityNames.length) {\n const AFF_TOP_K = 8;\n const AFF_WINDOW = 0.20;\n const AFF_BOOST = 1.08;\n const topScore = intermediate[0]?.score ?? 0;\n const threshold = topScore * (1 - AFF_WINDOW);\n let affChanged = false;\n for (let i = 0; i < Math.min(AFF_TOP_K, intermediate.length); i++) {\n const entry = intermediate[i];\n if (entry.score < threshold) break;\n if (matchedEntities.has(entry.entityName ?? '')) {\n intermediate[i] = { ...entry, score: entry.score * AFF_BOOST };\n affChanged = true;\n }\n }\n if (affChanged) intermediate.sort((a, b) => b.score - a.score);\n }\n }\n }\n\n // ── LLM Reranking (heavy-tier only) ────────────────────────────\n // Only triggered for heavy-tier queries with ambiguous top results.\n // Fast and standard tiers skip entirely.\n // Ambiguity check: top-2 scores within 30% → results are uncertain.\n const shouldRerank = tier === 'heavy'\n && hasQuery\n && intermediate.length > 2\n && (() => {\n const top = intermediate[0]?.score ?? 0;\n const second = intermediate[1]?.score ?? 0;\n return top > 0 && second / top > 0.7; // top-2 within 30% = ambiguous\n })();\n\n if (shouldRerank) {\n try {\n const { rerankResults } = await import('../llm/quality.js');\n const narrativeMap = new Map<string, string>();\n for (const hit of results.hits) {\n const doc = hit.document as unknown as MemorixDocument;\n narrativeMap.set(makeEntryKey(doc.projectId, doc.observationId), doc.narrative);\n }\n // Rerank only top-5 (was 10) to save LLM tokens and latency\n const RERANK_TOP_K = 5;\n const toRerank = intermediate.slice(0, RERANK_TOP_K);\n const candidates = toRerank.map((e, index) => ({\n id: `r${index + 1}`,\n title: e.title,\n type: e.type,\n score: e.score,\n narrative: narrativeMap.get(makeEntryKey(e.projectId, e.id)),\n }));\n \n // LLM rerank timeout: configurable via MEMORIX_RERANK_TIMEOUT_MS, default 5s\n const _parsedRerank = parseInt(process.env.MEMORIX_RERANK_TIMEOUT_MS || '', 10);\n const RERANK_TIMEOUT_MS = Number.isFinite(_parsedRerank) && _parsedRerank > 0 ? _parsedRerank : 5000;\n const rerankPromise = rerankResults(originalQuery!, candidates);\n const timeoutPromise = new Promise<never>((_, reject) =>\n setTimeout(() => reject(new Error(`LLM rerank timeout after ${RERANK_TIMEOUT_MS}ms`)), RERANK_TIMEOUT_MS)\n );\n const { reranked, usedLLM } = await Promise.race([rerankPromise, timeoutPromise]);\n mark(`rerank(usedLLM=${usedLLM})`);\n \n if (usedLLM) {\n lastSearchModeByProject.set(modeKey, (lastSearchModeByProject.get(modeKey) ?? 'fulltext') + ' + LLM rerank');\n const candidateMap = new Map(candidates.map((candidate, index) => [candidate.id, toRerank[index]]));\n const rerankedTop = reranked\n .map(r => candidateMap.get(r.id))\n .filter((e): e is NonNullable<typeof e> => e != null);\n if (rerankedTop.length > 0) {\n intermediate = [...rerankedTop, ...intermediate.slice(RERANK_TOP_K)];\n }\n }\n } catch (error) {\n // Reranking is best-effort: fall back to original order on timeout or error\n console.error('[memorix] LLM rerank failed or timed out, using original order');\n }\n } else {\n mark(`rerank(skipped,tier=${tier})`);\n }\n\n // Build IndexEntry with optional match explanation\n let entries: IndexEntry[] = intermediate.map(({ rawTime: _, _isCommandLog: _c, ...rest }: any) => rest);\n\n for (const hit of results.hits) {\n const doc = hit.document as unknown as MemorixDocument;\n if (canReadObservation(doc, options.reader)) rememberObservationDoc(doc);\n }\n\n // Explainable recall: annotate entries with match reasons (O(1) lookup via Map)\n if (hasQuery && originalQuery) {\n const queryLower = originalQuery.toLowerCase();\n const queryTokens = queryLower.split(/\\s+/).filter(t => t.length > 1);\n const entryMap = new Map(entries.map(e => [makeEntryKey(e.projectId, e.id), e]));\n for (const hit of results.hits) {\n const doc = hit.document as unknown as MemorixDocument;\n const entry = entryMap.get(makeEntryKey(doc.projectId, doc.observationId));\n if (!entry) continue;\n\n const reasons: string[] = [];\n const fields: [string, string][] = [\n ['title', doc.title], ['entity', doc.entityName], ['concept', doc.concepts],\n ['narrative', doc.narrative], ['fact', doc.facts], ['file', doc.filesModified],\n ];\n for (const [name, value] of fields) {\n const valueLower = value.toLowerCase();\n if (queryTokens.some(t => valueLower.includes(t))) reasons.push(name);\n }\n if (reasons.length === 0) reasons.push('fuzzy');\n\n // Prepend a single evidence-type tag (max 1) ahead of field-match labels.\n // Priority: git evidence > synthesized > core core\n // This surfaces WHY this result is notable beyond the query match.\n const isGitEvidence = doc.sourceDetail === 'git-ingest' || doc.source === 'git';\n const isSynthesized = doc.sourceDetail === 'explicit' &&\n // Note: relatedCommits not in MemorixDocument; flag is best-effort from sourceDetail alone.\n // Full synthesized detection is handled in the detail/timeline path where we have the full obs.\n false; // reserved — set explicitly if MemorixDocument gains relatedCommits in future\n const isCore = doc.valueCategory === 'core';\n\n if (isGitEvidence) {\n entry.matchedFields = ['git evidence', ...reasons];\n } else if (isSynthesized) {\n entry.matchedFields = ['synthesized', ...reasons];\n } else if (isCore) {\n entry.matchedFields = ['core core', ...reasons];\n } else {\n entry.matchedFields = reasons;\n }\n }\n }\n\n // Apply token budget if specified (inspired by MemCP)\n if (options.maxTokens && options.maxTokens > 0) {\n entries = applyTokenBudget(entries, options.maxTokens);\n }\n\n // Record access for returned results (fire-and-forget, non-blocking).\n if (options.trackAccess !== false) {\n const returnedKeys = new Set(entries.map((entry) => makeEntryKey(entry.projectId, entry.id)));\n const hitDocs = results.hits\n .map((hit) => ({ id: hit.id, doc: hit.document as unknown as MemorixDocument }))\n .filter(({ doc }) => returnedKeys.has(makeEntryKey(doc.projectId, doc.observationId)));\n recordAccessBatch(hitDocs).catch(() => {});\n }\n\n return entries;\n}\n\n/**\n * Get full observation documents by their observation IDs.\n *\n * Progressive Disclosure Layer 3 — adopted from claude-mem.\n */\nexport async function getObservationsByIds(\n ids: number[],\n projectId?: string,\n): Promise<MemorixDocument[]> {\n const database = await getDb();\n\n // Search for each ID individually and collect results\n const results: MemorixDocument[] = [];\n\n for (const id of ids) {\n if (projectId) {\n const cached = docByObservationKey.get(makeEntryKey(projectId, id));\n if (cached) {\n results.push(cached);\n continue;\n }\n }\n\n const searchResult = await search(database, {\n term: '',\n includeVectors: true,\n where: {\n observationId: { eq: id },\n ...(projectId ? { projectId } : {}),\n },\n limit: 1,\n });\n\n if (searchResult.hits.length > 0) {\n results.push(rememberObservationDoc(searchResult.hits[0].document as unknown as MemorixDocument));\n }\n }\n\n return results;\n}\n\n/**\n * Get observations around an anchor for timeline context.\n *\n * Progressive Disclosure Layer 2 — adopted from claude-mem.\n */\nexport async function getTimeline(\n anchorId: number,\n projectId?: string,\n depthBefore = 3,\n depthAfter = 3,\n reader?: ObservationReader,\n): Promise<{ before: IndexEntry[]; anchor: IndexEntry | null; after: IndexEntry[] }> {\n // Use in-memory observations for reliable lookup\n // (Orama search with empty term is unreliable — same fix as compactDetail)\n const { withFreshIndex } = await import('../memory/freshness.js');\n const { getAllObservations } = await import('../memory/observations.js');\n const rawObs = await withFreshIndex(() => getAllObservations());\n\n // Filter by project if specified — prevents cross-project context leaking\n const allObs = (projectId\n ? rawObs.filter((o) => o.projectId === projectId)\n : rawObs).filter((observation) => canReadObservation(observation, reader));\n\n // Sort by creation time\n const sorted = allObs.sort((a, b) => a.createdAt.localeCompare(b.createdAt));\n\n const anchorIndex = sorted.findIndex((o) => o.id === anchorId);\n if (anchorIndex === -1) {\n return { before: [], anchor: null, after: [] };\n }\n\n const toIndexEntry = (obs: {\n id: number; type: string; title: string; tokens: number; createdAt: string;\n source?: string; sourceDetail?: string; valueCategory?: string; admissionState?: string; visibility?: string;\n }): IndexEntry => {\n const obsType = obs.type as ObservationType;\n return {\n id: obs.id,\n time: formatTime(obs.createdAt),\n type: obsType,\n icon: OBSERVATION_ICONS[obsType] ?? '[UNKNOWN]',\n title: obs.title,\n tokens: obs.tokens,\n source: (obs.source as IndexEntry['source']) || undefined,\n sourceDetail: (obs.sourceDetail as IndexEntry['sourceDetail']) || undefined,\n valueCategory: (obs.valueCategory as IndexEntry['valueCategory']) || undefined,\n admissionState: (obs.admissionState as IndexEntry['admissionState']) || undefined,\n visibility: (obs.visibility as IndexEntry['visibility']) || undefined,\n };\n };\n\n const before = sorted\n .slice(Math.max(0, anchorIndex - depthBefore), anchorIndex)\n .map(toIndexEntry);\n\n const after = sorted\n .slice(anchorIndex + 1, anchorIndex + 1 + depthAfter)\n .map(toIndexEntry);\n\n return {\n before,\n anchor: toIndexEntry(sorted[anchorIndex]),\n after,\n };\n}\n\n/**\n * Record access for observations returned in search results.\n * Increments accessCount and updates lastAccessedAt.\n * Inspired by mcp-memory-service's record_access() pattern.\n */\nasync function recordAccessBatch(hitDocs: { id: string; doc: MemorixDocument }[]): Promise<void> {\n const database = await getDb();\n const now = new Date().toISOString();\n\n for (const { id, doc } of hitDocs) {\n try {\n // Use update() directly — no need to re-search since we already have the doc\n await update(database, id, {\n ...doc,\n accessCount: (doc.accessCount ?? 0) + 1,\n lastAccessedAt: now,\n });\n } catch {\n // Best-effort — don't break search if access tracking fails\n }\n }\n}\n\n/**\n * Trim search results to fit within a token budget.\n * Inspired by MemCP's _apply_token_budget() pattern.\n */\nfunction applyTokenBudget(entries: IndexEntry[], maxTokens: number): IndexEntry[] {\n const budgeted: IndexEntry[] = [];\n let tokensUsed = 0;\n\n for (const entry of entries) {\n if (tokensUsed + entry.tokens > maxTokens && budgeted.length > 0) {\n break;\n }\n budgeted.push(entry);\n tokensUsed += entry.tokens;\n }\n\n return budgeted;\n}\n\n/**\n * Get total observation count, optionally filtered by project.\n */\nexport async function getObservationCount(projectId?: string): Promise<number> {\n const database = await getDb();\n if (!projectId) {\n return await count(database);\n }\n const results = await search(database, {\n term: '',\n where: { projectId },\n limit: 0,\n });\n return results.count;\n}\n\n/**\n * Format ISO date string to compact time display.\n */\nfunction formatTime(isoDate: string): string {\n try {\n const date = new Date(isoDate);\n return date.toLocaleTimeString('en-US', {\n hour: 'numeric',\n minute: '2-digit',\n hour12: true,\n });\n } catch {\n return isoDate;\n }\n}\n","/**\n * Entity Extractor\n *\n * Regex-based entity extraction from observation content.\n * Inspired by MemCP's RegexEntityExtractor (MAGMA paper).\n *\n * Extracts: file paths, module paths, URLs, @mentions, CamelCase identifiers.\n * Also detects causal patterns for automatic edge typing.\n */\n\nconst ENTITY_PATTERNS: Array<{ kind: string; pattern: RegExp }> = [\n // File paths (e.g. src/auth/jwt.ts, ./config.json)\n { kind: 'file', pattern: /(?:^|[\\s\"'(])([.\\w/-]+\\.\\w{1,10})(?:[\\s\"'),]|$)/g },\n // Module/package paths (e.g. @orama/orama, memcp.core.graph)\n { kind: 'module', pattern: /(?:^|[\\s\"'(,])(@[\\w-]+\\/[\\w.-]+)|\\b([a-zA-Z_]\\w*(?:\\.[a-zA-Z_]\\w*){2,})\\b/g },\n // URLs\n { kind: 'url', pattern: /https?:\\/\\/[^\\s\"'<>)]+/g },\n // @mentions\n { kind: 'mention', pattern: /@([a-zA-Z_]\\w+)/g },\n // CamelCase identifiers (likely class/type names)\n { kind: 'identifier', pattern: /\\b([A-Z][a-z]+(?:[A-Z][a-z]+)+)\\b/g },\n // Chinese identifiers: quoted Chinese terms or backtick-wrapped Chinese (e.g. 「认证模块」, `数据库连接`)\n { kind: 'identifier', pattern: /[「『【]([一-鿿㐀-䶿]{2,}(?:[一-鿿㐀-䶿a-zA-Z0-9_-]*[一-鿿㐀-䶿])?)[」』】]/g },\n { kind: 'identifier', pattern: /`([一-鿿㐀-䶿]{2,}[一-鿿㐀-䶿a-zA-Z0-9_-]*)`/g },\n];\n\n/**\n * Patterns that indicate causal relationships.\n * Used to auto-detect causal edge types in Knowledge Graph.\n */\nconst CAUSAL_PATTERN = /\\b(?:because|therefore|due to|caused by|as a result|decided to|chosen because|so that|in order to|leads to|results in|fixed by|resolved by)\\b|(?:因为|所以|由于|导致|造成|结果|因此|为了|解决|修复|修正|决定|选择|采用)/i;\n\nexport interface ExtractedEntities {\n files: string[];\n modules: string[];\n urls: string[];\n mentions: string[];\n identifiers: string[];\n hasCausalLanguage: boolean;\n}\n\n/**\n * Extract entities from text content.\n * Returns deduplicated lists of each entity type.\n */\nexport function extractEntities(content: string): ExtractedEntities {\n const result: ExtractedEntities = {\n files: [],\n modules: [],\n urls: [],\n mentions: [],\n identifiers: [],\n hasCausalLanguage: false,\n };\n\n const seen = new Set<string>();\n\n for (const { kind, pattern } of ENTITY_PATTERNS) {\n // Reset lastIndex for global regexes\n pattern.lastIndex = 0;\n let match: RegExpExecArray | null;\n while ((match = pattern.exec(content)) !== null) {\n const entity = (match[1] ?? match[2] ?? match[0]).trim().replace(/^[\"'(]+|[\"'),]+$/g, '');\n if (entity.length < 3 || (kind === 'file' && entity.length < 5)) continue;\n\n const key = `${kind}:${entity.toLowerCase()}`;\n if (seen.has(key)) continue;\n seen.add(key);\n\n switch (kind) {\n case 'file':\n // Filter out property chains (e.g. config.llm.apiKey, process.env.FOO)\n // Real files have path separators or known extensions\n // Inline logic to prevent tree-shaking\n const isLikelyFilePath = (() => {\n // Has path separator → likely a file path\n if (entity.includes('/') || entity.includes('\\\\')) return true;\n // Starts with ./ or ../ → relative path\n if (entity.startsWith('./') || entity.startsWith('../')) return true;\n // Blocked property chains\n if (/^(?:process\\.env|config\\.|options\\.|params\\.|props\\.|this\\.|self\\.|module\\.|exports\\.|require\\.|import\\.)/i.test(entity)) return false;\n // Multiple dots without path separator → likely property chain\n const dotCount = (entity.match(/\\./g) || []).length;\n if (dotCount >= 2) return false;\n // Single dot: check if extension is a known file extension\n const ext = entity.split('.').pop()?.toLowerCase() ?? '';\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']);\n return FILE_EXTENSIONS.has(ext);\n })();\n if (isLikelyFilePath) {\n result.files.push(entity);\n }\n break;\n case 'module':\n result.modules.push(entity);\n break;\n case 'url':\n result.urls.push(entity);\n break;\n case 'mention':\n result.mentions.push(entity);\n break;\n case 'identifier':\n result.identifiers.push(entity);\n break;\n }\n }\n }\n\n result.hasCausalLanguage = CAUSAL_PATTERN.test(content);\n\n return result;\n}\n\n/** Known file extensions that indicate a real file path */\nconst FILE_EXTENSIONS = new Set([\n 'ts', 'js', 'tsx', 'jsx', 'mts', 'mjs', 'cjs',\n 'json', 'yaml', 'yml', 'toml', 'xml', 'csv',\n 'py', 'rb', 'go', 'rs', 'java', 'kt', 'swift', 'c', 'cpp', 'h',\n 'html', 'css', 'scss', 'less', 'vue', 'svelte',\n 'sh', 'bash', 'zsh', 'ps1', 'cmd', 'bat',\n 'md', 'txt', 'rst', 'log',\n 'sql', 'graphql', 'prisma',\n 'env', 'gitignore', 'dockerignore', 'dockerfile',\n 'lock', 'config',\n]);\n\n/** Property-chain patterns that are NOT file paths */\nconst PROPERTY_CHAIN_BLOCKLIST = /^(?:process\\.env|config\\.|options\\.|params\\.|props\\.|this\\.|self\\.|module\\.|exports\\.|require\\.|import\\.)/i;\n\n/**\n * Determine if a matched string is likely a real file path vs a property chain.\n * \n * Examples:\n * \"src/config.ts\" → true (has path separator + known extension)\n * \"config.llm.apiKey\" → false (property chain, no path separator)\n * \"./package.json\" → true (relative path)\n * \"process.env.FOO\" → false (property chain)\n */\nfunction isLikelyFilePath(candidate: string): boolean {\n // Has path separator → likely a file path\n if (candidate.includes('/') || candidate.includes('\\\\')) return true;\n\n // Starts with ./ or ../ → relative path\n if (candidate.startsWith('./') || candidate.startsWith('../')) return true;\n\n // Blocked property chains\n if (PROPERTY_CHAIN_BLOCKLIST.test(candidate)) return false;\n\n // Multiple dots without path separator → likely property chain (e.g. config.llm.apiKey)\n const dotCount = (candidate.match(/\\./g) || []).length;\n if (dotCount >= 2) return false;\n\n // Single dot: check if extension is a known file extension\n const ext = candidate.split('.').pop()?.toLowerCase() ?? '';\n return FILE_EXTENSIONS.has(ext);\n}\n\n/**\n * Auto-generate concepts from extracted entities.\n * Merges with any user-provided concepts.\n */\nexport function enrichConcepts(\n userConcepts: string[],\n extracted: ExtractedEntities,\n): string[] {\n const all = new Set(userConcepts.map((c) => c.toLowerCase()));\n const enriched = [...userConcepts];\n\n // Add file names (without path) as concepts\n for (const f of extracted.files) {\n const name = f.split('/').pop()?.replace(/\\.\\w+$/, '') ?? '';\n if (name.length >= 3 && !all.has(name.toLowerCase())) {\n all.add(name.toLowerCase());\n enriched.push(name);\n }\n }\n\n // Add module names as concepts\n for (const m of extracted.modules) {\n const short = m.split(/[./]/).pop() ?? '';\n if (short.length >= 3 && !all.has(short.toLowerCase())) {\n all.add(short.toLowerCase());\n enriched.push(short);\n }\n }\n\n // Add CamelCase identifiers as concepts\n for (const id of extracted.identifiers) {\n if (!all.has(id.toLowerCase())) {\n all.add(id.toLowerCase());\n enriched.push(id);\n }\n }\n\n return enriched;\n}\n","/**\n * Secret Filter\n *\n * Conservative credential detection and redaction for Memorix memory content.\n * Designed for low false-positive risk: only matches explicit credential\n * assignments (key=value / key: value), not generic discussion of auth concepts.\n *\n * sanitizeCredentials() — store-time: called inside storeObservation() before write\n * redactCredentials() — retrieval-time: called in format/output paths for legacy safety\n * containsCredential() — predicate used for testing and optional logging\n *\n * Both sanitize and redact share the same pattern logic. They are kept as\n * separate named exports so call-site semantics remain clear.\n */\n\n/**\n * Replaces the VALUE portion of matched credential patterns with [REDACTED].\n * The credential key name is preserved so context is not lost.\n *\n * Pattern categories:\n * 1. key=value / key: value forms — password, token, api_key, secret, etc.\n * Requires a real value (6+ non-whitespace chars) to avoid matching\n * discussion text like \"password must be 8 chars\".\n * 2. Bearer authorization header tokens (20+ chars)\n * 3. Structured token prefixes: GitHub (ghp_/ghs_/gho_), OpenAI (sk-), JWT (eyJ)\n */\nfunction applyRedaction(text: string): string {\n if (!text) return text;\n let out = text;\n\n // key=value / key: \"value\" / key='value' — preserve key, redact value\n out = out.replace(\n /((?:password|passwd|pwd|secret|token|api[_-]?key|auth[_-]?key|access[_-]?key|private[_-]?key|client[_-]?secret)\\s*[:=]\\s*[\"']?)([^\\s\"',;\\n]{6,})/gi,\n '$1[REDACTED]',\n );\n\n // Bearer <token> — preserve \"Bearer \", redact token\n out = out.replace(\n /(Bearer\\s+)([A-Za-z0-9._\\-/+]{20,})/g,\n '$1[REDACTED]',\n );\n\n // GitHub tokens (ghp_, ghs_, gho_, github_pat_)\n out = out.replace(/\\b(?:ghp|ghs|gho|github_pat)_[A-Za-z0-9]{36,}\\b/g, '[REDACTED]');\n\n // OpenAI / similar keys (sk-...)\n out = out.replace(/\\bsk-[A-Za-z0-9T-]{20,}\\b/g, '[REDACTED]');\n\n // JWT tokens (base64url header eyJ...)\n out = out.replace(/\\beyJ[A-Za-z0-9._-]{40,}\\b/g, '[REDACTED]');\n\n return out;\n}\n\n/**\n * Store-time sanitization: strips credential values before any durable write.\n * Called inside storeObservation() / upsertObservation() so that every write\n * path (hooks, git-ingest, CLI, reasoning, compact-on-write) is covered.\n */\nexport function sanitizeCredentials(text: string): string {\n return applyRedaction(text);\n}\n\n/**\n * Retrieval-time redaction: masks credential values in display output.\n * Applied in all output formatters (detail, index table, timeline, session context)\n * as a safety net for legacy observations stored before sanitization was in place.\n */\nexport function redactCredentials(text: string): string {\n return applyRedaction(text);\n}\n\n/**\n * Returns true if the text contains an obvious credential pattern.\n * Used for testing and optional diagnostic logging.\n */\nexport function containsCredential(text: string): boolean {\n return applyRedaction(text) !== text;\n}\n","import { randomUUID } from 'node:crypto';\n\nimport { getDatabase } from '../store/sqlite-db.js';\nimport { sanitizeCredentials } from '../memory/secret-filter.js';\n\nexport const MAINTENANCE_JOB_KINDS = [\n 'vector-backfill',\n 'retention-archive',\n 'consolidation',\n 'codegraph-refresh',\n 'observation-qualify',\n 'claim-derive',\n 'claim-requalification',\n 'knowledge-compile',\n 'knowledge-lint',\n 'workflow-index',\n] as const;\n\nexport type MaintenanceJobKind = typeof MAINTENANCE_JOB_KINDS[number];\nexport type MaintenanceJobStatus = 'pending' | 'running' | 'retry' | 'completed' | 'failed';\n\nexport interface MaintenanceJob {\n id: string;\n projectId: string;\n kind: MaintenanceJobKind;\n dedupeKey: string;\n payload: Record<string, unknown>;\n status: MaintenanceJobStatus;\n attempts: number;\n maxAttempts: number;\n runAfter: number;\n leaseOwner?: string;\n leaseExpiresAt?: number;\n lastError?: string;\n createdAt: number;\n updatedAt: number;\n completedAt?: number;\n}\n\nexport interface EnqueueMaintenanceJobInput {\n projectId: string;\n kind: MaintenanceJobKind;\n dedupeKey?: string;\n payload?: Record<string, unknown>;\n maxAttempts?: number;\n runAfter?: number;\n now?: number;\n}\n\nexport interface ClaimMaintenanceJobOptions {\n workerId: string;\n projectId?: string;\n /** Limit this worker to compatible job kinds without claiming other work. */\n kinds?: readonly MaintenanceJobKind[];\n leaseMs?: number;\n now?: number;\n}\n\nexport interface MaintenanceJobSummary {\n total: number;\n pending: number;\n running: number;\n retrying: number;\n completed: number;\n failed: number;\n}\n\nexport type MaintenanceJobRunResult =\n | { action: 'complete' }\n | { action: 'reschedule'; delayMs: number; resetAttempts?: boolean; payload?: Record<string, unknown> };\n\nexport type MaintenanceJobHandler = (\n job: MaintenanceJob,\n) => Promise<MaintenanceJobRunResult | void>;\n\nconst DEFAULT_MAX_ATTEMPTS = 8;\nconst DEFAULT_LEASE_MS = 30_000;\nconst DEFAULT_POLL_INTERVAL_MS = 2_000;\nconst MAX_ERROR_LENGTH = 1_000;\nconst DEFAULT_COMPLETED_HISTORY_RETENTION_MS = 7 * 24 * 60 * 60 * 1_000;\n\nfunction parsePayload(raw: unknown): Record<string, unknown> {\n if (typeof raw !== 'string' || !raw) return {};\n try {\n const parsed = JSON.parse(raw);\n return parsed && typeof parsed === 'object' && !Array.isArray(parsed)\n ? parsed as Record<string, unknown>\n : {};\n } catch {\n return {};\n }\n}\n\nfunction rowToJob(row: any): MaintenanceJob {\n return {\n id: row.id,\n projectId: row.project_id,\n kind: row.kind as MaintenanceJobKind,\n dedupeKey: row.dedupe_key,\n payload: parsePayload(row.payload_json),\n status: row.status as MaintenanceJobStatus,\n attempts: Number(row.attempts),\n maxAttempts: Number(row.max_attempts),\n runAfter: Number(row.run_after),\n ...(row.lease_owner ? { leaseOwner: row.lease_owner } : {}),\n ...(row.lease_expires_at != null ? { leaseExpiresAt: Number(row.lease_expires_at) } : {}),\n ...(row.last_error ? { lastError: row.last_error } : {}),\n createdAt: Number(row.created_at),\n updatedAt: Number(row.updated_at),\n ...(row.completed_at != null ? { completedAt: Number(row.completed_at) } : {}),\n };\n}\n\nfunction clampPositiveInteger(value: number | undefined, fallback: number): number {\n if (!Number.isFinite(value) || value == null) return fallback;\n return Math.max(1, Math.floor(value));\n}\n\nfunction errorText(error: unknown): string {\n const text = error instanceof Error ? error.message : String(error);\n return sanitizeCredentials(text).slice(0, MAX_ERROR_LENGTH);\n}\n\nfunction normalizedKinds(kinds: readonly MaintenanceJobKind[] | undefined): MaintenanceJobKind[] | undefined {\n if (!kinds) return undefined;\n return [...new Set(kinds.filter((kind) => MAINTENANCE_JOB_KINDS.includes(kind)))];\n}\n\n/** Retry delay grows slowly enough for a local control plane but never spins. */\nexport function getMaintenanceRetryDelayMs(attempts: number): number {\n return Math.min(60_000, 1_000 * (2 ** Math.max(0, attempts - 1)));\n}\n\n/**\n * Persistent queue for work that must never run inside an MCP tool handler.\n * SQLite leases make recovery deterministic when a process exits mid-job.\n */\nexport class MaintenanceJobStore {\n private readonly db: any;\n\n constructor(dataDir: string) {\n this.db = getDatabase(dataDir);\n }\n\n enqueue(input: EnqueueMaintenanceJobInput): MaintenanceJob {\n const now = input.now ?? Date.now();\n const dedupeKey = input.dedupeKey ?? input.kind;\n const runAfter = input.runAfter ?? now;\n const maxAttempts = clampPositiveInteger(input.maxAttempts, DEFAULT_MAX_ATTEMPTS);\n const payloadJson = JSON.stringify(input.payload ?? {});\n\n this.begin();\n try {\n this.pruneCompletedHistory({ now });\n const existing = this.db.prepare(`\n SELECT * FROM maintenance_jobs\n WHERE project_id = ? AND kind = ? AND dedupe_key = ?\n AND status IN ('pending', 'running', 'retry')\n LIMIT 1\n `).get(input.projectId, input.kind, dedupeKey);\n\n if (existing) {\n const nextRunAfter = Math.min(Number(existing.run_after), runAfter);\n this.db.prepare(`\n UPDATE maintenance_jobs\n SET payload_json = ?, run_after = ?, updated_at = ?\n WHERE id = ?\n `).run(payloadJson, nextRunAfter, now, existing.id);\n const updated = this.getRow(existing.id)!;\n this.commit();\n return rowToJob(updated);\n }\n\n const id = randomUUID();\n this.db.prepare(`\n INSERT INTO maintenance_jobs (\n id, project_id, kind, dedupe_key, payload_json, status, attempts,\n max_attempts, run_after, created_at, updated_at\n ) VALUES (?, ?, ?, ?, ?, 'pending', 0, ?, ?, ?, ?)\n `).run(id, input.projectId, input.kind, dedupeKey, payloadJson, maxAttempts, runAfter, now, now);\n const created = this.getRow(id)!;\n this.commit();\n return rowToJob(created);\n } catch (error) {\n this.rollback();\n throw error;\n }\n }\n\n get(id: string): MaintenanceJob | undefined {\n const row = this.getRow(id);\n return row ? rowToJob(row) : undefined;\n }\n\n list(options: { projectId?: string; status?: MaintenanceJobStatus; limit?: number } = {}): MaintenanceJob[] {\n const limit = Math.min(500, clampPositiveInteger(options.limit, 100));\n const clauses: string[] = [];\n const values: unknown[] = [];\n if (options.projectId) {\n clauses.push('project_id = ?');\n values.push(options.projectId);\n }\n if (options.status) {\n clauses.push('status = ?');\n values.push(options.status);\n }\n const where = clauses.length > 0 ? `WHERE ${clauses.join(' AND ')}` : '';\n const rows = this.db.prepare(`\n SELECT * FROM maintenance_jobs\n ${where}\n ORDER BY run_after ASC, created_at ASC\n LIMIT ?\n `).all(...values, limit);\n return rows.map(rowToJob);\n }\n\n summary(projectId?: string): MaintenanceJobSummary {\n const row = projectId\n ? this.db.prepare(`\n SELECT\n COUNT(*) AS total,\n SUM(status = 'pending') AS pending,\n SUM(status = 'running') AS running,\n SUM(status = 'retry') AS retrying,\n SUM(status = 'completed') AS completed,\n SUM(status = 'failed') AS failed\n FROM maintenance_jobs WHERE project_id = ?\n `).get(projectId)\n : this.db.prepare(`\n SELECT\n COUNT(*) AS total,\n SUM(status = 'pending') AS pending,\n SUM(status = 'running') AS running,\n SUM(status = 'retry') AS retrying,\n SUM(status = 'completed') AS completed,\n SUM(status = 'failed') AS failed\n FROM maintenance_jobs\n `).get();\n return {\n total: Number(row?.total ?? 0),\n pending: Number(row?.pending ?? 0),\n running: Number(row?.running ?? 0),\n retrying: Number(row?.retrying ?? 0),\n completed: Number(row?.completed ?? 0),\n failed: Number(row?.failed ?? 0),\n };\n }\n\n /**\n * Completed jobs are useful recent operator history, not permanent data.\n * Failed jobs stay available for diagnosis until an operator explicitly\n * resolves them or clears the database.\n */\n pruneCompletedHistory(options: { now?: number; maxAgeMs?: number } = {}): number {\n const now = options.now ?? Date.now();\n const maxAgeMs = Number.isFinite(options.maxAgeMs)\n ? Math.max(0, Math.floor(options.maxAgeMs!))\n : DEFAULT_COMPLETED_HISTORY_RETENTION_MS;\n const result = this.db.prepare(`\n DELETE FROM maintenance_jobs\n WHERE status = 'completed'\n AND completed_at IS NOT NULL\n AND completed_at < ?\n `).run(now - maxAgeMs);\n return Number(result.changes ?? 0);\n }\n\n claimNext(options: ClaimMaintenanceJobOptions): MaintenanceJob | undefined {\n const now = options.now ?? Date.now();\n const leaseMs = clampPositiveInteger(options.leaseMs, DEFAULT_LEASE_MS);\n const kinds = normalizedKinds(options.kinds);\n\n this.begin();\n try {\n // A dead worker leaves a leased row behind. Make it retryable before\n // selecting the next candidate, while respecting its retry budget.\n this.db.prepare(`\n UPDATE maintenance_jobs\n SET\n status = CASE WHEN attempts >= max_attempts THEN 'failed' ELSE 'retry' END,\n run_after = CASE WHEN attempts >= max_attempts THEN run_after ELSE ? END,\n lease_owner = NULL,\n lease_expires_at = NULL,\n last_error = COALESCE(last_error, 'worker lease expired'),\n updated_at = ?\n WHERE status = 'running' AND lease_expires_at IS NOT NULL AND lease_expires_at <= ?\n `).run(now, now, now);\n this.db.prepare(`\n UPDATE maintenance_jobs\n SET status = 'failed', updated_at = ?\n WHERE status IN ('pending', 'retry') AND attempts >= max_attempts\n `).run(now);\n\n if (options.kinds && kinds?.length === 0) {\n this.commit();\n return undefined;\n }\n const projectClause = options.projectId ? 'AND project_id = ?' : '';\n const kindClause = kinds?.length\n ? `AND kind IN (${kinds.map(() => '?').join(', ')})`\n : '';\n const values = [\n now,\n ...(kinds ?? []),\n ...(options.projectId ? [options.projectId] : []),\n ];\n const candidate = this.db.prepare(`\n SELECT * FROM maintenance_jobs\n WHERE status IN ('pending', 'retry') AND run_after <= ?\n ${kindClause}\n ${projectClause}\n ORDER BY run_after ASC, created_at ASC\n LIMIT 1\n `).get(...values);\n\n if (!candidate) {\n this.commit();\n return undefined;\n }\n\n const leaseExpiresAt = now + leaseMs;\n this.db.prepare(`\n UPDATE maintenance_jobs\n SET status = 'running', attempts = attempts + 1, lease_owner = ?,\n lease_expires_at = ?, updated_at = ?\n WHERE id = ?\n `).run(options.workerId, leaseExpiresAt, now, candidate.id);\n const claimed = this.getRow(candidate.id)!;\n this.commit();\n return rowToJob(claimed);\n } catch (error) {\n this.rollback();\n throw error;\n }\n }\n\n /**\n * Extend a running job's lease. A worker may only renew its own lease, so a\n * stale worker cannot reclaim work that was already recovered elsewhere.\n */\n renewLease(id: string, workerId: string, leaseMs = DEFAULT_LEASE_MS, now = Date.now()): boolean {\n const expiresAt = now + clampPositiveInteger(leaseMs, DEFAULT_LEASE_MS);\n const result = this.db.prepare(`\n UPDATE maintenance_jobs\n SET lease_expires_at = ?, updated_at = ?\n WHERE id = ? AND status = 'running' AND lease_owner = ?\n `).run(expiresAt, now, id, workerId);\n return Number(result.changes) > 0;\n }\n\n complete(id: string, workerId: string, now = Date.now()): MaintenanceJob | undefined {\n this.db.prepare(`\n UPDATE maintenance_jobs\n SET status = 'completed', lease_owner = NULL, lease_expires_at = NULL,\n completed_at = ?, updated_at = ?\n WHERE id = ? AND status = 'running' AND lease_owner = ?\n `).run(now, now, id, workerId);\n return this.get(id);\n }\n\n reschedule(\n id: string,\n workerId: string,\n options: { delayMs: number; resetAttempts?: boolean; payload?: Record<string, unknown>; now?: number },\n ): MaintenanceJob | undefined {\n const now = options.now ?? Date.now();\n const delayMs = Number.isFinite(options.delayMs) ? Math.max(0, Math.floor(options.delayMs)) : 0;\n const payloadJson = options.payload === undefined ? null : JSON.stringify(options.payload);\n this.db.prepare(`\n UPDATE maintenance_jobs\n SET status = 'pending', run_after = ?, attempts = CASE WHEN ? THEN 0 ELSE attempts END,\n payload_json = COALESCE(?, payload_json),\n lease_owner = NULL, lease_expires_at = NULL, updated_at = ?\n WHERE id = ? AND status = 'running' AND lease_owner = ?\n `).run(now + delayMs, options.resetAttempts ? 1 : 0, payloadJson, now, id, workerId);\n return this.get(id);\n }\n\n fail(id: string, workerId: string, error: unknown, now = Date.now()): MaintenanceJob | undefined {\n this.begin();\n try {\n const current = this.db.prepare(`\n SELECT * FROM maintenance_jobs\n WHERE id = ? AND status = 'running' AND lease_owner = ?\n `).get(id, workerId);\n if (!current) {\n this.commit();\n return undefined;\n }\n\n const attempts = Number(current.attempts);\n const exhausted = attempts >= Number(current.max_attempts);\n const status: MaintenanceJobStatus = exhausted ? 'failed' : 'retry';\n const runAfter = exhausted ? Number(current.run_after) : now + getMaintenanceRetryDelayMs(attempts);\n this.db.prepare(`\n UPDATE maintenance_jobs\n SET status = ?, run_after = ?, lease_owner = NULL, lease_expires_at = NULL,\n last_error = ?, updated_at = ?\n WHERE id = ?\n `).run(status, runAfter, errorText(error), now, id);\n const updated = this.getRow(id)!;\n this.commit();\n return rowToJob(updated);\n } catch (caught) {\n this.rollback();\n throw caught;\n }\n }\n\n private getRow(id: string): any {\n return this.db.prepare(`SELECT * FROM maintenance_jobs WHERE id = ?`).get(id);\n }\n\n private begin(): void {\n this.db.prepare('BEGIN IMMEDIATE').run();\n }\n\n private commit(): void {\n this.db.prepare('COMMIT').run();\n }\n\n private rollback(): void {\n try { this.db.prepare('ROLLBACK').run(); } catch { /* transaction already closed */ }\n }\n}\n\nexport class MaintenanceJobWorker {\n private readonly workerId: string;\n private readonly leaseMs: number;\n private readonly pollIntervalMs: number;\n private readonly projectId?: string;\n private readonly kinds?: readonly MaintenanceJobKind[];\n private timer: ReturnType<typeof setInterval> | null = null;\n private running = false;\n\n constructor(\n private readonly store: MaintenanceJobStore,\n private readonly handler: MaintenanceJobHandler,\n options: {\n workerId?: string;\n leaseMs?: number;\n pollIntervalMs?: number;\n projectId?: string;\n kinds?: readonly MaintenanceJobKind[];\n } = {},\n ) {\n this.workerId = options.workerId ?? `memorix-${process.pid}-${randomUUID().slice(0, 8)}`;\n this.leaseMs = clampPositiveInteger(options.leaseMs, DEFAULT_LEASE_MS);\n this.pollIntervalMs = clampPositiveInteger(options.pollIntervalMs, DEFAULT_POLL_INTERVAL_MS);\n this.projectId = options.projectId;\n this.kinds = options.kinds;\n }\n\n async runOnce(now = Date.now()): Promise<{ state: 'idle' | 'busy' | 'completed' | 'rescheduled' | 'failed'; job?: MaintenanceJob }> {\n if (this.running) return { state: 'busy' };\n this.running = true;\n try {\n const job = this.store.claimNext({\n workerId: this.workerId,\n projectId: this.projectId,\n kinds: this.kinds,\n now,\n leaseMs: this.leaseMs,\n });\n if (!job) return { state: 'idle' };\n\n const heartbeatMs = Math.max(10, Math.floor(this.leaseMs / 3));\n let leaseLost = false;\n const heartbeat = setInterval(() => {\n try {\n leaseLost = !this.store.renewLease(job.id, this.workerId, this.leaseMs);\n } catch {\n // The next heartbeat can recover from a transient SQLite error. The\n // job itself still has its prior lease until it expires.\n }\n }, heartbeatMs);\n heartbeat.unref?.();\n\n try {\n const result = await this.handler(job);\n if (leaseLost) {\n return { state: 'failed', job: this.store.get(job.id) };\n }\n if (result?.action === 'reschedule') {\n const updated = this.store.reschedule(job.id, this.workerId, {\n delayMs: result.delayMs,\n resetAttempts: result.resetAttempts,\n payload: result.payload,\n now,\n });\n return { state: 'rescheduled', job: updated };\n }\n const updated = this.store.complete(job.id, this.workerId, now);\n return { state: 'completed', job: updated };\n } catch (error) {\n const updated = this.store.fail(job.id, this.workerId, error, now);\n return { state: 'failed', job: updated };\n } finally {\n clearInterval(heartbeat);\n }\n } finally {\n this.running = false;\n }\n }\n\n start(): void {\n if (this.timer) return;\n void this.runOnce().catch(() => {});\n this.timer = setInterval(() => { void this.runOnce().catch(() => {}); }, this.pollIntervalMs);\n this.timer.unref?.();\n }\n\n stop(): void {\n if (!this.timer) return;\n clearInterval(this.timer);\n this.timer = null;\n }\n}\n","import { MaintenanceJobStore } from './maintenance-jobs.js';\n\nexport type MaintenanceQueue = Pick<MaintenanceJobStore, 'enqueue'>;\n\nfunction queueFor(input: { dataDir: string; queue?: MaintenanceQueue }): MaintenanceQueue {\n return input.queue ?? new MaintenanceJobStore(input.dataDir);\n}\n\n/**\n * Coalesce every trigger for a project's next Code Memory scan. The newest\n * event replaces the payload while one durable job remains pending.\n */\nexport function enqueueCodegraphRefresh(input: {\n dataDir: string;\n projectId: string;\n source: string;\n maxFiles?: number;\n queue?: MaintenanceQueue;\n}): void {\n queueFor(input).enqueue({\n projectId: input.projectId,\n kind: 'codegraph-refresh',\n dedupeKey: 'codegraph-refresh',\n payload: {\n source: input.source,\n ...(input.maxFiles ? { maxFiles: input.maxFiles } : {}),\n },\n });\n}\n\n/**\n * Requalification is owned by one job per project, never by an individual\n * snapshot. A newer refresh replaces the snapshot metadata before it runs.\n */\nexport function enqueueClaimRequalification(input: {\n dataDir: string;\n projectId: string;\n source: string;\n snapshotId?: string;\n queue?: MaintenanceQueue;\n}): void {\n queueFor(input).enqueue({\n projectId: input.projectId,\n kind: 'claim-requalification',\n dedupeKey: 'claim-requalification',\n payload: {\n source: input.source,\n ...(input.snapshotId ? { snapshotId: input.snapshotId } : {}),\n },\n });\n}\n\n/** A stored explicit/Git observation earns a recoverable claim derivation. */\nexport function enqueueClaimDerivation(input: {\n dataDir: string;\n projectId: string;\n observationId: number;\n queue?: MaintenanceQueue;\n}): void {\n queueFor(input).enqueue({\n projectId: input.projectId,\n kind: 'claim-derive',\n dedupeKey: 'claim-derive:' + input.observationId,\n payload: { observationId: input.observationId },\n });\n}\n\n/**\n * Automatic captures are initially only candidates. Qualification runs in the\n * durable maintenance lane after Code Memory has a chance to refresh.\n */\nexport function enqueueObservationQualification(input: {\n dataDir: string;\n projectId: string;\n source: string;\n queue?: MaintenanceQueue;\n}): void {\n queueFor(input).enqueue({\n projectId: input.projectId,\n kind: 'observation-qualify',\n dedupeKey: 'observation-qualify',\n payload: { source: input.source, limit: 100 },\n });\n}\n\n/**\n * The follow-up jobs operate on the same workspace the Workset reads: a\n * versioned workspace when present, otherwise the local workspace.\n */\nexport function enqueueKnowledgeFollowups(input: {\n dataDir: string;\n projectId: string;\n source: string;\n includeCompile?: boolean;\n workspaceMode?: 'local' | 'versioned';\n allowVersionedWrite?: boolean;\n queue?: MaintenanceQueue;\n}): void {\n const queue = queueFor(input);\n const payload = {\n source: input.source,\n ...(input.workspaceMode ? { workspaceMode: input.workspaceMode } : {}),\n ...(input.allowVersionedWrite ? { allowVersionedWrite: true } : {}),\n };\n if (input.includeCompile) {\n queue.enqueue({\n projectId: input.projectId,\n kind: 'knowledge-compile',\n dedupeKey: 'knowledge-compile',\n payload,\n });\n }\n queue.enqueue({\n projectId: input.projectId,\n kind: 'knowledge-lint',\n dedupeKey: 'knowledge-lint',\n payload,\n });\n queue.enqueue({\n projectId: input.projectId,\n kind: 'workflow-index',\n dedupeKey: 'workflow-index',\n payload,\n });\n}\n","import { createHash } from 'node:crypto';\n\nfunction digest(input: string): string {\n return createHash('sha256').update(input).digest('hex').slice(0, 16);\n}\n\nexport function normalizeCodePath(path: string): string {\n return path.replace(/\\\\/g, '/').replace(/^\\.\\//, '').replace(/\\/+/g, '/');\n}\n\nexport function makeCodeFileId(projectId: string, path: string): string {\n return `file:${digest(`${projectId}\\n${normalizeCodePath(path)}`)}`;\n}\n\nexport function makeCodeSymbolId(input: {\n projectId: string;\n path: string;\n qualifiedName: string;\n kind: string;\n}): string {\n return `symbol:${digest([\n input.projectId,\n normalizeCodePath(input.path),\n input.qualifiedName,\n input.kind,\n ].join('\\n'))}`;\n}\n\nexport function makeCodeEdgeId(projectId: string, from: string, type: string, to: string): string {\n return `edge:${digest([projectId, from, type, to].join('\\n'))}`;\n}\n\nexport function makeObservationCodeRefId(projectId: string, observationId: number, fileId?: string, symbolId?: string): string {\n return `coderef:${digest([projectId, String(observationId), fileId ?? '', symbolId ?? ''].join('\\n'))}`;\n}\n","import { randomUUID } from 'node:crypto';\nimport { getDatabase } from '../store/sqlite-db.js';\nimport type {\n CodeEdge,\n CodeFile,\n CodeGraphStatus,\n CodeStateScanCompleteness,\n CodeStateSnapshot,\n CodeStateSnapshotInput,\n CodeSymbol,\n ObservationCodeRef,\n} from './types.js';\nimport { normalizeCodePath } from './ids.js';\n\nexport interface CodeGraphFileDelta {\n file: CodeFile;\n symbols: CodeSymbol[];\n edges: CodeEdge[];\n}\n\nfunction rowToFile(row: any): CodeFile {\n return {\n id: row.id,\n projectId: row.projectId,\n path: row.path,\n ...(row.language ? { language: row.language } : {}),\n contentHash: row.contentHash,\n ...(row.mtimeMs != null ? { mtimeMs: row.mtimeMs } : {}),\n ...(row.sizeBytes != null ? { sizeBytes: row.sizeBytes } : {}),\n indexedAt: row.indexedAt,\n ...(row.gitCommit ? { gitCommit: row.gitCommit } : {}),\n ...(row.snapshotId ? { snapshotId: row.snapshotId } : {}),\n ...(row.sourceEpoch != null ? { sourceEpoch: Number(row.sourceEpoch) } : {}),\n };\n}\n\nfunction rowToSymbol(row: any): CodeSymbol {\n return {\n id: row.id,\n projectId: row.projectId,\n fileId: row.fileId,\n path: row.path,\n name: row.name,\n qualifiedName: row.qualifiedName,\n kind: row.kind,\n ...(row.startLine != null ? { startLine: row.startLine } : {}),\n ...(row.endLine != null ? { endLine: row.endLine } : {}),\n ...(row.signature ? { signature: row.signature } : {}),\n ...(row.contentHash ? { contentHash: row.contentHash } : {}),\n indexedAt: row.indexedAt,\n stale: !!row.stale,\n ...(row.snapshotId ? { snapshotId: row.snapshotId } : {}),\n ...(row.sourceEpoch != null ? { sourceEpoch: Number(row.sourceEpoch) } : {}),\n } as CodeSymbol;\n}\n\nfunction rowToEdge(row: any): CodeEdge {\n return {\n id: row.id,\n projectId: row.projectId,\n ...(row.fromSymbolId ? { fromSymbolId: row.fromSymbolId } : {}),\n ...(row.toSymbolId ? { toSymbolId: row.toSymbolId } : {}),\n ...(row.fromFileId ? { fromFileId: row.fromFileId } : {}),\n ...(row.toFileId ? { toFileId: row.toFileId } : {}),\n type: row.type,\n confidence: row.confidence,\n ...(row.evidence ? { evidence: row.evidence } : {}),\n indexedAt: row.indexedAt,\n ...(row.snapshotId ? { snapshotId: row.snapshotId } : {}),\n ...(row.sourceEpoch != null ? { sourceEpoch: Number(row.sourceEpoch) } : {}),\n } as CodeEdge;\n}\n\nfunction rowToRef(row: any): ObservationCodeRef {\n return {\n id: row.id,\n projectId: row.projectId,\n observationId: row.observationId,\n ...(row.fileId ? { fileId: row.fileId } : {}),\n ...(row.symbolId ? { symbolId: row.symbolId } : {}),\n ...(row.capturedFileHash ? { capturedFileHash: row.capturedFileHash } : {}),\n ...(row.capturedSymbolHash ? { capturedSymbolHash: row.capturedSymbolHash } : {}),\n status: row.status,\n ...(row.reason ? { reason: row.reason } : {}),\n createdAt: row.createdAt,\n ...(row.updatedAt ? { updatedAt: row.updatedAt } : {}),\n ...(row.snapshotId ? { snapshotId: row.snapshotId } : {}),\n } as ObservationCodeRef;\n}\n\nfunction parseCompleteness(raw: unknown): CodeStateScanCompleteness {\n try {\n const parsed = typeof raw === 'string' ? JSON.parse(raw) : raw;\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) throw new Error('invalid completeness');\n return {\n scannedFiles: Number((parsed as any).scannedFiles) || 0,\n maxFiles: Number((parsed as any).maxFiles) || 0,\n changedFiles: Number((parsed as any).changedFiles) || 0,\n unchangedFiles: Number((parsed as any).unchangedFiles) || 0,\n metadataOnlyFiles: Number((parsed as any).metadataOnlyFiles) || 0,\n removedFiles: Number((parsed as any).removedFiles) || 0,\n skippedOversizedFiles: Number((parsed as any).skippedOversizedFiles) || 0,\n unreadableFiles: Number((parsed as any).unreadableFiles) || 0,\n removalScanDeferred: Boolean((parsed as any).removalScanDeferred),\n };\n } catch {\n return {\n scannedFiles: 0,\n maxFiles: 0,\n changedFiles: 0,\n unchangedFiles: 0,\n metadataOnlyFiles: 0,\n removedFiles: 0,\n skippedOversizedFiles: 0,\n unreadableFiles: 0,\n removalScanDeferred: false,\n };\n }\n}\n\nfunction rowToSnapshot(row: any): CodeStateSnapshot {\n return {\n id: row.id,\n projectId: row.projectId,\n provider: row.provider,\n ...(row.baseRevision ? { baseRevision: row.baseRevision } : {}),\n worktreeFingerprint: row.worktreeFingerprint,\n worktreeState: row.worktreeState,\n changedPathCount: Number(row.changedPathCount),\n indexedAt: row.indexedAt,\n sourceEpoch: Number(row.sourceEpoch),\n completeness: parseCompleteness(row.completenessJson),\n ...(row.previousSnapshotId ? { previousSnapshotId: row.previousSnapshotId } : {}),\n } as CodeStateSnapshot;\n}\n\nexport class CodeGraphStore {\n private db: any = null;\n private dataDir: string | null = null;\n\n async init(dataDir: string): Promise<void> {\n this.dataDir = dataDir;\n this.db = getDatabase(dataDir);\n }\n\n /** Data directory shared with the rest of the local project evidence stores. */\n getDataDir(): string {\n if (!this.dataDir) throw new Error('CodeGraphStore is not initialized');\n return this.dataDir;\n }\n\n upsertFiles(files: CodeFile[]): void {\n if (files.length === 0) return;\n const stmt = this.db.prepare(`\n INSERT OR REPLACE INTO code_files\n (id, projectId, path, language, contentHash, mtimeMs, sizeBytes, indexedAt, gitCommit)\n VALUES\n (@id, @projectId, @path, @language, @contentHash, @mtimeMs, @sizeBytes, @indexedAt, @gitCommit)\n `);\n const tx = this.db.transaction((items: CodeFile[]) => {\n for (const file of items) {\n stmt.run({\n id: file.id,\n projectId: file.projectId,\n path: normalizeCodePath(file.path),\n language: file.language ?? null,\n contentHash: file.contentHash,\n mtimeMs: file.mtimeMs ?? null,\n sizeBytes: file.sizeBytes ?? null,\n indexedAt: file.indexedAt,\n gitCommit: file.gitCommit ?? null,\n });\n }\n });\n tx(files);\n }\n\n upsertSymbols(symbols: CodeSymbol[]): void {\n if (symbols.length === 0) return;\n const stmt = this.db.prepare(`\n INSERT OR REPLACE INTO code_symbols\n (id, projectId, fileId, path, name, qualifiedName, kind, startLine, endLine, signature, contentHash, indexedAt, stale)\n VALUES\n (@id, @projectId, @fileId, @path, @name, @qualifiedName, @kind, @startLine, @endLine, @signature, @contentHash, @indexedAt, @stale)\n `);\n const tx = this.db.transaction((items: CodeSymbol[]) => {\n for (const symbol of items) {\n stmt.run({\n id: symbol.id,\n projectId: symbol.projectId,\n fileId: symbol.fileId,\n path: normalizeCodePath(symbol.path),\n name: symbol.name,\n qualifiedName: symbol.qualifiedName,\n kind: symbol.kind,\n startLine: symbol.startLine ?? null,\n endLine: symbol.endLine ?? null,\n signature: symbol.signature ?? null,\n contentHash: symbol.contentHash ?? null,\n indexedAt: symbol.indexedAt,\n stale: symbol.stale ? 1 : 0,\n });\n }\n });\n tx(symbols);\n }\n\n upsertEdges(edges: CodeEdge[]): void {\n if (edges.length === 0) return;\n const stmt = this.db.prepare(`\n INSERT OR REPLACE INTO code_edges\n (id, projectId, fromSymbolId, toSymbolId, fromFileId, toFileId, type, confidence, evidence, indexedAt)\n VALUES\n (@id, @projectId, @fromSymbolId, @toSymbolId, @fromFileId, @toFileId, @type, @confidence, @evidence, @indexedAt)\n `);\n const tx = this.db.transaction((items: CodeEdge[]) => {\n for (const edge of items) {\n stmt.run({\n id: edge.id,\n projectId: edge.projectId,\n fromSymbolId: edge.fromSymbolId ?? null,\n toSymbolId: edge.toSymbolId ?? null,\n fromFileId: edge.fromFileId ?? null,\n toFileId: edge.toFileId ?? null,\n type: edge.type,\n confidence: edge.confidence,\n evidence: edge.evidence ?? null,\n indexedAt: edge.indexedAt,\n });\n }\n });\n tx(edges);\n }\n\n replaceProjectIndex(\n projectId: string,\n index: { files: CodeFile[]; symbols: CodeSymbol[]; edges: CodeEdge[] },\n ): void {\n const deleteEdges = this.db.prepare(`DELETE FROM code_edges WHERE projectId = ?`);\n const staleSymbols = this.db.prepare(`UPDATE code_symbols SET stale = 1 WHERE projectId = ?`);\n const deleteFiles = this.db.prepare(`DELETE FROM code_files WHERE projectId = ?`);\n const insertFile = this.db.prepare(`\n INSERT OR REPLACE INTO code_files\n (id, projectId, path, language, contentHash, mtimeMs, sizeBytes, indexedAt, gitCommit)\n VALUES\n (@id, @projectId, @path, @language, @contentHash, @mtimeMs, @sizeBytes, @indexedAt, @gitCommit)\n `);\n const insertSymbol = this.db.prepare(`\n INSERT OR REPLACE INTO code_symbols\n (id, projectId, fileId, path, name, qualifiedName, kind, startLine, endLine, signature, contentHash, indexedAt, stale)\n VALUES\n (@id, @projectId, @fileId, @path, @name, @qualifiedName, @kind, @startLine, @endLine, @signature, @contentHash, @indexedAt, @stale)\n `);\n const insertEdge = this.db.prepare(`\n INSERT OR REPLACE INTO code_edges\n (id, projectId, fromSymbolId, toSymbolId, fromFileId, toFileId, type, confidence, evidence, indexedAt)\n VALUES\n (@id, @projectId, @fromSymbolId, @toSymbolId, @fromFileId, @toFileId, @type, @confidence, @evidence, @indexedAt)\n `);\n\n const tx = this.db.transaction(() => {\n deleteEdges.run(projectId);\n staleSymbols.run(projectId);\n deleteFiles.run(projectId);\n\n for (const file of index.files) {\n insertFile.run({\n id: file.id,\n projectId: file.projectId,\n path: normalizeCodePath(file.path),\n language: file.language ?? null,\n contentHash: file.contentHash,\n mtimeMs: file.mtimeMs ?? null,\n sizeBytes: file.sizeBytes ?? null,\n indexedAt: file.indexedAt,\n gitCommit: file.gitCommit ?? null,\n });\n }\n\n for (const symbol of index.symbols) {\n insertSymbol.run({\n id: symbol.id,\n projectId: symbol.projectId,\n fileId: symbol.fileId,\n path: normalizeCodePath(symbol.path),\n name: symbol.name,\n qualifiedName: symbol.qualifiedName,\n kind: symbol.kind,\n startLine: symbol.startLine ?? null,\n endLine: symbol.endLine ?? null,\n signature: symbol.signature ?? null,\n contentHash: symbol.contentHash ?? null,\n indexedAt: symbol.indexedAt,\n stale: 0,\n });\n }\n\n for (const edge of index.edges) {\n insertEdge.run({\n id: edge.id,\n projectId: edge.projectId,\n fromSymbolId: edge.fromSymbolId ?? null,\n toSymbolId: edge.toSymbolId ?? null,\n fromFileId: edge.fromFileId ?? null,\n toFileId: edge.toFileId ?? null,\n type: edge.type,\n confidence: edge.confidence,\n evidence: edge.evidence ?? null,\n indexedAt: edge.indexedAt,\n });\n }\n });\n\n tx();\n }\n\n /**\n * Reconcile only files whose source changed plus files that disappeared.\n * Refs tied to replaced sources become stale instead of being silently kept.\n */\n applyFileDeltas(\n projectId: string,\n input: {\n changed: CodeGraphFileDelta[];\n metadataOnly?: CodeFile[];\n removedFileIds?: string[];\n },\n ): void {\n const changed = input.changed.filter((delta) => delta.file.projectId === projectId);\n const metadataOnly = (input.metadataOnly ?? []).filter((file) => file.projectId === projectId);\n const removedFileIds = input.removedFileIds ?? [];\n if (changed.length === 0 && metadataOnly.length === 0 && removedFileIds.length === 0) return;\n\n const staleRefsForFile = this.db.prepare(`\n UPDATE observation_code_refs\n SET status = 'stale', updatedAt = ?\n WHERE projectId = ? AND (\n fileId = ? OR symbolId IN (\n SELECT id FROM code_symbols WHERE projectId = ? AND fileId = ?\n )\n )\n `);\n const deleteEdgesForFile = this.db.prepare(`\n DELETE FROM code_edges\n WHERE projectId = ? AND (fromFileId = ? OR toFileId = ?)\n `);\n const deleteSymbolsForFile = this.db.prepare(`DELETE FROM code_symbols WHERE projectId = ? AND fileId = ?`);\n const deleteFile = this.db.prepare(`DELETE FROM code_files WHERE projectId = ? AND id = ?`);\n const upsertFile = this.db.prepare(`\n INSERT OR REPLACE INTO code_files\n (id, projectId, path, language, contentHash, mtimeMs, sizeBytes, indexedAt, gitCommit)\n VALUES\n (@id, @projectId, @path, @language, @contentHash, @mtimeMs, @sizeBytes, @indexedAt, @gitCommit)\n `);\n const upsertSymbol = this.db.prepare(`\n INSERT OR REPLACE INTO code_symbols\n (id, projectId, fileId, path, name, qualifiedName, kind, startLine, endLine, signature, contentHash, indexedAt, stale)\n VALUES\n (@id, @projectId, @fileId, @path, @name, @qualifiedName, @kind, @startLine, @endLine, @signature, @contentHash, @indexedAt, @stale)\n `);\n const upsertEdge = this.db.prepare(`\n INSERT OR REPLACE INTO code_edges\n (id, projectId, fromSymbolId, toSymbolId, fromFileId, toFileId, type, confidence, evidence, indexedAt)\n VALUES\n (@id, @projectId, @fromSymbolId, @toSymbolId, @fromFileId, @toFileId, @type, @confidence, @evidence, @indexedAt)\n `);\n const writeFile = (file: CodeFile) => upsertFile.run({\n id: file.id,\n projectId: file.projectId,\n path: normalizeCodePath(file.path),\n language: file.language ?? null,\n contentHash: file.contentHash,\n mtimeMs: file.mtimeMs ?? null,\n sizeBytes: file.sizeBytes ?? null,\n indexedAt: file.indexedAt,\n gitCommit: file.gitCommit ?? null,\n });\n\n const tx = this.db.transaction(() => {\n const staleAt = new Date().toISOString();\n for (const fileId of removedFileIds) {\n staleRefsForFile.run(staleAt, projectId, fileId, projectId, fileId);\n deleteEdgesForFile.run(projectId, fileId, fileId);\n deleteSymbolsForFile.run(projectId, fileId);\n deleteFile.run(projectId, fileId);\n }\n\n for (const delta of changed) {\n const fileId = delta.file.id;\n staleRefsForFile.run(staleAt, projectId, fileId, projectId, fileId);\n deleteEdgesForFile.run(projectId, fileId, fileId);\n deleteSymbolsForFile.run(projectId, fileId);\n writeFile(delta.file);\n\n for (const symbol of delta.symbols) {\n upsertSymbol.run({\n id: symbol.id,\n projectId: symbol.projectId,\n fileId: symbol.fileId,\n path: normalizeCodePath(symbol.path),\n name: symbol.name,\n qualifiedName: symbol.qualifiedName,\n kind: symbol.kind,\n startLine: symbol.startLine ?? null,\n endLine: symbol.endLine ?? null,\n signature: symbol.signature ?? null,\n contentHash: symbol.contentHash ?? null,\n indexedAt: symbol.indexedAt,\n stale: symbol.stale ? 1 : 0,\n });\n }\n\n for (const edge of delta.edges) {\n upsertEdge.run({\n id: edge.id,\n projectId: edge.projectId,\n fromSymbolId: edge.fromSymbolId ?? null,\n toSymbolId: edge.toSymbolId ?? null,\n fromFileId: edge.fromFileId ?? null,\n toFileId: edge.toFileId ?? null,\n type: edge.type,\n confidence: edge.confidence,\n evidence: edge.evidence ?? null,\n indexedAt: edge.indexedAt,\n });\n }\n }\n\n for (const file of metadataOnly) writeFile(file);\n });\n tx();\n }\n\n upsertObservationRefs(refs: ObservationCodeRef[]): void {\n if (refs.length === 0) return;\n const stmt = this.db.prepare(`\n INSERT OR REPLACE INTO observation_code_refs\n (id, projectId, observationId, fileId, symbolId, capturedFileHash, capturedSymbolHash, status, reason, createdAt, updatedAt, snapshotId)\n VALUES\n (@id, @projectId, @observationId, @fileId, @symbolId, @capturedFileHash, @capturedSymbolHash, @status, @reason, @createdAt, @updatedAt, @snapshotId)\n `);\n const tx = this.db.transaction((items: ObservationCodeRef[]) => {\n for (const ref of items) {\n stmt.run({\n id: ref.id,\n projectId: ref.projectId,\n observationId: ref.observationId,\n fileId: ref.fileId ?? null,\n symbolId: ref.symbolId ?? null,\n capturedFileHash: ref.capturedFileHash ?? null,\n capturedSymbolHash: ref.capturedSymbolHash ?? null,\n status: ref.status,\n reason: ref.reason ?? null,\n createdAt: ref.createdAt,\n updatedAt: ref.updatedAt ?? null,\n snapshotId: ref.snapshotId ?? this.latestSnapshot(ref.projectId)?.id ?? null,\n });\n }\n });\n tx(refs);\n }\n\n replaceObservationRefs(projectId: string, observationId: number, refs: ObservationCodeRef[]): void {\n const deleteRefs = this.db.prepare(`\n DELETE FROM observation_code_refs\n WHERE projectId = ? AND observationId = ?\n `);\n const insertRef = this.db.prepare(`\n INSERT OR REPLACE INTO observation_code_refs\n (id, projectId, observationId, fileId, symbolId, capturedFileHash, capturedSymbolHash, status, reason, createdAt, updatedAt, snapshotId)\n VALUES\n (@id, @projectId, @observationId, @fileId, @symbolId, @capturedFileHash, @capturedSymbolHash, @status, @reason, @createdAt, @updatedAt, @snapshotId)\n `);\n const tx = this.db.transaction(() => {\n deleteRefs.run(projectId, observationId);\n for (const ref of refs) {\n insertRef.run({\n id: ref.id,\n projectId: ref.projectId,\n observationId: ref.observationId,\n fileId: ref.fileId ?? null,\n symbolId: ref.symbolId ?? null,\n capturedFileHash: ref.capturedFileHash ?? null,\n capturedSymbolHash: ref.capturedSymbolHash ?? null,\n status: ref.status,\n reason: ref.reason ?? null,\n createdAt: ref.createdAt,\n updatedAt: ref.updatedAt ?? null,\n snapshotId: ref.snapshotId ?? this.latestSnapshot(ref.projectId)?.id ?? null,\n });\n }\n });\n tx();\n }\n\n getFile(projectId: string, path: string): CodeFile | null {\n const row = this.db.prepare(`SELECT * FROM code_files WHERE projectId = ? AND path = ?`).get(projectId, normalizeCodePath(path));\n return row ? rowToFile(row) : null;\n }\n\n listFiles(projectId: string): CodeFile[] {\n return this.db.prepare(`SELECT * FROM code_files WHERE projectId = ? ORDER BY path`).all(projectId).map(rowToFile);\n }\n\n findSymbols(projectId: string, query: string, limit = 20): CodeSymbol[] {\n const like = `%${query.trim()}%`;\n return this.db.prepare(`\n SELECT * FROM code_symbols\n WHERE projectId = ? AND stale = 0 AND (name LIKE ? OR qualifiedName LIKE ? OR path LIKE ?)\n ORDER BY path, startLine\n LIMIT ?\n `).all(projectId, like, like, like, limit).map(rowToSymbol);\n }\n\n listSymbols(projectId: string): CodeSymbol[] {\n return this.db.prepare(`\n SELECT * FROM code_symbols\n WHERE projectId = ? AND stale = 0\n ORDER BY path, startLine\n `).all(projectId).map(rowToSymbol);\n }\n\n findSymbolsByNames(projectId: string, names: string[], fileIds: string[] = []): CodeSymbol[] {\n const candidates = [...new Set(names.map(name => name.trim()).filter(Boolean))];\n if (candidates.length === 0) return [];\n const candidateJson = JSON.stringify(candidates);\n const hintedFiles = [...new Set(fileIds.map(fileId => fileId.trim()).filter(Boolean))];\n if (hintedFiles.length > 0) {\n return this.db.prepare(`\n SELECT * FROM code_symbols\n WHERE projectId = ?\n AND stale = 0\n AND name IN (SELECT value FROM json_each(?))\n AND fileId IN (SELECT value FROM json_each(?))\n ORDER BY path, startLine\n `).all(projectId, candidateJson, JSON.stringify(hintedFiles)).map(rowToSymbol);\n }\n\n return this.db.prepare(`\n SELECT symbols.*\n FROM code_symbols AS symbols\n INNER JOIN (\n SELECT name\n FROM code_symbols\n WHERE projectId = ?\n AND stale = 0\n AND name IN (SELECT value FROM json_each(?))\n GROUP BY name\n HAVING COUNT(*) = 1\n ) AS unambiguous ON unambiguous.name = symbols.name\n WHERE symbols.projectId = ? AND symbols.stale = 0\n ORDER BY symbols.path, symbols.startLine\n `).all(projectId, candidateJson, projectId).map(rowToSymbol);\n }\n\n listSymbolsForFile(fileId: string): CodeSymbol[] {\n return this.db.prepare(`SELECT * FROM code_symbols WHERE fileId = ? AND stale = 0 ORDER BY startLine`).all(fileId).map(rowToSymbol);\n }\n\n listEdges(projectId: string): CodeEdge[] {\n return this.db.prepare(`SELECT * FROM code_edges WHERE projectId = ? ORDER BY type, id`).all(projectId).map(rowToEdge);\n }\n\n listObservationRefs(projectId: string, observationId: number): ObservationCodeRef[] {\n return this.db.prepare(`\n SELECT * FROM observation_code_refs\n WHERE projectId = ? AND observationId = ?\n ORDER BY status, id\n `).all(projectId, observationId).map(rowToRef);\n }\n\n listProjectObservationRefs(projectId: string): ObservationCodeRef[] {\n return this.db.prepare(`\n SELECT * FROM observation_code_refs\n WHERE projectId = ?\n ORDER BY observationId, status, id\n `).all(projectId).map(rowToRef);\n }\n\n listReferencedSymbols(projectId: string): CodeSymbol[] {\n return this.db.prepare(`\n SELECT DISTINCT symbols.*\n FROM code_symbols AS symbols\n INNER JOIN observation_code_refs AS refs ON refs.symbolId = symbols.id\n WHERE refs.projectId = ? AND symbols.projectId = ? AND symbols.stale = 0\n ORDER BY symbols.path, symbols.startLine\n `).all(projectId, projectId).map(rowToSymbol);\n }\n\n latestSnapshot(projectId: string): CodeStateSnapshot | undefined {\n const row = this.db.prepare(\n 'SELECT * FROM code_state_snapshots WHERE projectId = ? ORDER BY sourceEpoch DESC LIMIT 1',\n ).get(projectId);\n return row ? rowToSnapshot(row) : undefined;\n }\n\n listSnapshots(projectId: string, limit = 20): CodeStateSnapshot[] {\n const safeLimit = Number.isFinite(limit) ? Math.max(1, Math.min(200, Math.floor(limit))) : 20;\n return this.db.prepare(\n 'SELECT * FROM code_state_snapshots WHERE projectId = ? ORDER BY sourceEpoch DESC LIMIT ?',\n ).all(projectId, safeLimit).map(rowToSnapshot);\n }\n\n /**\n * Record a completed scan and mark all current structural facts with its\n * epoch. The snapshot is written only after refresh reconciliation succeeds,\n * so an interrupted scan cannot be advertised as complete.\n */\n recordCodeStateSnapshot(input: CodeStateSnapshotInput): CodeStateSnapshot {\n const id = randomUUID();\n let snapshot: CodeStateSnapshot | undefined;\n const tx = this.db.transaction(() => {\n const previous = this.db.prepare(\n 'SELECT id, sourceEpoch FROM code_state_snapshots WHERE projectId = ? ORDER BY sourceEpoch DESC LIMIT 1',\n ).get(input.projectId);\n const sourceEpoch = Number(previous?.sourceEpoch ?? 0) + 1;\n const previousSnapshotId = previous?.id as string | undefined;\n this.db.prepare(\n 'INSERT INTO code_state_snapshots (id, projectId, provider, baseRevision, worktreeFingerprint, worktreeState, changedPathCount, indexedAt, sourceEpoch, completenessJson, previousSnapshotId) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)',\n ).run(\n id,\n input.projectId,\n input.provider,\n input.baseRevision ?? null,\n input.worktreeFingerprint,\n input.worktreeState,\n input.changedPathCount,\n input.indexedAt,\n sourceEpoch,\n JSON.stringify(input.completeness),\n previousSnapshotId ?? null,\n );\n this.db.prepare(\n 'UPDATE code_files SET snapshotId = ?, sourceEpoch = ?, gitCommit = COALESCE(?, gitCommit) WHERE projectId = ?',\n ).run(id, sourceEpoch, input.baseRevision ?? null, input.projectId);\n this.db.prepare(\n 'UPDATE code_symbols SET snapshotId = ?, sourceEpoch = ? WHERE projectId = ? AND stale = 0',\n ).run(id, sourceEpoch, input.projectId);\n this.db.prepare(\n 'UPDATE code_edges SET snapshotId = ?, sourceEpoch = ? WHERE projectId = ?',\n ).run(id, sourceEpoch, input.projectId);\n this.db.prepare(\n \"UPDATE observation_code_refs SET snapshotId = ? WHERE projectId = ? AND status = 'current'\",\n ).run(id, input.projectId);\n snapshot = {\n ...input,\n id,\n sourceEpoch,\n ...(previousSnapshotId ? { previousSnapshotId } : {}),\n };\n });\n tx();\n return snapshot!;\n }\n\n status(projectId: string): CodeGraphStatus {\n const files = this.db.prepare(`SELECT COUNT(*) AS count FROM code_files WHERE projectId = ?`).get(projectId).count;\n const symbols = this.db.prepare(`SELECT COUNT(*) AS count FROM code_symbols WHERE projectId = ? AND stale = 0`).get(projectId).count;\n const edges = this.db.prepare(`SELECT COUNT(*) AS count FROM code_edges WHERE projectId = ?`).get(projectId).count;\n const refs = this.db.prepare(`SELECT COUNT(*) AS count FROM observation_code_refs WHERE projectId = ?`).get(projectId).count;\n const latest = this.db.prepare(`SELECT MAX(indexedAt) AS indexedAt FROM code_files WHERE projectId = ?`).get(projectId);\n const latestSnapshot = this.latestSnapshot(projectId);\n return {\n provider: 'lite',\n files,\n symbols,\n edges,\n refs,\n ...(latest?.indexedAt ? { indexedAt: latest.indexedAt } : {}),\n ...(latestSnapshot ? { latestSnapshot } : {}),\n };\n }\n}\n","import type { CodeFile, CodeSymbol, ObservationCodeRef } from './types.js';\nimport { makeObservationCodeRefId, normalizeCodePath } from './ids.js';\nimport type { CodeGraphStore } from './store.js';\n\nexport interface BindableObservation {\n id: number;\n projectId: string;\n title: string;\n narrative: string;\n facts?: string[];\n filesModified?: string[];\n createdAt: string;\n}\n\nexport interface CodeRefBackfillResult {\n observationsScanned: number;\n observationsBackfilled: number;\n refsBackfilled: number;\n}\n\nfunction observationText(obs: BindableObservation): string {\n return [obs.title, obs.narrative, ...(obs.facts ?? [])].join('\\n');\n}\n\nfunction mentionsSymbol(text: string, symbol: CodeSymbol): boolean {\n const name = symbol.name.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n return new RegExp(`(^|[^\\\\w$])${name}([^\\\\w$]|$)`).test(text);\n}\n\nfunction identifierCandidates(text: string): string[] {\n return [...new Set(text.match(/[A-Za-z_$][\\w$]*(?:::[A-Za-z_$][\\w$]*)*[!?=]?/g) ?? [])];\n}\n\nfunction codeIdentifierCandidates(text: string): string[] {\n const explicit = new Set<string>();\n for (const match of text.matchAll(/`([A-Za-z_$][\\w$]*(?:::[A-Za-z_$][\\w$]*)*[!?=]?)`/g)) explicit.add(match[1]);\n for (const match of text.matchAll(/\\b([A-Za-z_$][\\w$]*(?:::[A-Za-z_$][\\w$]*)*[!?=]?)\\s*\\(/g)) explicit.add(match[1]);\n return identifierCandidates(text).filter(candidate =>\n explicit.has(candidate) ||\n candidate.includes('::') ||\n /[!?=]$/.test(candidate) ||\n /^[A-Z]/.test(candidate) ||\n /[_$]/.test(candidate) ||\n /[a-z0-9][A-Z]/.test(candidate) ||\n /[A-Z]{2}/.test(candidate));\n}\n\nfunction fileRef(projectId: string, obs: BindableObservation, file: CodeFile): ObservationCodeRef {\n return {\n id: makeObservationCodeRefId(projectId, obs.id, file.id),\n projectId,\n observationId: obs.id,\n fileId: file.id,\n capturedFileHash: file.contentHash,\n status: 'current',\n reason: 'bound by file path',\n createdAt: obs.createdAt,\n };\n}\n\nfunction symbolRef(projectId: string, obs: BindableObservation, file: CodeFile, symbol: CodeSymbol): ObservationCodeRef {\n return {\n id: makeObservationCodeRefId(projectId, obs.id, file.id, symbol.id),\n projectId,\n observationId: obs.id,\n fileId: file.id,\n symbolId: symbol.id,\n capturedFileHash: file.contentHash,\n ...(symbol.contentHash ? { capturedSymbolHash: symbol.contentHash } : {}),\n status: 'current',\n reason: 'bound by symbol mention',\n createdAt: obs.createdAt,\n };\n}\n\ninterface CodeBindingLookup {\n findFile(path: string): CodeFile | undefined;\n findSymbols(names: string[], hintedFileIds: string[]): CodeSymbol[];\n}\n\nfunction resolveObservationCodeRefs(\n obs: BindableObservation,\n lookup: CodeBindingLookup,\n): ObservationCodeRef[] {\n const refs = new Map<string, ObservationCodeRef>();\n const text = observationText(obs);\n const candidateFiles = new Map<string, CodeFile>();\n\n for (const rawPath of obs.filesModified ?? []) {\n const file = lookup.findFile(normalizeCodePath(rawPath));\n if (!file) continue;\n candidateFiles.set(file.id, file);\n const ref = fileRef(obs.projectId, obs, file);\n refs.set(ref.id, ref);\n }\n\n const hintedFileIds = new Set(candidateFiles.keys());\n const symbolNames = hintedFileIds.size > 0 ? identifierCandidates(text) : codeIdentifierCandidates(text);\n const symbols = lookup.findSymbols(symbolNames, [...hintedFileIds]);\n const symbolsByName = new Map<string, CodeSymbol[]>();\n for (const symbol of symbols) {\n const group = symbolsByName.get(symbol.name) ?? [];\n group.push(symbol);\n symbolsByName.set(symbol.name, group);\n }\n\n for (const group of symbolsByName.values()) {\n const candidates = group.length === 1 ? group : [];\n for (const symbol of candidates) {\n if (!mentionsSymbol(text, symbol)) continue;\n const file = candidateFiles.get(symbol.fileId) ?? lookup.findFile(symbol.path);\n if (!file) continue;\n candidateFiles.set(file.id, file);\n const ref = symbolRef(obs.projectId, obs, file, symbol);\n refs.set(ref.id, ref);\n }\n }\n\n return [...refs.values()];\n}\n\nfunction createStoreLookup(store: CodeGraphStore, projectId: string): CodeBindingLookup {\n return {\n findFile: path => store.getFile(projectId, path) ?? undefined,\n findSymbols: (names, hintedFileIds) => store.findSymbolsByNames(projectId, names, hintedFileIds),\n };\n}\n\nfunction createSnapshotLookup(files: CodeFile[], symbols: CodeSymbol[]): CodeBindingLookup {\n const filesByPath = new Map(files.map(file => [normalizeCodePath(file.path), file]));\n const symbolsByName = new Map<string, CodeSymbol[]>();\n for (const symbol of symbols) {\n const group = symbolsByName.get(symbol.name) ?? [];\n group.push(symbol);\n symbolsByName.set(symbol.name, group);\n }\n\n return {\n findFile: path => filesByPath.get(normalizeCodePath(path)),\n findSymbols: (names, hintedFileIds) => {\n const hinted = new Set(hintedFileIds);\n const found: CodeSymbol[] = [];\n for (const name of names) {\n const candidates = symbolsByName.get(name) ?? [];\n found.push(...(hinted.size > 0 ? candidates.filter(symbol => hinted.has(symbol.fileId)) : candidates));\n }\n return found;\n },\n };\n}\n\nexport async function bindObservationToCode(\n store: CodeGraphStore,\n obs: BindableObservation,\n): Promise<ObservationCodeRef[]> {\n const refs = resolveObservationCodeRefs(obs, createStoreLookup(store, obs.projectId));\n store.replaceObservationRefs(obs.projectId, obs.id, refs);\n return refs;\n}\n\nexport async function backfillMissingObservationCodeRefs(\n store: CodeGraphStore,\n observations: BindableObservation[],\n): Promise<CodeRefBackfillResult> {\n let observationsBackfilled = 0;\n let refsBackfilled = 0;\n const boundObservationIdsByProject = new Map<string, Set<number>>();\n const lookupByProject = new Map<string, CodeBindingLookup>();\n\n for (const projectId of new Set(observations.map(observation => observation.projectId))) {\n boundObservationIdsByProject.set(\n projectId,\n new Set(store.listProjectObservationRefs(projectId).map(ref => ref.observationId)),\n );\n lookupByProject.set(\n projectId,\n createSnapshotLookup(store.listFiles(projectId), store.listSymbols(projectId)),\n );\n }\n\n const refsToInsert: ObservationCodeRef[] = [];\n for (const observation of observations) {\n if (boundObservationIdsByProject.get(observation.projectId)?.has(observation.id)) continue;\n if ((observation.filesModified?.length ?? 0) === 0 && codeIdentifierCandidates(observationText(observation)).length === 0) {\n continue;\n }\n const lookup = lookupByProject.get(observation.projectId);\n if (!lookup) continue;\n const refs = resolveObservationCodeRefs(observation, lookup);\n if (refs.length === 0) continue;\n observationsBackfilled += 1;\n refsBackfilled += refs.length;\n refsToInsert.push(...refs);\n }\n store.upsertObservationRefs(refsToInsert);\n\n return {\n observationsScanned: observations.length,\n observationsBackfilled,\n refsBackfilled,\n };\n}\n","/**\n * Observations Manager\n *\n * Manages rich observation records with auto-classification and token counting.\n * Source: claude-mem's observation data model with structured fields.\n *\n * Each observation is stored both in the knowledge graph (as entity observation)\n * and in the Orama search index (for full-text + vector search).\n */\n\nimport type {\n Observation,\n ObservationAdmissionState,\n ObservationReader,\n ObservationVisibility,\n ObservationType,\n ObservationStatus,\n MemorixDocument,\n ProgressInfo,\n} from '../types.js';\nimport { TOPIC_KEY_FAMILIES } from '../types.js';\nimport {\n insertObservation,\n removeObservation,\n resetDb,\n generateEmbedding,\n batchGenerateEmbeddings,\n getDb,\n getDeferredCachedVectorHydration,\n getVectorDimensions,\n hydrateIndexForStartup,\n hasObservationVector,\n isEmbeddingEnabled,\n makeOramaObservationId,\n getLastSearchMode,\n searchObservations,\n updateObservationMetadata,\n} from '../store/orama-store.js';\nimport { getObservationStore, initObservationStore } from '../store/obs-store.js';\nimport { countTextTokens } from '../compact/token-budget.js';\nimport { extractEntities, enrichConcepts } from './entity-extractor.js';\nimport { getEmbeddingProvider, isEmbeddingExplicitlyDisabled } from '../embedding/provider.js';\nimport { sanitizeCredentials } from './secret-filter.js';\nimport { enqueueClaimDerivation, enqueueObservationQualification } from '../runtime/lifecycle.js';\nimport { canManageObservation, resolveObservationVisibility } from './visibility.js';\n\n/** In-memory observation list (loaded from persistence on init) */\nlet observations: Observation[] = [];\nlet nextId = 1;\nlet projectDir: string | null = null;\nlet searchIndexPrepared = false;\n\n// ── Vector-missing tracking ──────────────────────────────────────\n// Tracks observation IDs whose async embedding write failed or was skipped.\n// Enables observability (\"how many memories lack vectors?\") and backfill.\nconst vectorMissingIds = new Set<number>();\nlet vectorBackfillRunning = false;\nlet vectorSchemaUpgradePromise: Promise<boolean> | null = null;\nlet lastVectorBackfill: {\n attempted: number;\n succeeded: number;\n failed: number;\n lastError?: string;\n finishedAt: string;\n} | null = null;\nconst embeddingFailureLogTimestamps = new Map<string, number>();\nconst EMBEDDING_FAILURE_LOG_COOLDOWN_MS = 30_000;\n\nfunction logEmbeddingFailureOnce(key: string, message: string): void {\n const now = Date.now();\n const last = embeddingFailureLogTimestamps.get(key) ?? 0;\n if (now - last < EMBEDDING_FAILURE_LOG_COOLDOWN_MS) return;\n embeddingFailureLogTimestamps.set(key, now);\n console.error(message);\n}\n\nfunction normalizeEmbeddingFailure(error: unknown): { key: string; message: string } {\n const raw = error instanceof Error ? error.message : String(error);\n\n if (\n /embedding api error \\(401\\)/i.test(raw) ||\n /invalid_api_key/i.test(raw) ||\n /incorrect api key/i.test(raw) ||\n /unauthorized/i.test(raw)\n ) {\n return {\n key: 'embedding-auth',\n message: 'Embedding API returned an invalid API key response; using BM25 until embedding recovers',\n };\n }\n\n if (/embedding api timeout/i.test(raw)) {\n return {\n key: 'embedding-timeout',\n message: 'Embedding API timed out; using BM25 until embedding recovers',\n };\n }\n\n return {\n key: raw,\n message: raw,\n };\n}\n\nfunction queueVectorBackfill(projectId: string): void {\n const dataDir = projectDir;\n if (!dataDir) return;\n void import('../runtime/maintenance-jobs.js')\n .then(({ MaintenanceJobStore }) => {\n new MaintenanceJobStore(dataDir).enqueue({\n projectId,\n kind: 'vector-backfill',\n dedupeKey: 'vector-backfill',\n payload: { limit: 12 },\n });\n })\n .catch(() => {\n // Memory writes remain durable even when the optional maintenance queue is unavailable.\n });\n}\n\nasync function bindObservationCodeRefsBestEffort(observation: Observation): Promise<void> {\n if (!projectDir) return;\n try {\n const { CodeGraphStore } = await import('../codegraph/store.js');\n const { bindObservationToCode } = await import('../codegraph/binder.js');\n const codeStore = new CodeGraphStore();\n await codeStore.init(projectDir);\n await bindObservationToCode(codeStore, observation);\n } catch {\n // Code refs enrich memory retrieval, but memory writes must remain durable without them.\n }\n}\n\nfunction queueClaimDerivation(observation: Observation): void {\n const dataDir = projectDir;\n const isExplicit = observation.sourceDetail === 'explicit';\n const isGit = observation.source === 'git' || observation.sourceDetail === 'git-ingest';\n if (!dataDir || (!isExplicit && !isGit)) return;\n try {\n enqueueClaimDerivation({\n dataDir,\n projectId: observation.projectId,\n observationId: observation.id,\n });\n } catch {\n // The observation remains durable; a later scan can recover its claim.\n }\n}\n\nfunction queueObservationQualification(observation: Observation): void {\n const dataDir = projectDir;\n if (!dataDir || observation.admissionState !== 'candidate') return;\n try {\n enqueueObservationQualification({\n dataDir,\n projectId: observation.projectId,\n source: 'automatic-capture:' + observation.id,\n });\n } catch {\n // Candidate evidence remains available for a later qualification scan.\n }\n}\n\nfunction isVectorCompatibleWithCurrentIndex(embedding: number[] | null): boolean {\n if (!embedding) return false;\n const vectorDimensions = getVectorDimensions();\n return vectorDimensions !== null &&\n embedding.length === vectorDimensions &&\n embedding.every(Number.isFinite);\n}\n\n/**\n * A cache-less API startup deliberately creates a lexical index so MCP can\n * answer immediately. Once the background lane obtains its first vector, the\n * in-memory index must be rebuilt with a vector field in this same process.\n */\nasync function upgradeVectorSchemaAfterFirstEmbedding(embedding: number[]): Promise<boolean> {\n if (isVectorCompatibleWithCurrentIndex(embedding)) return true;\n if (getVectorDimensions() !== null || !embedding.every(Number.isFinite)) return false;\n\n const targetProjectDir = projectDir;\n if (!vectorSchemaUpgradePromise) {\n vectorSchemaUpgradePromise = reindexObservations()\n .then(() => projectDir === targetProjectDir && isVectorCompatibleWithCurrentIndex(embedding))\n .catch(() => false)\n .finally(() => {\n vectorSchemaUpgradePromise = null;\n });\n }\n return vectorSchemaUpgradePromise;\n}\n\n/**\n * Initialize the observations manager with a project directory.\n * Auto-initializes the ObservationStore if not already set.\n */\nexport async function initObservations(dir: string): Promise<void> {\n if (projectDir === dir) return;\n await initObservationStore(dir);\n const store = getObservationStore();\n observations = await store.loadAll();\n nextId = await store.loadIdCounter();\n projectDir = dir;\n searchIndexPrepared = false;\n vectorSchemaUpgradePromise = null;\n}\n\n/**\n * Check cross-process freshness and reload if another process has written.\n *\n * Call this at every read boundary (MCP tool handler, dashboard API, etc.)\n * BEFORE reading observations[] via getObservation / getAllObservations /\n * getProjectObservations / getObservationCount.\n *\n * When the SQLite storage_generation has advanced beyond our local snapshot:\n * 1. Reloads observations[] from the store\n * 2. Updates nextId from the store\n * 3. Rebuilds the Orama search index (so vector + BM25 search stay in sync)\n *\n * For DegradedBackend this is a no-op (always returns false).\n */\nexport async function ensureFreshObservations(): Promise<boolean> {\n if (!projectDir) return false;\n try {\n const store = getObservationStore();\n const wasStale = await store.ensureFresh();\n if (wasStale) {\n observations = await store.loadAll();\n nextId = await store.loadIdCounter();\n await reindexObservations();\n searchIndexPrepared = true;\n return true;\n }\n } catch {\n // Best-effort — don't crash the read path on freshness failure\n }\n return false;\n}\n\n/**\n * @internal Observation-only freshness gate.\n *\n * Public callers should use `withFreshIndex()` from freshness.ts instead,\n * which also covers mini-skills. This function remains for internal use\n * by the freshness module and legacy test code only.\n */\nexport async function withFreshObservations<T>(fn: () => T | Promise<T>): Promise<T> {\n await ensureFreshObservations();\n return fn();\n}\n\n/**\n * Store a new observation.\n *\n * This is the primary write API — called by the `memorix_store` MCP tool.\n * Automatically:\n * 1. Assigns an incremental ID\n * 2. Counts tokens for the observation content\n * 3. Inserts into Orama for full-text search\n * 4. Persists to disk\n */\nexport async function storeObservation(input: {\n entityName: string;\n type: ObservationType;\n title: string;\n narrative: string;\n facts?: string[];\n filesModified?: string[];\n concepts?: string[];\n projectId: string;\n topicKey?: string;\n sessionId?: string;\n progress?: ProgressInfo;\n source?: 'agent' | 'git' | 'manual';\n commitHash?: string;\n relatedCommits?: string[];\n relatedEntities?: string[];\n sourceDetail?: 'explicit' | 'hook' | 'git-ingest';\n valueCategory?: 'core' | 'contextual' | 'ephemeral';\n admissionState?: ObservationAdmissionState;\n admissionReason?: string;\n visibility?: ObservationVisibility;\n sharedWithAgentIds?: string[];\n createdByAgentId?: string;\n /** Optional caller-bound write scope for topic-key upserts. */\n visibilityReader?: ObservationReader;\n}): Promise<{ observation: Observation; upserted: boolean }> {\n const now = new Date().toISOString();\n\n // ── Central secret sanitization — strip credential values before any persistence ──\n // Covers all write paths: hooks, git-ingest, CLI, reasoning, compact-on-write, etc.\n input = { ...input, title: sanitizeCredentials(input.title), narrative: sanitizeCredentials(input.narrative), facts: input.facts?.map(sanitizeCredentials) };\n\n // Sync the local cache before using it as the topicKey fast path. This costs a\n // generation read in the normal case and only reloads when another process wrote.\n await ensureFreshObservations();\n\n // Topic key upsert: fast-path check in-memory (optimistic, may be stale).\n // A second authoritative check happens inside the file lock to prevent TOCTOU races\n // where two concurrent calls with the same topicKey both miss this check.\n if (input.topicKey) {\n const existing = observations.find(\n o => o.topicKey === input.topicKey && o.projectId === input.projectId,\n );\n if (existing) {\n if (input.visibilityReader && !canManageObservation(existing, input.visibilityReader)) {\n throw new Error('Cannot update a memory outside this session\\'s write scope.');\n }\n return { observation: await upsertObservation(existing, input, now), upserted: true };\n }\n }\n\n // ── Pre-compute enrichments (pure, no side-effects) ──\n const contentForExtraction = [input.title, input.narrative, ...(input.facts ?? [])].join(' ');\n const extracted = extractEntities(contentForExtraction);\n const enrichedConcepts = enrichConcepts(input.concepts ?? [], extracted);\n const userFiles = new Set((input.filesModified ?? []).map((f) => f.toLowerCase()));\n const enrichedFiles = [...(input.filesModified ?? [])];\n for (const f of extracted.files) {\n if (!userFiles.has(f.toLowerCase())) {\n enrichedFiles.push(f);\n }\n }\n const fullText = [\n input.title, input.narrative,\n ...(input.facts ?? []), ...enrichedFiles, ...enrichedConcepts,\n ].join(' ');\n const tokens = countTextTokens(fullText);\n\n // ── Atomic write: ID allocation + persist + in-memory push inside lock ──\n // This prevents concurrent calls from getting duplicate IDs or silently\n // losing observations due to stale in-memory state.\n let observation!: Observation;\n let doc!: MemorixDocument;\n\n let upsertedInsideLock = false;\n let reloadCacheAfterCommit = false;\n const assignAndPersist = async () => {\n if (projectDir) {\n const store = getObservationStore();\n const cachedGeneration = store.getGeneration();\n await store.atomic(async (tx) => {\n const transactionGeneration = await tx.getGeneration();\n const diskNextId = await tx.loadIdCounter();\n\n // A different writer committed after the cache freshness check but before\n // this transaction acquired its lock. Keep the cache coherent after commit.\n reloadCacheAfterCommit = transactionGeneration !== cachedGeneration;\n\n // ── Atomic topicKey re-check inside lock (prevents TOCTOU race) ──\n // Two concurrent calls with the same topicKey may both pass the fast-path\n // check above, but here we re-check against the authoritative disk state.\n if (input.topicKey) {\n const diskExisting = await tx.findByTopicKey(input.projectId, input.topicKey);\n if (diskExisting) {\n if (input.visibilityReader && !canManageObservation(diskExisting, input.visibilityReader)) {\n throw new Error('Cannot update a memory outside this session\\'s write scope.');\n }\n // Switch to upsert path — update the existing observation after this\n // short transaction has released its lock.\n upsertedInsideLock = true;\n observation = diskExisting;\n return; // Exit atomic — upsert will be handled after assignAndPersist\n }\n }\n\n // Use the higher of in-memory vs disk counter (handles multi-process)\n const id = Math.max(nextId, diskNextId);\n\n observation = {\n id,\n entityName: input.entityName,\n type: input.type,\n title: input.title,\n narrative: input.narrative,\n facts: input.facts ?? [],\n filesModified: enrichedFiles,\n concepts: enrichedConcepts,\n tokens,\n createdAt: now,\n projectId: input.projectId,\n hasCausalLanguage: extracted.hasCausalLanguage,\n topicKey: input.topicKey,\n revisionCount: 1,\n sessionId: input.sessionId,\n status: 'active',\n progress: input.progress,\n source: input.source,\n commitHash: input.commitHash,\n relatedCommits: input.relatedCommits,\n relatedEntities: input.relatedEntities,\n sourceDetail: input.sourceDetail,\n valueCategory: input.valueCategory,\n admissionState: input.admissionState,\n admissionReason: input.admissionReason ? sanitizeCredentials(input.admissionReason) : undefined,\n visibility: input.visibility ?? 'project',\n sharedWithAgentIds: input.sharedWithAgentIds,\n createdByAgentId: input.createdByAgentId,\n // Predict the generation that atomic() will commit after this callback.\n // bumpGeneration() runs after fn(tx) returns, incrementing by 1.\n writeGeneration: transactionGeneration + 1,\n };\n\n await tx.insert(observation);\n await tx.saveIdCounter(id + 1);\n });\n\n // Phase 4a: confirm writeGeneration matches actual post-bump value\n observation.writeGeneration = store.getGeneration();\n\n if (upsertedInsideLock || reloadCacheAfterCommit) {\n observations = await store.loadAll();\n nextId = await store.loadIdCounter();\n if (upsertedInsideLock) {\n observation = observations.find((candidate) => candidate.id === observation.id)\n ?? observation;\n }\n } else {\n observations.push(observation);\n nextId = observation.id + 1;\n }\n\n // If the atomic block detected a topicKey duplicate, skip Orama insert — upsert handles it\n if (upsertedInsideLock) return;\n } else {\n // No projectDir (e.g., tests) — just use in-memory counter\n const id = nextId++;\n observation = {\n id,\n entityName: input.entityName,\n type: input.type,\n title: input.title,\n narrative: input.narrative,\n facts: input.facts ?? [],\n filesModified: enrichedFiles,\n concepts: enrichedConcepts,\n tokens,\n createdAt: now,\n projectId: input.projectId,\n hasCausalLanguage: extracted.hasCausalLanguage,\n topicKey: input.topicKey,\n revisionCount: 1,\n sessionId: input.sessionId,\n status: 'active',\n progress: input.progress,\n source: input.source,\n commitHash: input.commitHash,\n relatedCommits: input.relatedCommits,\n relatedEntities: input.relatedEntities,\n sourceDetail: input.sourceDetail,\n valueCategory: input.valueCategory,\n admissionState: input.admissionState,\n admissionReason: input.admissionReason ? sanitizeCredentials(input.admissionReason) : undefined,\n visibility: input.visibility ?? 'project',\n sharedWithAgentIds: input.sharedWithAgentIds,\n createdByAgentId: input.createdByAgentId,\n writeGeneration: 0,\n };\n observations.push(observation);\n }\n\n // Build Orama doc AFTER id is assigned\n doc = {\n id: makeOramaObservationId(input.projectId, observation.id),\n observationId: observation.id,\n entityName: input.entityName,\n type: input.type,\n title: input.title,\n narrative: input.narrative,\n facts: (input.facts ?? []).join('\\n'),\n filesModified: enrichedFiles.join('\\n'),\n concepts: enrichedConcepts.map(c => c.replace(/-/g, ' ')).join(', '),\n tokens,\n createdAt: now,\n projectId: input.projectId,\n accessCount: 0,\n lastAccessedAt: '',\n status: 'active',\n source: input.source ?? 'agent',\n sourceDetail: input.sourceDetail ?? '',\n valueCategory: input.valueCategory ?? '',\n admissionState: input.admissionState ?? '',\n admissionReason: input.admissionReason ? sanitizeCredentials(input.admissionReason) : '',\n visibility: input.visibility ?? 'project',\n createdByAgentId: input.createdByAgentId ?? '',\n sharedWithAgentIds: JSON.stringify(input.sharedWithAgentIds ?? []),\n };\n\n await insertObservation(doc);\n };\n\n await assignAndPersist();\n\n // If the lock discovered a topicKey duplicate on disk, delegate to upsert\n if (upsertedInsideLock) {\n return { observation: await upsertObservation(observation, input, now), upserted: true };\n }\n\n await bindObservationCodeRefsBestEffort(observation);\n queueObservationQualification(observation);\n if (resolveObservationVisibility(observation) === 'project') {\n queueClaimDerivation(observation);\n }\n\n // Generate embedding async (fire-and-forget) — never blocks MCP response\n // Track in vectorMissingIds until embedding is successfully written.\n const obsId = observation.id;\n vectorMissingIds.add(obsId);\n const searchableText = [input.title, input.narrative, ...(input.facts ?? [])].join(' ');\n generateEmbedding(searchableText).then(async (embedding) => {\n if (embedding) {\n if (!isVectorCompatibleWithCurrentIndex(embedding)) {\n await upgradeVectorSchemaAfterFirstEmbedding(embedding);\n }\n if (!isVectorCompatibleWithCurrentIndex(embedding)) {\n const vectorDimensions = getVectorDimensions();\n console.error(\n `[memorix] Embedding dimension mismatch for obs-${obsId}: provider returned ${embedding.length}d, index expects ${vectorDimensions ?? 'unknown'}d (kept in backfill queue)`,\n );\n queueVectorBackfill(input.projectId);\n return;\n }\n try {\n const { removeObservation: removeObs } = await import('../store/orama-store.js');\n await removeObs(makeOramaObservationId(input.projectId, obsId));\n await insertObservation(Object.assign({}, doc, { embedding }));\n vectorMissingIds.delete(obsId);\n } catch {\n console.error(`[memorix] Embedding index update failed for obs-${obsId} (kept in backfill queue)`);\n queueVectorBackfill(input.projectId);\n }\n } else if (isEmbeddingExplicitlyDisabled()) {\n vectorMissingIds.delete(obsId);\n } else {\n queueVectorBackfill(input.projectId);\n logEmbeddingFailureOnce(\n 'provider-unavailable',\n `[memorix] Embedding provider unavailable (using BM25 until embedding recovers; queued obs-${obsId} for retry)`,\n );\n }\n }).catch((err) => {\n queueVectorBackfill(input.projectId);\n const failure = normalizeEmbeddingFailure(err);\n logEmbeddingFailureOnce(\n failure.key,\n `[memorix] Async embedding failed (using BM25 until embedding recovers; queued obs-${obsId} for retry): ${failure.message}`,\n );\n });\n\n return { observation, upserted: false };\n}\n\n/**\n * Update an existing observation via topic key upsert.\n * Replaces content but preserves the original ID and createdAt.\n */\nasync function upsertObservation(\n existing: Observation,\n input: {\n entityName: string;\n type: ObservationType;\n title: string;\n narrative: string;\n facts?: string[];\n filesModified?: string[];\n concepts?: string[];\n projectId: string;\n topicKey?: string;\n sessionId?: string;\n progress?: ProgressInfo;\n sourceDetail?: 'explicit' | 'hook' | 'git-ingest';\n valueCategory?: 'core' | 'contextual' | 'ephemeral';\n admissionState?: ObservationAdmissionState;\n admissionReason?: string;\n visibility?: ObservationVisibility;\n sharedWithAgentIds?: string[];\n },\n now: string,\n): Promise<Observation> {\n // ── Central secret sanitization ──\n input = { ...input, title: sanitizeCredentials(input.title), narrative: sanitizeCredentials(input.narrative), facts: input.facts?.map(sanitizeCredentials) };\n\n // Auto-extract and enrich (same as storeObservation)\n const contentForExtraction = [input.title, input.narrative, ...(input.facts ?? [])].join(' ');\n const extracted = extractEntities(contentForExtraction);\n const enrichedConcepts = enrichConcepts(input.concepts ?? [], extracted);\n const userFiles = new Set((input.filesModified ?? []).map((f) => f.toLowerCase()));\n const enrichedFiles = [...(input.filesModified ?? [])];\n for (const f of extracted.files) {\n if (!userFiles.has(f.toLowerCase())) enrichedFiles.push(f);\n }\n const fullText = [input.title, input.narrative, ...(input.facts ?? []), ...enrichedFiles, ...enrichedConcepts].join(' ');\n const tokens = countTextTokens(fullText);\n\n // Mark old observation as resolved (superseded by new version)\n // Note: topicKey upsert replaces in-place, so we just bump revision\n\n // Update in-place\n existing.entityName = input.entityName;\n existing.type = input.type;\n existing.title = input.title;\n existing.narrative = input.narrative;\n existing.facts = input.facts ?? [];\n existing.filesModified = enrichedFiles;\n existing.concepts = enrichedConcepts;\n existing.tokens = tokens;\n existing.updatedAt = now;\n existing.hasCausalLanguage = extracted.hasCausalLanguage;\n existing.revisionCount = (existing.revisionCount ?? 1) + 1;\n existing.status = 'active';\n if (input.sessionId) existing.sessionId = input.sessionId;\n if (input.progress) existing.progress = input.progress;\n if (input.sourceDetail !== undefined) existing.sourceDetail = input.sourceDetail;\n if (input.valueCategory !== undefined) existing.valueCategory = input.valueCategory;\n if (input.admissionState !== undefined) existing.admissionState = input.admissionState;\n if (input.admissionReason !== undefined) existing.admissionReason = sanitizeCredentials(input.admissionReason);\n if (input.visibility !== undefined) existing.visibility = input.visibility;\n if (input.sharedWithAgentIds !== undefined) existing.sharedWithAgentIds = input.sharedWithAgentIds;\n\n // Re-index in Orama WITHOUT embedding first (non-blocking)\n const doc: MemorixDocument = {\n id: makeOramaObservationId(existing.projectId, existing.id),\n observationId: existing.id,\n entityName: existing.entityName,\n type: existing.type,\n title: existing.title,\n narrative: existing.narrative,\n facts: existing.facts.join('\\n'),\n filesModified: enrichedFiles.join('\\n'),\n concepts: enrichedConcepts.map(c => c.replace(/-/g, ' ')).join(', '),\n tokens,\n createdAt: existing.createdAt,\n projectId: existing.projectId,\n accessCount: 0,\n lastAccessedAt: '',\n status: 'active',\n source: existing.source ?? 'agent',\n sourceDetail: existing.sourceDetail ?? '',\n valueCategory: existing.valueCategory ?? '',\n admissionState: existing.admissionState ?? '',\n admissionReason: existing.admissionReason ?? '',\n visibility: existing.visibility ?? 'project',\n createdByAgentId: existing.createdByAgentId ?? '',\n sharedWithAgentIds: JSON.stringify(existing.sharedWithAgentIds ?? []),\n };\n\n // Remove old doc and insert updated one (with retry for concurrent upsert race)\n const oramaId = makeOramaObservationId(existing.projectId, existing.id);\n try {\n const { removeObservation } = await import('../store/orama-store.js');\n await removeObservation(oramaId);\n } catch { /* may not exist in index */ }\n try {\n await insertObservation(doc);\n } catch {\n // Concurrent upsert may have already re-inserted — retry remove+insert once\n try {\n const { removeObservation: removeObs } = await import('../store/orama-store.js');\n await removeObs(oramaId);\n await insertObservation(doc);\n } catch { /* best effort — file persistence is the source of truth */ }\n }\n\n // Persist via ObservationStore\n if (projectDir) {\n const store = getObservationStore();\n await store.update(existing);\n }\n\n await bindObservationCodeRefsBestEffort(existing);\n queueObservationQualification(existing);\n if (resolveObservationVisibility(existing) === 'project') {\n queueClaimDerivation(existing);\n }\n\n // Generate embedding async (fire-and-forget) — never blocks MCP response\n const searchableText = [input.title, input.narrative, ...(input.facts ?? [])].join(' ');\n const obsId = existing.id;\n vectorMissingIds.add(obsId);\n generateEmbedding(searchableText).then(async (embedding) => {\n if (embedding) {\n if (!isVectorCompatibleWithCurrentIndex(embedding)) {\n await upgradeVectorSchemaAfterFirstEmbedding(embedding);\n }\n if (!isVectorCompatibleWithCurrentIndex(embedding)) {\n queueVectorBackfill(existing.projectId);\n return;\n }\n try {\n const { removeObservation: removeObs } = await import('../store/orama-store.js');\n await removeObs(makeOramaObservationId(existing.projectId, obsId));\n await insertObservation(Object.assign({}, doc, { embedding }));\n vectorMissingIds.delete(obsId);\n } catch {\n // Embedding index update failed — observation still persisted without vector\n queueVectorBackfill(existing.projectId);\n }\n } else if (isEmbeddingExplicitlyDisabled()) {\n vectorMissingIds.delete(obsId);\n } else {\n queueVectorBackfill(existing.projectId);\n }\n }).catch((err) => {\n queueVectorBackfill(existing.projectId);\n const failure = normalizeEmbeddingFailure(err);\n logEmbeddingFailureOnce(\n failure.key,\n `[memorix] Async embedding failed (using BM25 until embedding recovers; queued obs-${obsId} for retry): ${failure.message}`,\n );\n });\n\n return existing;\n}\n\n/**\n * Get an observation by ID.\n */\nexport function getObservation(id: number, projectId?: string): Observation | undefined {\n return observations.find((o) => o.id === id && (projectId ? o.projectId === projectId : true));\n}\n\n/**\n * Promote or demote an automatic observation without changing its content.\n * The expected-state guard keeps concurrent maintenance workers from\n * resurrecting an observation that another writer has already changed.\n */\nexport async function updateObservationAdmission(input: {\n observationId: number;\n projectId?: string;\n expectedState?: ObservationAdmissionState;\n admissionState: ObservationAdmissionState;\n admissionReason: string;\n visibility?: ObservationVisibility;\n}): Promise<Observation | undefined> {\n await ensureFreshObservations();\n const cached = observations.find((observation) =>\n observation.id === input.observationId &&\n (!input.projectId || observation.projectId === input.projectId),\n );\n if (!cached) return undefined;\n\n const now = new Date().toISOString();\n const admissionReason = sanitizeCredentials(input.admissionReason).slice(0, 240);\n const apply = (current: Observation): Observation | undefined => {\n if (input.projectId && current.projectId !== input.projectId) return undefined;\n if (input.expectedState && current.admissionState !== input.expectedState) return undefined;\n return {\n ...current,\n admissionState: input.admissionState,\n admissionReason,\n ...(input.visibility !== undefined ? { visibility: input.visibility } : {}),\n updatedAt: now,\n };\n };\n\n let updated: Observation | undefined;\n if (projectDir) {\n const store = getObservationStore();\n await store.atomic(async (tx) => {\n const current = await tx.getById(input.observationId);\n if (!current) return;\n const next = apply(current);\n if (!next) return;\n await tx.update(next);\n updated = next;\n });\n } else {\n updated = apply(cached);\n }\n\n if (!updated) return undefined;\n observations = observations.map((observation) =>\n observation.id === updated!.id && observation.projectId === updated!.projectId\n ? updated!\n : observation,\n );\n\n try {\n await updateObservationMetadata(updated.projectId, updated.id, {\n admissionState: updated.admissionState,\n admissionReason: updated.admissionReason,\n ...(updated.visibility !== undefined ? { visibility: updated.visibility } : {}),\n });\n } catch {\n // SQLite is canonical. The next index hydration repairs a missed update.\n }\n\n if (updated.admissionState === 'qualified' && resolveObservationVisibility(updated) === 'project') {\n queueClaimDerivation(updated);\n }\n\n return updated;\n}\n\n/**\n * Resolve observations — mark them as resolved (completed/no longer active).\n * This prevents resolved memories from appearing in default search results.\n */\nexport async function resolveObservations(\n ids: number[],\n status: ObservationStatus = 'resolved',\n): Promise<{ resolved: number[]; notFound: number[] }> {\n const resolved: number[] = [];\n const notFound: number[] = [];\n const changed: Observation[] = [];\n const now = new Date().toISOString();\n\n for (const id of ids) {\n const obs = observations.find(o => o.id === id);\n if (!obs) {\n notFound.push(id);\n continue;\n }\n obs.status = status;\n obs.updatedAt = now;\n if (obs.progress) {\n obs.progress.status = status === 'resolved' ? 'completed' : obs.progress.status;\n }\n resolved.push(id);\n changed.push(obs);\n\n // Update Orama index (without blocking on embedding)\n try {\n const { removeObservation: removeObs } = await import('../store/orama-store.js');\n await removeObs(makeOramaObservationId(obs.projectId, id));\n const doc: MemorixDocument = {\n id: makeOramaObservationId(obs.projectId, obs.id),\n observationId: obs.id,\n entityName: obs.entityName,\n type: obs.type,\n title: obs.title,\n narrative: obs.narrative,\n facts: obs.facts.join('\\n'),\n filesModified: obs.filesModified.join('\\n'),\n concepts: obs.concepts.map(c => c.replace(/-/g, ' ')).join(', '),\n tokens: obs.tokens,\n createdAt: obs.createdAt,\n projectId: obs.projectId,\n accessCount: 0,\n lastAccessedAt: '',\n status,\n source: obs.source ?? 'agent',\n sourceDetail: obs.sourceDetail ?? '',\n valueCategory: obs.valueCategory ?? '',\n admissionState: obs.admissionState ?? '',\n admissionReason: obs.admissionReason ?? '',\n visibility: obs.visibility ?? 'project',\n createdByAgentId: obs.createdByAgentId ?? '',\n sharedWithAgentIds: JSON.stringify(obs.sharedWithAgentIds ?? []),\n };\n await insertObservation(doc);\n // Async embedding update (fire-and-forget)\n const obsId = obs.id;\n generateEmbedding([obs.title, obs.narrative, ...obs.facts].join(' ')).then(async (embedding) => {\n if (embedding) {\n try {\n await removeObs(`obs-${obsId}`);\n await insertObservation(Object.assign({}, doc, { embedding }));\n } catch { /* best effort */ }\n }\n }).catch(() => {});\n } catch { /* best effort */ }\n }\n\n // Persist via ObservationStore\n if (projectDir && resolved.length > 0) {\n const store = getObservationStore();\n await store.atomic(async (tx) => {\n await Promise.all(changed.map((observation) => tx.update(observation)));\n });\n }\n\n return { resolved, notFound };\n}\n\n/**\n * Get all observations for a project.\n * Supports alias expansion: if projectIds is an array, matches any of them.\n */\nexport function getProjectObservations(projectId: string | string[]): Observation[] {\n if (Array.isArray(projectId)) {\n const idSet = new Set(projectId);\n return observations.filter((o) => idSet.has(o.projectId));\n }\n return observations.filter((o) => o.projectId === projectId);\n}\n\n/**\n * Migrate observations from non-canonical project IDs to the canonical ID.\n *\n * Called once during server startup after alias registration.\n * Rewrites in-memory observations and persists changes to disk.\n *\n * @param aliasIds - All known alias IDs for this project (including canonical)\n * @param canonicalId - The canonical project ID to normalize to\n * @returns Number of observations migrated\n */\nexport async function migrateProjectIds(\n aliasIds: string[],\n canonicalId: string,\n): Promise<number> {\n const nonCanonical = new Set(aliasIds.filter(id => id !== canonicalId));\n if (nonCanonical.size === 0) return 0;\n\n let migrated = 0;\n const changed: Observation[] = [];\n for (const obs of observations) {\n if (nonCanonical.has(obs.projectId)) {\n obs.projectId = canonicalId;\n migrated++;\n changed.push(obs);\n }\n }\n\n if (migrated > 0 && projectDir) {\n const store = getObservationStore();\n await store.atomic(async (tx) => {\n await Promise.all(changed.map((observation) => tx.update(observation)));\n });\n }\n\n return migrated;\n}\n\n/**\n * Get all observations (in-memory copy).\n * Used by timeline and retention to avoid unreliable Orama empty-term queries.\n */\nexport function getAllObservations(): Observation[] {\n return [...observations];\n}\n\n/**\n * Get the total number of stored observations.\n */\nexport function getObservationCount(): number {\n return observations.length;\n}\n\n/**\n * Suggest a stable topic key from type + title.\n * Uses family heuristics (architecture/*, bug/*, decision/*, etc.)\n * Inspired by Engram's mem_suggest_topic_key.\n */\nexport function suggestTopicKey(type: string, title: string): string {\n // Determine family from type\n let family = 'general';\n const typeLower = type.toLowerCase();\n for (const [fam, keywords] of Object.entries(TOPIC_KEY_FAMILIES)) {\n if (keywords.some(k => typeLower.includes(k))) {\n family = fam;\n break;\n }\n }\n\n // Normalize title to slug\n const slug = title\n .toLowerCase()\n .replace(/[^a-z0-9\\u4e00-\\u9fff\\s-]/g, '') // keep letters, digits, CJK, spaces, hyphens\n .trim()\n .replace(/\\s+/g, '-')\n .slice(0, 60);\n\n if (!slug) return '';\n return `${family}/${slug}`;\n}\n\n/**\n * Reload observations into the Orama index with full corpus embeddings.\n * Intended for explicit heavy rebuilds, not normal MCP startup.\n *\n * Optimization: uses batch embedding (ONNX processes 64 texts at a time)\n * instead of individual embed calls. This reduces startup CPU from minutes\n * to seconds for large observation sets (500+).\n */\nexport async function reindexObservations(): Promise<number> {\n if (observations.length === 0) return 0;\n\n // Reset the Orama index to ensure clean reindex (idempotent)\n await resetDb();\n searchIndexPrepared = false;\n vectorMissingIds.clear();\n\n // Prefer already-persisted vectors for remote providers. This restores semantic\n // recall after a restart without waiting on the network; cache misses remain\n // in the existing bounded background recovery lane.\n let embeddings: (number[] | null)[] = observations.map(() => null);\n const provider = await getEmbeddingProvider();\n const canBatchEmbedAtStartup = provider !== null && !provider.name.startsWith('api-');\n\n // This is an explicit rebuild path. Establish the current Orama schema before\n // accepting cached vectors so a stale cache entry cannot make an observation\n // disappear from the lexical index on insert.\n await getDb();\n\n const texts = observations.map(obs =>\n [obs.title, obs.narrative, ...obs.facts].join(' '),\n );\n\n if (provider?.getCachedEmbeddings) {\n try {\n embeddings = await provider.getCachedEmbeddings(texts);\n } catch {\n // Cache lookup is optional; remote cache misses continue to background recovery.\n }\n }\n\n if (provider && !canBatchEmbedAtStartup) {\n console.error('[memorix] Startup reindex: restored cached API embeddings; uncached vectors stay in background recovery');\n }\n\n if (canBatchEmbedAtStartup) {\n try {\n embeddings = await batchGenerateEmbeddings(texts);\n // Batch embedding failed — fall back to no embeddings\n } catch {\n // Batch embedding failed; fall back to no embeddings.\n }\n }\n\n let count = 0;\n for (let i = 0; i < observations.length; i++) {\n const obs = observations[i];\n try {\n const embedding = embeddings[i] ?? null;\n const compatibleEmbedding = isVectorCompatibleWithCurrentIndex(embedding) ? embedding : null;\n if (embedding && !compatibleEmbedding) {\n const vectorDimensions = getVectorDimensions();\n console.error(\n `[memorix] Startup reindex embedding mismatch for obs-${obs.id}: provider returned ${embedding.length}d, index expects ${vectorDimensions ?? 'unknown'}d (queued for backfill)`,\n );\n }\n const docId = makeOramaObservationId(obs.projectId, obs.id);\n const doc: MemorixDocument = {\n id: docId,\n observationId: obs.id,\n entityName: obs.entityName,\n type: obs.type,\n title: obs.title,\n narrative: obs.narrative,\n facts: obs.facts.join('\\n'),\n filesModified: obs.filesModified.join('\\n'),\n concepts: obs.concepts.map((c: string) => c.replace(/-/g, ' ')).join(', '),\n tokens: obs.tokens,\n createdAt: obs.createdAt,\n projectId: obs.projectId,\n accessCount: 0,\n lastAccessedAt: '',\n status: obs.status ?? 'active',\n source: obs.source ?? 'agent',\n sourceDetail: obs.sourceDetail ?? '',\n valueCategory: obs.valueCategory ?? '',\n admissionState: obs.admissionState ?? '',\n admissionReason: obs.admissionReason ?? '',\n visibility: obs.visibility ?? 'project',\n createdByAgentId: obs.createdByAgentId ?? '',\n sharedWithAgentIds: JSON.stringify(obs.sharedWithAgentIds ?? []),\n ...(compatibleEmbedding ? { embedding: compatibleEmbedding } : {}),\n };\n await insertObservation(doc);\n if (!compatibleEmbedding && !isEmbeddingExplicitlyDisabled()) {\n vectorMissingIds.add(obs.id);\n }\n count++;\n } catch (err) {\n console.error(`[memorix] Failed to reindex observation #${obs.id}: ${err}`);\n }\n }\n searchIndexPrepared = true;\n return count;\n}\n\n/**\n * Prepare the search index for startup and hot-reload without blocking on\n * corpus-wide embedding generation.\n *\n * This hydrates the lexical/BM25 index immediately so MCP availability is not\n * coupled to embedding provider throughput. Missing vectors are queued for the\n * existing background backfill cycle.\n */\nexport async function prepareSearchIndex(): Promise<number> {\n if (searchIndexPrepared) return 0;\n\n const count = await hydrateIndexForStartup(observations as unknown as any[]);\n if (count === 0) {\n searchIndexPrepared = true;\n return 0;\n }\n\n const hydratedProjectDir = projectDir;\n const queueMissingVectors = () => {\n if (projectDir !== hydratedProjectDir) return;\n vectorMissingIds.clear();\n if (!isEmbeddingExplicitlyDisabled()) {\n const projectsWithMissingVectors = new Set<string>();\n for (const obs of observations) {\n // Queue ALL statuses for vector backfill — status filtering happens at query time,\n // not at index time. Omitting non-active observations here would permanently\n // exclude resolved/archived memories from hybrid search after restart.\n if (!hasObservationVector(obs.projectId, obs.id)) {\n vectorMissingIds.add(obs.id);\n projectsWithMissingVectors.add(obs.projectId);\n }\n }\n for (const projectId of projectsWithMissingVectors) queueVectorBackfill(projectId);\n }\n };\n\n const cacheHydration = getDeferredCachedVectorHydration();\n if (cacheHydration) {\n // Let the disk cache finish outside the interactive startup path. Misses are\n // queued only after it has had a chance to restore compatible vectors.\n void cacheHydration.finally(queueMissingVectors);\n } else {\n queueMissingVectors();\n }\n\n searchIndexPrepared = true;\n return count;\n}\n\n// ── Vector-missing observability & backfill ─────────────────────────\n\n/**\n * Get the current set of observation IDs that are missing vector embeddings.\n * Useful for dashboards, health checks, and monitoring search quality degradation.\n */\nexport function getVectorMissingIds(projectId?: string): number[] {\n if (!projectId) return [...vectorMissingIds];\n const observationById = new Map(observations.map((observation) => [observation.id, observation]));\n return [...vectorMissingIds].filter((id) => observationById.get(id)?.projectId === projectId);\n}\n\n/**\n * Get a summary of vector embedding status.\n * Returns total observations, how many have vectors, and how many are missing.\n */\nexport function getVectorStatus(projectId?: string): {\n total: number;\n missing: number;\n missingIds: number[];\n backfillRunning: boolean;\n lastBackfill: typeof lastVectorBackfill;\n} {\n const missingIds = getVectorMissingIds(projectId);\n return {\n total: projectId ? observations.filter((observation) => observation.projectId === projectId).length : observations.length,\n missing: missingIds.length,\n missingIds,\n backfillRunning: vectorBackfillRunning,\n lastBackfill: lastVectorBackfill,\n };\n}\n\n/**\n * Return search-index state from the same module graph that owns the hydrated\n * Orama instance. This avoids split singleton state when tools load Memorix\n * TypeScript sources through runtime loaders.\n */\nexport function getSearchIndexStatus(projectId?: string): {\n embeddingEnabled: boolean;\n vectorDimensions: number | null;\n lastSearchMode: string;\n prepared: boolean;\n} {\n return {\n embeddingEnabled: isEmbeddingEnabled(),\n vectorDimensions: getVectorDimensions(),\n lastSearchMode: getLastSearchMode(projectId),\n prepared: searchIndexPrepared,\n };\n}\n\n/**\n * Observability-only semantic probe. It intentionally disables access tracking\n * so status checks do not mutate retention/access metadata.\n */\nexport async function probeSearchIndex(projectId: string): Promise<string> {\n await searchObservations({\n query: 'semantic memory retrieval status',\n projectId,\n reader: { projectId },\n limit: 1,\n status: 'all',\n trackAccess: false,\n });\n return getLastSearchMode(projectId);\n}\n\n/**\n * Attempt to backfill missing vector embeddings.\n * Re-generates embeddings for observations in vectorMissingIds.\n * Returns the number successfully backfilled.\n *\n * Safe to call concurrently — only one backfill runs at a time.\n */\nexport async function backfillVectorEmbeddings(options: {\n projectId?: string;\n limit?: number;\n} = {}): Promise<{\n attempted: number;\n succeeded: number;\n failed: number;\n}> {\n if (vectorBackfillRunning) {\n return { attempted: 0, succeeded: 0, failed: 0 };\n }\n vectorBackfillRunning = true;\n\n const observationById = new Map(observations.map((observation) => [observation.id, observation]));\n const limit = Number.isFinite(options.limit)\n ? Math.max(1, Math.floor(options.limit!))\n : Number.POSITIVE_INFINITY;\n const ids = [...vectorMissingIds]\n .filter((id) => !options.projectId || observationById.get(id)?.projectId === options.projectId)\n .slice(0, limit);\n let succeeded = 0;\n let failed = 0;\n let lastFailure: string | undefined;\n\n try {\n for (const id of ids) {\n const obs = observationById.get(id);\n if (!obs) {\n vectorMissingIds.delete(id);\n continue;\n }\n\n const text = [obs.title, obs.narrative, ...obs.facts].join(' ');\n try {\n const embedding = await generateEmbedding(text);\n if (embedding) {\n if (!isVectorCompatibleWithCurrentIndex(embedding)) {\n await upgradeVectorSchemaAfterFirstEmbedding(embedding);\n }\n if (!isVectorCompatibleWithCurrentIndex(embedding)) {\n const vectorDimensions = getVectorDimensions();\n console.error(\n `[memorix] Backfill embedding mismatch for obs-${id}: provider returned ${embedding.length}d, index expects ${vectorDimensions ?? 'unknown'}d (kept in queue)`,\n );\n lastFailure = `dimension mismatch: provider returned ${embedding.length}d, index expects ${vectorDimensions ?? 'unknown'}d`;\n failed++;\n continue;\n }\n const oramaId = makeOramaObservationId(obs.projectId, obs.id);\n try {\n const { removeObservation: removeObs } = await import('../store/orama-store.js');\n await removeObs(oramaId);\n } catch { /* may not exist */ }\n const doc: MemorixDocument = {\n id: oramaId,\n observationId: obs.id,\n entityName: obs.entityName,\n type: obs.type,\n title: obs.title,\n narrative: obs.narrative,\n facts: obs.facts.join('\\n'),\n filesModified: obs.filesModified.join('\\n'),\n concepts: obs.concepts.map(c => c.replace(/-/g, ' ')).join(', '),\n tokens: obs.tokens,\n createdAt: obs.createdAt,\n projectId: obs.projectId,\n accessCount: 0,\n lastAccessedAt: '',\n status: obs.status ?? 'active',\n source: obs.source ?? 'agent',\n sourceDetail: obs.sourceDetail ?? '',\n valueCategory: obs.valueCategory ?? '',\n admissionState: obs.admissionState ?? '',\n admissionReason: obs.admissionReason ?? '',\n visibility: obs.visibility ?? 'project',\n createdByAgentId: obs.createdByAgentId ?? '',\n sharedWithAgentIds: JSON.stringify(obs.sharedWithAgentIds ?? []),\n embedding,\n };\n await insertObservation(doc);\n vectorMissingIds.delete(id);\n succeeded++;\n } else if (isEmbeddingExplicitlyDisabled()) {\n // Embedding explicitly off — nothing to backfill from\n vectorMissingIds.delete(id);\n } else {\n // Provider temporarily unavailable — keep in queue for next backfill cycle\n lastFailure = 'embedding provider unavailable';\n failed++;\n }\n } catch (err) {\n lastFailure = err instanceof Error ? err.message : String(err);\n failed++;\n }\n }\n } finally {\n vectorBackfillRunning = false;\n lastVectorBackfill = {\n attempted: ids.length,\n succeeded,\n failed,\n ...(lastFailure ? { lastError: lastFailure } : {}),\n finishedAt: new Date().toISOString(),\n };\n }\n\n return { attempted: ids.length, succeeded, failed };\n}\n","import { randomUUID } from 'node:crypto';\nimport { getDatabase } from '../store/sqlite-db.js';\nimport type {\n KnowledgePageRecord,\n KnowledgeProposal,\n KnowledgeWorkspace,\n KnowledgeWorkspaceMode,\n KnowledgeWorkspaceStatus,\n} from './workspace-types.js';\n\nfunction arrayValue(raw: unknown): string[] {\n if (typeof raw !== 'string' || !raw) return [];\n try {\n const parsed = JSON.parse(raw);\n return Array.isArray(parsed) ? parsed.filter((item): item is string => typeof item === 'string') : [];\n } catch {\n return [];\n }\n}\n\nfunction optionalText(value: unknown): string | undefined {\n return typeof value === 'string' && value ? value : undefined;\n}\n\nfunction rowToWorkspace(row: any): KnowledgeWorkspace {\n return {\n id: row.id,\n projectId: row.projectId,\n mode: row.mode,\n rootPath: row.rootPath,\n ...(optionalText(row.projectRoot) ? { projectRoot: row.projectRoot } : {}),\n status: row.status,\n createdAt: row.createdAt,\n updatedAt: row.updatedAt,\n ...(optionalText(row.lastCompiledAt) ? { lastCompiledAt: row.lastCompiledAt } : {}),\n ...(optionalText(row.lastLintedAt) ? { lastLintedAt: row.lastLintedAt } : {}),\n };\n}\n\nfunction rowToPage(row: any): KnowledgePageRecord {\n return {\n id: row.id,\n workspaceId: row.workspaceId,\n relativePath: row.relativePath,\n title: row.title,\n kind: row.kind,\n status: row.status,\n reviewState: row.reviewState,\n contentHash: row.contentHash,\n sourceHash: row.sourceHash,\n claimIds: arrayValue(row.claimIdsJson),\n ...(optionalText(row.snapshotId) ? { snapshotId: row.snapshotId } : {}),\n tags: arrayValue(row.tagsJson),\n generatedAt: row.generatedAt,\n updatedAt: row.updatedAt,\n ...(optionalText(row.lastLintedAt) ? { lastLintedAt: row.lastLintedAt } : {}),\n ...(optionalText(row.manualContentHash) ? { manualContentHash: row.manualContentHash } : {}),\n };\n}\n\nfunction rowToProposal(row: any): KnowledgeProposal {\n return {\n id: row.id,\n workspaceId: row.workspaceId,\n pageId: row.pageId,\n targetPath: row.targetPath,\n proposalPath: row.proposalPath,\n ...(optionalText(row.baseContentHash) ? { baseContentHash: row.baseContentHash } : {}),\n sourceHash: row.sourceHash,\n reason: row.reason,\n status: row.status,\n createdAt: row.createdAt,\n ...(optionalText(row.appliedAt) ? { appliedAt: row.appliedAt } : {}),\n };\n}\n\n/**\n * Operational metadata for Markdown workspaces. The Markdown files remain the\n * human-readable source; this store tracks provenance and safe proposal state.\n */\nexport class KnowledgeWorkspaceStore {\n private db: any = null;\n\n async init(dataDir: string): Promise<void> {\n this.db = getDatabase(dataDir);\n }\n\n upsertWorkspace(input: Omit<KnowledgeWorkspace, 'createdAt' | 'updatedAt'> & {\n createdAt?: string;\n updatedAt?: string;\n }): KnowledgeWorkspace {\n const now = input.updatedAt ?? new Date().toISOString();\n const createdAt = input.createdAt ?? now;\n this.db.prepare(\n 'INSERT INTO knowledge_workspaces (id, projectId, mode, rootPath, projectRoot, status, createdAt, updatedAt, lastCompiledAt, lastLintedAt) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT(id) DO UPDATE SET mode = excluded.mode, rootPath = excluded.rootPath, projectRoot = excluded.projectRoot, status = excluded.status, updatedAt = excluded.updatedAt, lastCompiledAt = excluded.lastCompiledAt, lastLintedAt = excluded.lastLintedAt',\n ).run(\n input.id,\n input.projectId,\n input.mode,\n input.rootPath,\n input.projectRoot ?? null,\n input.status,\n createdAt,\n now,\n input.lastCompiledAt ?? null,\n input.lastLintedAt ?? null,\n );\n return this.getWorkspace(input.id)!;\n }\n\n getWorkspace(id: string): KnowledgeWorkspace | undefined {\n const row = this.db.prepare('SELECT * FROM knowledge_workspaces WHERE id = ?').get(id);\n return row ? rowToWorkspace(row) : undefined;\n }\n\n findWorkspace(projectId: string, mode: KnowledgeWorkspaceMode): KnowledgeWorkspace | undefined {\n const row = this.db.prepare('SELECT * FROM knowledge_workspaces WHERE projectId = ? AND mode = ? ORDER BY updatedAt DESC LIMIT 1').get(projectId, mode);\n return row ? rowToWorkspace(row) : undefined;\n }\n\n upsertPage(page: KnowledgePageRecord): void {\n this.db.prepare(\n 'INSERT INTO knowledge_pages (id, workspaceId, relativePath, title, kind, status, reviewState, contentHash, sourceHash, claimIdsJson, snapshotId, tagsJson, generatedAt, updatedAt, lastLintedAt, manualContentHash) VALUES (@id, @workspaceId, @relativePath, @title, @kind, @status, @reviewState, @contentHash, @sourceHash, @claimIdsJson, @snapshotId, @tagsJson, @generatedAt, @updatedAt, @lastLintedAt, @manualContentHash) ON CONFLICT(workspaceId, relativePath) DO UPDATE SET id = excluded.id, title = excluded.title, kind = excluded.kind, status = excluded.status, reviewState = excluded.reviewState, contentHash = excluded.contentHash, sourceHash = excluded.sourceHash, claimIdsJson = excluded.claimIdsJson, snapshotId = excluded.snapshotId, tagsJson = excluded.tagsJson, generatedAt = excluded.generatedAt, updatedAt = excluded.updatedAt, lastLintedAt = excluded.lastLintedAt, manualContentHash = excluded.manualContentHash',\n ).run({\n ...page,\n claimIdsJson: JSON.stringify(page.claimIds),\n snapshotId: page.snapshotId ?? null,\n tagsJson: JSON.stringify(page.tags),\n lastLintedAt: page.lastLintedAt ?? null,\n manualContentHash: page.manualContentHash ?? null,\n });\n }\n\n getPage(workspaceId: string, relativePath: string): KnowledgePageRecord | undefined {\n const row = this.db.prepare('SELECT * FROM knowledge_pages WHERE workspaceId = ? AND relativePath = ?').get(workspaceId, relativePath);\n return row ? rowToPage(row) : undefined;\n }\n\n getPageById(id: string): KnowledgePageRecord | undefined {\n const row = this.db.prepare('SELECT * FROM knowledge_pages WHERE id = ?').get(id);\n return row ? rowToPage(row) : undefined;\n }\n\n listPages(workspaceId: string): KnowledgePageRecord[] {\n return this.db.prepare('SELECT * FROM knowledge_pages WHERE workspaceId = ? ORDER BY relativePath').all(workspaceId).map(rowToPage);\n }\n\n replacePageClaims(pageId: string, claimIds: string[]): void {\n const remove = this.db.prepare('DELETE FROM knowledge_page_claims WHERE pageId = ?');\n const insert = this.db.prepare(\"INSERT OR IGNORE INTO knowledge_page_claims (pageId, claimId, role) VALUES (?, ?, 'primary')\");\n this.db.transaction(() => {\n remove.run(pageId);\n for (const claimId of [...new Set(claimIds)]) insert.run(pageId, claimId);\n })();\n }\n\n replacePageLinks(pageId: string, targets: string[]): void {\n const remove = this.db.prepare('DELETE FROM knowledge_page_links WHERE sourcePageId = ?');\n const insert = this.db.prepare('INSERT OR IGNORE INTO knowledge_page_links (sourcePageId, targetPath) VALUES (?, ?)');\n this.db.transaction(() => {\n remove.run(pageId);\n for (const target of [...new Set(targets)]) insert.run(pageId, target);\n })();\n }\n\n createProposal(input: Omit<KnowledgeProposal, 'id' | 'createdAt' | 'status'> & {\n id?: string;\n createdAt?: string;\n status?: KnowledgeProposal['status'];\n }): KnowledgeProposal {\n const proposal: KnowledgeProposal = {\n id: input.id ?? randomUUID(),\n ...input,\n status: input.status ?? 'pending',\n createdAt: input.createdAt ?? new Date().toISOString(),\n };\n this.db.prepare(\n 'INSERT INTO knowledge_proposals (id, workspaceId, pageId, targetPath, proposalPath, baseContentHash, sourceHash, reason, status, createdAt, appliedAt) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT(workspaceId, proposalPath) DO UPDATE SET pageId = excluded.pageId, targetPath = excluded.targetPath, baseContentHash = excluded.baseContentHash, sourceHash = excluded.sourceHash, reason = excluded.reason, status = excluded.status, createdAt = excluded.createdAt, appliedAt = excluded.appliedAt',\n ).run(\n proposal.id,\n proposal.workspaceId,\n proposal.pageId,\n proposal.targetPath,\n proposal.proposalPath,\n proposal.baseContentHash ?? null,\n proposal.sourceHash,\n proposal.reason,\n proposal.status,\n proposal.createdAt,\n proposal.appliedAt ?? null,\n );\n const row = this.db.prepare('SELECT * FROM knowledge_proposals WHERE workspaceId = ? AND proposalPath = ?').get(proposal.workspaceId, proposal.proposalPath);\n return rowToProposal(row);\n }\n\n getProposal(id: string): KnowledgeProposal | undefined {\n const row = this.db.prepare('SELECT * FROM knowledge_proposals WHERE id = ?').get(id);\n return row ? rowToProposal(row) : undefined;\n }\n\n listProposals(workspaceId: string, status?: KnowledgeProposal['status']): KnowledgeProposal[] {\n const rows = status\n ? this.db.prepare('SELECT * FROM knowledge_proposals WHERE workspaceId = ? AND status = ? ORDER BY createdAt DESC, id').all(workspaceId, status)\n : this.db.prepare('SELECT * FROM knowledge_proposals WHERE workspaceId = ? ORDER BY createdAt DESC, id').all(workspaceId);\n return rows.map(rowToProposal);\n }\n\n markProposalApplied(id: string, appliedAt = new Date().toISOString()): KnowledgeProposal {\n this.db.prepare(\"UPDATE knowledge_proposals SET status = 'applied', appliedAt = ? WHERE id = ?\").run(appliedAt, id);\n return this.getProposal(id)!;\n }\n\n markWorkspaceCompiled(id: string, at = new Date().toISOString()): void {\n this.db.prepare('UPDATE knowledge_workspaces SET lastCompiledAt = ?, updatedAt = ? WHERE id = ?').run(at, at, id);\n }\n\n markWorkspaceLinted(id: string, status: KnowledgeWorkspaceStatus, at = new Date().toISOString()): void {\n this.db.prepare('UPDATE knowledge_workspaces SET status = ?, lastLintedAt = ?, updatedAt = ? WHERE id = ?').run(status, at, at, id);\n }\n}\n","import { createHash } from 'node:crypto';\nimport { execFile } from 'node:child_process';\nimport { promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport { promisify } from 'node:util';\nimport { atomicWriteFile, withFileLock } from '../store/file-lock.js';\nimport { KnowledgeWorkspaceStore } from './workspace-store.js';\nimport type { KnowledgeWorkspace, KnowledgeWorkspaceMode } from './workspace-types.js';\n\nconst execFileAsync = promisify(execFile);\n\nexport interface KnowledgeWorkspacePaths {\n root: string;\n pages: string;\n proposals: string;\n workflows: string;\n index: string;\n log: string;\n schema: string;\n}\n\nexport interface InitializeKnowledgeWorkspaceInput {\n projectId: string;\n dataDir: string;\n mode: KnowledgeWorkspaceMode;\n projectRoot?: string;\n rootPath?: string;\n}\n\nfunction hash(value: string): string {\n return createHash('sha256').update(value).digest('hex');\n}\n\nfunction workspaceId(projectId: string, mode: KnowledgeWorkspaceMode): string {\n return 'workspace:' + hash(projectId + ':' + mode).slice(0, 24);\n}\n\nfunction localWorkspacePath(dataDir: string, projectId: string): string {\n return path.join(path.resolve(dataDir), 'knowledge-workspaces', hash(projectId).slice(0, 24));\n}\n\nfunction isWithin(root: string, candidate: string): boolean {\n const relative = path.relative(root, candidate);\n return relative !== '' && !relative.startsWith('..' + path.sep) && relative !== '..' && !path.isAbsolute(relative);\n}\n\nfunction ensureVersionedPath(projectRoot: string, rootPath: string): string {\n if (!path.isAbsolute(rootPath)) {\n throw new Error('A versioned knowledge workspace requires an explicit absolute path');\n }\n const resolvedProject = path.resolve(projectRoot);\n const resolvedWorkspace = path.resolve(rootPath);\n if (!isWithin(resolvedProject, resolvedWorkspace)) {\n throw new Error('A versioned knowledge workspace must live inside the Git project');\n }\n const segments = path.relative(resolvedProject, resolvedWorkspace).split(path.sep);\n if (segments.includes('.git') || segments.includes('node_modules') || segments.includes('dist')) {\n throw new Error('The selected knowledge workspace path is not safe for project artifacts');\n }\n return resolvedWorkspace;\n}\n\nasync function isIgnoredByGit(projectRoot: string, workspaceRoot: string): Promise<boolean> {\n const relative = path.relative(projectRoot, workspaceRoot).split(path.sep).join('/');\n const probes = [relative, relative.replace(/\\/+$/, '') + '/.memorix-workspace-probe'];\n for (const probe of probes) {\n try {\n await execFileAsync('git', ['-C', projectRoot, 'check-ignore', '--quiet', '--no-index', '--', probe], {\n timeout: 3_000,\n windowsHide: true,\n });\n return true;\n } catch (error) {\n const code = error && typeof error === 'object' && 'code' in error\n ? (error as { code?: number | string }).code\n : undefined;\n if (code === 1 || code === '1') continue;\n return false;\n }\n }\n return false;\n}\n\nasync function assertNoSymlinkEscape(projectRoot: string, workspaceRoot: string): Promise<void> {\n const [realProject, realWorkspace] = await Promise.all([\n fs.realpath(projectRoot),\n fs.realpath(workspaceRoot),\n ]);\n if (!isWithin(realProject, realWorkspace)) {\n throw new Error('The selected knowledge workspace resolves outside the Git project');\n }\n}\n\nexport function getKnowledgeWorkspacePaths(workspace: Pick<KnowledgeWorkspace, 'rootPath'>): KnowledgeWorkspacePaths {\n const root = path.resolve(workspace.rootPath);\n return {\n root,\n pages: path.join(root, 'pages'),\n proposals: path.join(root, 'proposals'),\n workflows: path.join(root, 'workflows'),\n index: path.join(root, 'index.md'),\n log: path.join(root, 'log.md'),\n schema: path.join(root, 'schema.md'),\n };\n}\n\nexport function resolveKnowledgeWorkspaceFile(workspace: Pick<KnowledgeWorkspace, 'rootPath'>, relativePath: string): string {\n if (!relativePath || path.isAbsolute(relativePath)) {\n throw new Error('Knowledge workspace paths must be relative');\n }\n const root = path.resolve(workspace.rootPath);\n const candidate = path.resolve(root, relativePath);\n if (candidate === root || !isWithin(root, candidate)) {\n throw new Error('Knowledge workspace path escapes its root');\n }\n return candidate;\n}\n\nasync function writeIfMissing(filePath: string, content: string): Promise<void> {\n try {\n await fs.access(filePath);\n } catch {\n await atomicWriteFile(filePath, content);\n }\n}\n\nfunction schemaContent(): string {\n return [\n '# Memorix Knowledge Workspace',\n '',\n 'This workspace is compiled from source-qualified Memorix claims.',\n 'Topic pages are proposal-first: review and apply a proposal before relying',\n 'on it as a published project knowledge page.',\n '',\n 'Do not remove claim ids, evidence references, source hashes, or snapshot',\n 'references from page frontmatter. Manual body edits are preserved and cause',\n 'later compiler output to remain a proposal.',\n '',\n ].join('\\n');\n}\n\nfunction indexContent(): string {\n return [\n '# Knowledge Workspace',\n '',\n '## Published pages',\n '',\n 'No published pages yet.',\n '',\n '## Review queue',\n '',\n 'No pending proposals.',\n '',\n ].join('\\n');\n}\n\nfunction logContent(): string {\n return '# Knowledge log\\n\\n';\n}\n\nexport async function initializeKnowledgeWorkspace(input: InitializeKnowledgeWorkspaceInput): Promise<KnowledgeWorkspace> {\n if (!input.projectId.trim()) throw new Error('Knowledge workspace project id is required');\n if (!input.dataDir.trim()) throw new Error('Knowledge workspace data directory is required');\n\n let rootPath: string;\n let projectRoot: string | undefined;\n if (input.mode === 'local') {\n rootPath = localWorkspacePath(input.dataDir, input.projectId);\n } else {\n if (!input.projectRoot || !input.rootPath) {\n throw new Error('A versioned knowledge workspace requires projectRoot and rootPath');\n }\n projectRoot = path.resolve(input.projectRoot);\n rootPath = ensureVersionedPath(projectRoot, input.rootPath);\n if (await isIgnoredByGit(projectRoot, rootPath)) {\n throw new Error('The selected versioned knowledge workspace is ignored by Git');\n }\n }\n\n const paths = getKnowledgeWorkspacePaths({ rootPath });\n await fs.mkdir(paths.pages, { recursive: true });\n await Promise.all([\n fs.mkdir(paths.proposals, { recursive: true }),\n fs.mkdir(paths.workflows, { recursive: true }),\n ]);\n if (projectRoot) await assertNoSymlinkEscape(projectRoot, paths.root);\n\n const workspace: KnowledgeWorkspace = {\n id: workspaceId(input.projectId, input.mode),\n projectId: input.projectId,\n dataDir: path.resolve(input.dataDir),\n mode: input.mode,\n rootPath: paths.root,\n ...(projectRoot ? { projectRoot } : {}),\n status: 'ready',\n createdAt: new Date().toISOString(),\n updatedAt: new Date().toISOString(),\n };\n\n await withFileLock(paths.root, async () => {\n await writeIfMissing(paths.schema, schemaContent());\n await writeIfMissing(paths.index, indexContent());\n await writeIfMissing(paths.log, logContent());\n });\n\n const store = new KnowledgeWorkspaceStore();\n await store.init(input.dataDir);\n return { ...store.upsertWorkspace(workspace), dataDir: workspace.dataDir };\n}\n\nexport async function loadKnowledgeWorkspace(input: {\n projectId: string;\n dataDir: string;\n mode?: KnowledgeWorkspaceMode;\n}): Promise<KnowledgeWorkspace | undefined> {\n const store = new KnowledgeWorkspaceStore();\n await store.init(input.dataDir);\n const workspace = store.findWorkspace(input.projectId, input.mode ?? 'local');\n return workspace ? { ...workspace, dataDir: path.resolve(input.dataDir) } : undefined;\n}\n","import type { Observation, ObservationAdmissionState, ObservationType } from '../types.js';\nimport { resolveObservationVisibility } from './visibility.js';\n\nconst DURABLE_AUTOMATIC_TYPES = new Set<ObservationType>([\n 'decision',\n 'gotcha',\n 'problem-solution',\n 'trade-off',\n 'why-it-exists',\n]);\n\n/**\n * Legacy observations predate admission metadata and retain their existing\n * delivery behavior. New automatic captures must explicitly earn delivery.\n */\nexport function isEligibleForAutomaticDelivery(observation: Pick<Observation, 'admissionState'>): boolean {\n return observation.admissionState !== 'ephemeral' && observation.admissionState !== 'candidate';\n}\n\nexport function isCandidateObservation(observation: Pick<Observation, 'admissionState'>): boolean {\n return observation.admissionState === 'candidate';\n}\n\nexport function isEligibleForKnowledgePromotion(\n observation: Pick<Observation, 'admissionState' | 'valueCategory' | 'visibility'>,\n): boolean {\n return isEligibleForAutomaticDelivery(observation)\n && observation.valueCategory !== 'ephemeral'\n && resolveObservationVisibility(observation) === 'project';\n}\n\nexport interface CandidateQualification {\n admissionState: ObservationAdmissionState;\n admissionReason: string;\n}\n\n/**\n * Automatic hook records can become default-deliverable only after a current\n * Code Memory link backs a non-ephemeral candidate. This deliberately does\n * not create a claim: claims keep their explicit/Git source boundary.\n */\nexport function qualifyCandidateFromCurrentCode(input: {\n observation: Pick<Observation, 'admissionState' | 'valueCategory' | 'type'>;\n currentCodeReferenceCount: number;\n}): CandidateQualification | undefined {\n if (!isCandidateObservation(input.observation)) return undefined;\n if (input.observation.valueCategory === 'ephemeral') return undefined;\n if (input.currentCodeReferenceCount <= 0) return undefined;\n\n const typeLabel = DURABLE_AUTOMATIC_TYPES.has(input.observation.type)\n ? 'high-value automatic record'\n : 'automatic record';\n return {\n admissionState: 'qualified',\n admissionReason: `${typeLabel} qualified against ${input.currentCodeReferenceCount} current Code Memory reference(s)`,\n };\n}\n","/**\n * Memory Consolidation Engine\n *\n * Merges similar observations into consolidated summaries to prevent data bloat.\n * Uses text similarity (Jaccard on token n-grams) to find clusters of related\n * observations, then merges them into a single observation preserving key facts.\n *\n * Strategy:\n * 1. Group observations by entity + type\n * 2. Within each group, compute pairwise similarity\n * 3. Cluster observations above a similarity threshold\n * 4. Merge each cluster into a consolidated observation\n * 5. Remove originals, keep the merged result\n *\n * Inspired by Engram's duplicate_count and MemCP's MAGMA consolidation.\n */\n\nimport type { Observation } from '../types.js';\nimport { getObservationStore } from '../store/obs-store.js';\nimport { isEligibleForAutomaticDelivery } from './admission.js';\nimport { resolveObservationVisibility } from './visibility.js';\n\n/** Default similarity threshold for merging (0.0-1.0) */\nconst DEFAULT_SIMILARITY_THRESHOLD = 0.45;\n\n/** Higher threshold for high-value types — only near-duplicates should merge */\nconst HIGH_VALUE_SIMILARITY_THRESHOLD = 0.85;\n\n/** Types that require much higher similarity to merge (carry unique implementation detail) */\nconst HIGH_VALUE_TYPES = new Set(['gotcha', 'decision', 'trade-off', 'reasoning', 'problem-solution']);\n\n/** Minimum cluster size to trigger consolidation */\nconst MIN_CLUSTER_SIZE = 2;\n\n/** Maximum observations to process in one consolidation run */\nconst MAX_BATCH_SIZE = 500;\n\n/**\n * Tokenize text into word-level tokens for similarity comparison.\n */\nfunction tokenize(text: string): Set<string> {\n return new Set(\n text\n .toLowerCase()\n .replace(/[^a-z0-9\\u4e00-\\u9fff\\s-]/g, ' ')\n .split(/\\s+/)\n .filter(t => t.length > 1),\n );\n}\n\n/**\n * Compute Jaccard similarity between two sets of tokens.\n */\nfunction jaccardSimilarity(a: Set<string>, b: Set<string>): number {\n if (a.size === 0 && b.size === 0) return 1;\n let intersection = 0;\n for (const token of a) {\n if (b.has(token)) intersection++;\n }\n const union = a.size + b.size - intersection;\n return union === 0 ? 0 : intersection / union;\n}\n\n/**\n * Build a text fingerprint from an observation for similarity matching.\n */\nfunction observationFingerprint(obs: Observation): string {\n return [obs.title, obs.narrative, ...obs.facts, ...obs.concepts].join(' ');\n}\n\n/** A cluster of similar observations to be merged */\nexport interface ConsolidationCluster {\n /** IDs of observations in this cluster */\n ids: number[];\n /** Titles of observations in this cluster */\n titles: string[];\n /** Average pairwise similarity */\n similarity: number;\n /** The entity these belong to */\n entityName: string;\n /** The observation type */\n type: string;\n}\n\n/** Result of a consolidation run */\nexport interface ConsolidationResult {\n /** Number of clusters found */\n clustersFound: number;\n /** Number of observations merged */\n observationsMerged: number;\n /** Number of observations after consolidation */\n observationsAfter: number;\n /** Number of active project observations inspected in this bounded pass. */\n scanned: number;\n /** Present when another bounded pass is needed to cover this project. */\n nextCursor?: number;\n /** Details of each merge */\n merges: Array<{\n clusterId: number;\n mergedIds: number[];\n resultTitle: string;\n factCount: number;\n }>;\n}\n\ninterface ConsolidationPage {\n observations: Observation[];\n nextCursor?: number;\n}\n\nfunction clampBatchSize(limit: number | undefined): number {\n if (!Number.isFinite(limit)) return MAX_BATCH_SIZE;\n return Math.min(MAX_BATCH_SIZE, Math.max(1, Math.floor(limit!)));\n}\n\nfunction clampCursor(afterId: number | undefined): number {\n if (!Number.isFinite(afterId)) return 0;\n return Math.max(0, Math.floor(afterId!));\n}\n\nasync function loadConsolidationPage(\n projectId: string,\n options: { limit?: number; afterId?: number },\n): Promise<ConsolidationPage> {\n const limit = clampBatchSize(options.limit);\n const page = await getObservationStore().loadByProject(projectId, {\n status: 'active',\n afterId: clampCursor(options.afterId),\n limit: limit + 1,\n });\n const hasMore = page.length > limit;\n const observations = hasMore ? page.slice(0, limit) : page;\n return hasMore && observations.length > 0\n ? { observations, nextCursor: observations[observations.length - 1].id }\n : { observations };\n}\n\nfunction findClusters(observations: Observation[], threshold: number): ConsolidationCluster[] {\n // Pending automatic evidence must stay individually inspectable until its\n // source-backed qualification step completes. Consolidating it first would\n // erase the evidence grain the control plane still needs to audit.\n // Consolidation is a project-level maintenance action. Personal notes and\n // targeted handoffs must remain individually inspectable and are never\n // merged by a background job or another agent's manual cleanup.\n const eligible = observations\n .filter(isEligibleForAutomaticDelivery)\n .filter((observation) => resolveObservationVisibility(observation) === 'project');\n if (eligible.length < MIN_CLUSTER_SIZE) return [];\n\n const groups = new Map<string, Observation[]>();\n for (const obs of eligible) {\n const key = `${obs.entityName}::${obs.type}`;\n const group = groups.get(key) ?? [];\n group.push(obs);\n groups.set(key, group);\n }\n\n const clusters: ConsolidationCluster[] = [];\n for (const group of groups.values()) {\n if (group.length < MIN_CLUSTER_SIZE) continue;\n\n const groupType = group[0].type;\n const effectiveThreshold = HIGH_VALUE_TYPES.has(groupType)\n ? Math.max(threshold, HIGH_VALUE_SIMILARITY_THRESHOLD)\n : threshold;\n const fingerprints = group.map(obs => ({ obs, tokens: tokenize(observationFingerprint(obs)) }));\n const clustered = new Set<number>();\n\n for (let i = 0; i < fingerprints.length; i++) {\n if (clustered.has(fingerprints[i].obs.id)) continue;\n\n const cluster: Observation[] = [fingerprints[i].obs];\n let totalSim = 0;\n let simCount = 0;\n for (let j = i + 1; j < fingerprints.length; j++) {\n if (clustered.has(fingerprints[j].obs.id)) continue;\n const sim = jaccardSimilarity(fingerprints[i].tokens, fingerprints[j].tokens);\n if (sim >= effectiveThreshold) {\n cluster.push(fingerprints[j].obs);\n totalSim += sim;\n simCount++;\n }\n }\n\n if (cluster.length >= MIN_CLUSTER_SIZE) {\n for (const obs of cluster) clustered.add(obs.id);\n clusters.push({\n ids: cluster.map(o => o.id),\n titles: cluster.map(o => o.title),\n similarity: simCount > 0 ? totalSim / simCount : 0,\n entityName: cluster[0].entityName,\n type: cluster[0].type,\n });\n }\n }\n }\n\n return clusters;\n}\n\n/**\n * Find clusters of similar observations that could be consolidated.\n * Does NOT modify data — use this for preview / dry run.\n */\nexport async function findConsolidationCandidates(\n _projectDir: string,\n projectId: string,\n opts?: { threshold?: number; limit?: number; afterId?: number },\n): Promise<ConsolidationCluster[]> {\n const threshold = opts?.threshold ?? DEFAULT_SIMILARITY_THRESHOLD;\n const page = await loadConsolidationPage(projectId, opts ?? {});\n return findClusters(page.observations, threshold);\n}\n\n/**\n * Execute consolidation — merge clusters into single observations.\n *\n * For each cluster:\n * 1. Keep the most recent observation as the \"primary\"\n * 2. Merge facts, files, concepts from all members (deduplicated)\n * 3. Create a consolidated narrative\n * 4. Remove the other members\n */\nexport async function executeConsolidation(\n _projectDir: string,\n projectId: string,\n opts?: { threshold?: number; limit?: number; afterId?: number },\n): Promise<ConsolidationResult> {\n const store = getObservationStore();\n const page = await loadConsolidationPage(projectId, opts ?? {});\n const clusters = findClusters(page.observations, opts?.threshold ?? DEFAULT_SIMILARITY_THRESHOLD);\n\n if (clusters.length === 0) {\n return {\n clustersFound: 0,\n observationsMerged: 0,\n observationsAfter: await store.countByProject(projectId),\n scanned: page.observations.length,\n ...(page.nextCursor === undefined ? {} : { nextCursor: page.nextCursor }),\n merges: [],\n };\n }\n\n const result: ConsolidationResult = {\n clustersFound: clusters.length,\n observationsMerged: 0,\n observationsAfter: 0,\n scanned: page.observations.length,\n ...(page.nextCursor === undefined ? {} : { nextCursor: page.nextCursor }),\n merges: [],\n };\n\n await store.atomic(async (tx) => {\n const idsToRemove = new Set<number>();\n const updated = new Map<number, Observation>();\n\n for (let ci = 0; ci < clusters.length; ci++) {\n const cluster = clusters[ci];\n const members = (await Promise.all(cluster.ids.map((id) => tx.getById(id))))\n .filter((observation): observation is Observation => {\n if (!observation) return false;\n return observation.projectId === projectId\n && (observation.status ?? 'active') === 'active';\n });\n\n if (members.length < MIN_CLUSTER_SIZE) continue;\n\n // Sort by date — most recent first\n members.sort((a, b) =>\n new Date(b.updatedAt || b.createdAt).getTime() -\n new Date(a.updatedAt || a.createdAt).getTime(),\n );\n\n const primary = members[0];\n const others = members.slice(1);\n\n // Merge facts (deduplicated)\n const allFacts = new Set(primary.facts);\n for (const other of others) {\n for (const fact of other.facts) allFacts.add(fact);\n }\n\n // Merge files (deduplicated, case-insensitive)\n const fileSet = new Set(primary.filesModified.map(f => f.toLowerCase()));\n const allFiles = [...primary.filesModified];\n for (const other of others) {\n for (const f of other.filesModified) {\n if (!fileSet.has(f.toLowerCase())) {\n fileSet.add(f.toLowerCase());\n allFiles.push(f);\n }\n }\n }\n\n // Merge concepts (deduplicated)\n const conceptSet = new Set(primary.concepts);\n for (const other of others) {\n for (const c of other.concepts) conceptSet.add(c);\n }\n\n // Build consolidated narrative\n const narrativeParts = [primary.narrative];\n for (const other of others) {\n if (other.narrative !== primary.narrative) {\n narrativeParts.push(`[Consolidated from #${other.id}] ${other.narrative}`);\n }\n }\n\n // Update primary\n primary.facts = [...allFacts];\n primary.filesModified = allFiles;\n primary.concepts = [...conceptSet];\n primary.narrative = narrativeParts.join('\\n\\n');\n primary.updatedAt = new Date().toISOString();\n primary.revisionCount = (primary.revisionCount ?? 1) + others.length;\n updated.set(primary.id, primary);\n\n // Mark others for removal\n for (const other of others) {\n idsToRemove.add(other.id);\n }\n\n result.observationsMerged += others.length;\n result.merges.push({\n clusterId: ci,\n mergedIds: cluster.ids,\n resultTitle: primary.title,\n factCount: primary.facts.length,\n });\n }\n\n await Promise.all([...updated.values()].map((observation) => tx.update(observation)));\n await Promise.all([...idsToRemove].map((id) => tx.remove(id)));\n });\n\n result.observationsAfter = await store.countByProject(projectId);\n\n return result;\n}\n","/**\n * Memory Compact Engine\n *\n * Dual-mode memory management inspired by:\n * - Mem0's ADD/UPDATE/DELETE/NONE decision model with content merging\n * - Cipher's dual-mode architecture (LLM + heuristic fallback)\n *\n * Two paths:\n * 1. LLM mode (compactOnWrite): Single LLM call → extract facts + compare + decide + merge\n * 2. Free mode (heuristicCompact): Vector similarity → rule-based ADD/UPDATE/NONE\n *\n * Both paths produce a CompactDecision that the caller executes.\n */\n\nimport { callLLM, isLLMEnabled } from './provider.js';\n\n/** The decision the compact engine makes for each memory operation */\nexport type MemoryAction = 'ADD' | 'UPDATE' | 'DELETE' | 'NONE';\n\n/** Existing memory entry for comparison */\nexport interface ExistingMemory {\n id: number;\n title: string;\n narrative: string;\n facts: string;\n score: number;\n}\n\n/** The compact decision — what to do with the new memory */\nexport interface CompactDecision {\n action: MemoryAction;\n /** ID of existing memory to UPDATE/DELETE */\n targetId?: number;\n /** Brief explanation of why this action was chosen */\n reason: string;\n /** Merged narrative for UPDATE (Mem0-style rewrite) */\n mergedNarrative?: string;\n /** Merged facts for UPDATE */\n mergedFacts?: string[];\n /** LLM-extracted enriched facts (only in LLM mode) */\n enrichedFacts?: string[];\n /** Whether LLM was used for this decision */\n usedLLM: boolean;\n}\n\n/**\n * Unified Compact on Write prompt (Mem0-inspired, single LLM call).\n *\n * This prompt does 3 things in 1 call:\n * 1. Extract structured facts from the new content\n * 2. Compare with existing similar memories\n * 3. Decide ADD/UPDATE/DELETE/NONE and merge if needed\n */\nconst COMPACT_ON_WRITE_PROMPT = `You are a smart coding memory manager. You control the memory of a cross-IDE coding assistant.\n\nYou receive a NEW MEMORY to store and a list of EXISTING similar memories. Your job:\n1. Extract the key facts from the new memory\n2. Compare with existing memories\n3. Decide the best action\n\nActions:\n- ADD: New memory contains unique information. Store it as-is.\n- UPDATE: New memory supersedes or improves an existing one. Merge them into a single, comprehensive memory.\n- DELETE: An existing memory is outdated/contradicted by the new one. Remove it.\n- NONE: New memory is redundant. Existing memories already cover this. Skip storing.\n\nDecision rules:\n- Same topic updated (e.g., \"MySQL → PostgreSQL\"): UPDATE the old memory with merged content\n- Bug fixed that was reported as open: UPDATE the bug report to include the fix\n- Task completed that was tracked as in-progress: UPDATE to mark completed\n- Minor variation of existing memory: NONE (skip)\n- Completely new topic: ADD\n- Old info directly contradicted: DELETE the old one\n- Prefer UPDATE over ADD — keep memory count low, merge information\n\nFor UPDATE: write a merged narrative that combines the best of both old and new, preserving all important details. Also merge the facts lists, removing duplicates.\n\nRespond in JSON only:\n{\n \"action\": \"ADD\" | \"UPDATE\" | \"DELETE\" | \"NONE\",\n \"targetId\": null or existing_memory_id_number,\n \"reason\": \"brief explanation of decision\",\n \"mergedNarrative\": \"merged narrative text (required for UPDATE, null otherwise)\",\n \"mergedFacts\": [\"merged fact 1\", \"merged fact 2\"] or null,\n \"extractedFacts\": [\"fact extracted from new content 1\", \"fact 2\"]\n}`;\n\n// ─── Heuristic Constants (Cipher-inspired) ───────────────────────────\n\n/** Similarity threshold above which we consider memories as \"same topic\" */\nconst SIMILARITY_HIGH = 0.75;\n/** Similarity threshold for \"related but different\" */\nconst SIMILARITY_MEDIUM = 0.5;\n\n// ─── LLM Mode ────────────────────────────────────────────────────────\n\n/**\n * Compact on Write — LLM mode.\n *\n * Single LLM call that extracts facts, compares with existing memories,\n * and decides ADD/UPDATE/DELETE/NONE with merged content.\n *\n * Inspired by Mem0's `get_update_memory_messages` but unified into 1 call.\n */\nexport async function compactOnWrite(\n newMemory: { title: string; narrative: string; facts: string[] },\n existingMemories: ExistingMemory[],\n): Promise<CompactDecision> {\n if (!isLLMEnabled()) {\n return heuristicCompact(newMemory, existingMemories);\n }\n\n if (existingMemories.length === 0) {\n return { action: 'ADD', reason: 'No existing memories to compare', usedLLM: false };\n }\n\n // Build the prompt with new + existing memories (Mem0's temp_uuid_mapping approach)\n const existingList = existingMemories\n .map(m => `[ID: ${m.id}] (similarity: ${m.score.toFixed(2)}) ${m.title}\\n Narrative: ${m.narrative}\\n Facts: ${m.facts}`)\n .join('\\n\\n');\n\n const userMessage = `NEW MEMORY:\nTitle: ${newMemory.title}\nNarrative: ${newMemory.narrative}\nFacts: ${newMemory.facts.join('; ')}\n\nEXISTING SIMILAR MEMORIES:\n${existingList}`;\n\n try {\n const response = await callLLM(COMPACT_ON_WRITE_PROMPT, userMessage);\n\n // Parse response — handle markdown code blocks\n let content = response.content.trim();\n if (content.startsWith('```')) {\n content = content.replace(/^```(?:json)?\\s*/, '').replace(/\\s*```$/, '');\n }\n\n const parsed = JSON.parse(content) as {\n action: string;\n targetId?: number | null;\n reason?: string;\n mergedNarrative?: string | null;\n mergedFacts?: string[] | null;\n extractedFacts?: string[] | null;\n };\n\n // Validate action\n const action = parsed.action?.toUpperCase() as MemoryAction;\n if (!action || !['ADD', 'UPDATE', 'DELETE', 'NONE'].includes(action)) {\n return { action: 'ADD', reason: 'LLM response invalid, defaulting to ADD', usedLLM: true };\n }\n\n // Validate targetId exists in existing memories for UPDATE/DELETE\n if ((action === 'UPDATE' || action === 'DELETE') && parsed.targetId != null) {\n const targetExists = existingMemories.some(m => m.id === parsed.targetId);\n if (!targetExists) {\n // LLM hallucinated an ID (common issue noted in Mem0's code)\n return { action: 'ADD', reason: `LLM referenced non-existent memory #${parsed.targetId}, defaulting to ADD`, usedLLM: true };\n }\n }\n\n return {\n action,\n targetId: parsed.targetId ?? undefined,\n reason: parsed.reason ?? 'LLM decision',\n mergedNarrative: parsed.mergedNarrative ?? undefined,\n mergedFacts: parsed.mergedFacts ?? undefined,\n enrichedFacts: parsed.extractedFacts ?? undefined,\n usedLLM: true,\n };\n } catch (err) {\n // LLM failed — fall back to heuristic\n console.error(`[memorix] LLM compact failed, falling back to heuristic:`, (err as Error)?.message ?? err);\n return heuristicCompact(newMemory, existingMemories);\n }\n}\n\n// ─── Free Mode (Heuristic) ───────────────────────────────────────────\n\n/**\n * Heuristic Compact — Free mode, no LLM needed.\n *\n * Uses vector similarity scores from search results to make decisions.\n * Inspired by Cipher's fallback logic in extract_and_operate_memory.ts.\n *\n * Decision logic:\n * - score >= 0.75: Very similar → check if new is more complete\n * - New is longer/richer → UPDATE (merge)\n * - Otherwise → NONE (skip, already covered)\n * - score >= 0.50: Related topic\n * - Same entity + same type → UPDATE if new has more facts\n * - Otherwise → ADD (different enough)\n * - score < 0.50: Different topic → ADD\n */\nexport function heuristicCompact(\n newMemory: { title: string; narrative: string; facts: string[] },\n existingMemories: ExistingMemory[],\n): CompactDecision {\n if (existingMemories.length === 0) {\n return { action: 'ADD', reason: 'No existing memories to compare', usedLLM: false };\n }\n\n const best = existingMemories[0]; // Already sorted by score\n\n // High similarity — very likely same topic\n if (best.score >= SIMILARITY_HIGH) {\n const newLength = newMemory.narrative.length + newMemory.facts.join(' ').length;\n const oldLength = best.narrative.length + best.facts.length;\n\n if (newLength > oldLength * 1.2) {\n // New memory is substantially richer — UPDATE with merged content\n const mergedNarrative = mergeTexts(best.narrative, newMemory.narrative);\n const mergedFacts = mergeFacts(best.facts, newMemory.facts.join('\\n'));\n return {\n action: 'UPDATE',\n targetId: best.id,\n reason: `New memory is more comprehensive (${newLength} > ${oldLength} chars)`,\n mergedNarrative,\n mergedFacts,\n usedLLM: false,\n };\n }\n\n // New memory is not richer — skip it\n return {\n action: 'NONE',\n targetId: best.id,\n reason: `Existing memory #${best.id} already covers this topic (similarity: ${best.score.toFixed(2)})`,\n usedLLM: false,\n };\n }\n\n // Medium similarity — related but might be different enough\n if (best.score >= SIMILARITY_MEDIUM) {\n const newFactCount = newMemory.facts.length;\n const oldFactCount = best.facts.split('\\n').filter(Boolean).length;\n\n if (newFactCount > oldFactCount) {\n // New has more facts — UPDATE\n const mergedNarrative = mergeTexts(best.narrative, newMemory.narrative);\n const mergedFacts = mergeFacts(best.facts, newMemory.facts.join('\\n'));\n return {\n action: 'UPDATE',\n targetId: best.id,\n reason: `New memory has more facts (${newFactCount} > ${oldFactCount}), merging`,\n mergedNarrative,\n mergedFacts,\n usedLLM: false,\n };\n }\n\n // Related but not richer — ADD as separate memory\n return { action: 'ADD', reason: `Related to #${best.id} but different enough to keep separate`, usedLLM: false };\n }\n\n // Low similarity — new topic\n return { action: 'ADD', reason: 'No similar memories found', usedLLM: false };\n}\n\n// ─── Content Merging Utilities ───────────────────────────────────────\n\n/**\n * Merge two narrative texts, keeping the more comprehensive version\n * while preserving unique information from both.\n */\nfunction mergeTexts(oldText: string, newText: string): string {\n // If new text is significantly longer, prefer it\n if (newText.length > oldText.length * 1.5) return newText;\n // If old text is significantly longer, append new info\n if (oldText.length > newText.length * 1.5) return oldText;\n // Similar length — combine with separator\n return `${newText}\\n\\n[Previous context]: ${oldText}`;\n}\n\n/**\n * Merge two fact lists, removing duplicates.\n * oldFacts is newline-separated string, newFacts is array.\n */\nfunction mergeFacts(oldFactsStr: string, newFactsStr: string): string[] {\n const oldFacts = oldFactsStr.split('\\n').filter(Boolean).map(f => f.trim());\n const newFacts = newFactsStr.split('\\n').filter(Boolean).map(f => f.trim());\n\n const seen = new Set<string>();\n const merged: string[] = [];\n\n // Add new facts first (they're more recent)\n for (const f of newFacts) {\n const normalized = f.toLowerCase();\n if (!seen.has(normalized)) {\n seen.add(normalized);\n merged.push(f);\n }\n }\n\n // Add old facts that aren't duplicates\n for (const f of oldFacts) {\n const normalized = f.toLowerCase();\n if (!seen.has(normalized)) {\n seen.add(normalized);\n merged.push(f);\n }\n }\n\n return merged;\n}\n\n// ─── Batch Dedup (for memorix_deduplicate tool) ──────────────────────\n\n/**\n * LLM-powered dedup for batch cleanup.\n * Compares a new memory against existing ones and returns a decision.\n * Used by memorix_deduplicate tool.\n */\nexport async function deduplicateMemory(\n newMemory: { title: string; narrative: string; facts: string[] },\n existingMemories: Array<{ id: number; title: string; narrative: string; facts: string }>,\n): Promise<CompactDecision | null> {\n if (!isLLMEnabled()) return null;\n if (existingMemories.length === 0) return { action: 'ADD', reason: 'No existing memories', usedLLM: false };\n\n const asExisting: ExistingMemory[] = existingMemories.map(m => ({\n ...m,\n score: 0.8, // Batch dedup assumes high similarity (pre-filtered)\n }));\n\n return compactOnWrite(newMemory, asExisting);\n}\n","/**\n * Retention & Decay Engine\n *\n * Manages memory relevance over time using exponential decay.\n * Sources:\n * - mcp-memory-service: ExponentialDecayCalculator (importance × decay × access_boost)\n * - MemCP: Active → Archive → Purge lifecycle with immunity rules\n *\n * Relevance formula:\n * score = baseImportance × e^(-ageDays / retentionPeriod) × accessBoost × connectionBoost\n *\n * Immunity: observations with importance=critical, valueCategory=core, accessCount>=3,\n * or tagged \"keep\"/\"pinned\" are never auto-archived.\n * High-importance types (gotcha/decision/trade-off/reasoning) retain a long 180-day\n * retention period but are no longer permanently immune — they decay normally.\n */\n\nimport type { MemorixDocument, Observation, ObservationReader } from '../types.js';\nimport { getObservationStore } from '../store/obs-store.js';\nimport { canManageObservation } from './visibility.js';\n\n// ── Importance → Retention Period mapping ────────────────────────────\n\nexport type ImportanceLevel = 'critical' | 'high' | 'medium' | 'low';\n\nconst RETENTION_DAYS: Record<ImportanceLevel, number> = {\n critical: 365,\n high: 180,\n medium: 90,\n low: 30,\n};\n\nconst BASE_IMPORTANCE: Record<ImportanceLevel, number> = {\n critical: 1.0,\n high: 0.8,\n medium: 0.5,\n low: 0.3,\n};\n\n// ── Observation Type → Default Importance ────────────────────────────\n\nconst TYPE_IMPORTANCE: Record<string, ImportanceLevel> = {\n gotcha: 'high',\n decision: 'high',\n 'trade-off': 'high',\n reasoning: 'high',\n 'problem-solution': 'medium',\n 'how-it-works': 'medium',\n 'what-changed': 'low',\n 'why-it-exists': 'medium',\n discovery: 'low',\n 'session-request': 'low',\n probe: 'low',\n};\n\n/** Per-type retention period overrides (in days). When set, replaces the importance-based base retention. */\nconst TYPE_RETENTION_OVERRIDE: Partial<Record<string, number>> = {\n probe: 7, // Operational heartbeats: expire after ~7 days regardless of source/valueCategory\n};\n\n// ── Immunity ─────────────────────────────────────────────────────────\n\nconst PROTECTED_TAGS = new Set(['keep', 'important', 'pinned', 'critical']);\nconst MIN_ACCESS_FOR_IMMUNITY = 3;\n\n/** Minimum effective retention period in days — prevents extreme multiplier combinations\n * (e.g. hook × ephemeral = 0.25×) from producing unreasonably short windows. */\nconst MIN_RETENTION_DAYS = 7;\n\n/**\n * Get retention period multiplier based on sourceDetail.\n * Neutral (1.0) for unknown/undefined sourceDetail — backward-compatible.\n */\nfunction getSourceRetentionMultiplier(doc: MemorixDocument): number {\n if (doc.sourceDetail === 'hook') return 0.5; // hook auto-captures: half the retention period\n if (doc.sourceDetail === 'git-ingest') return 1.5; // git-backed truth: extend retention\n return 1.0; // explicit/undefined: neutral\n}\n\n/**\n * Get retention period multiplier based on valueCategory.\n * Neutral (1.0) for undefined/contextual — backward-compatible.\n */\nfunction getValueCategoryMultiplier(doc: MemorixDocument): number {\n if (doc.valueCategory === 'ephemeral') return 0.5; // short-lived context: decay faster\n if (doc.valueCategory === 'core') return 2.0; // durable knowledge: extend retention\n return 1.0; // contextual/undefined: neutral\n}\n\n/**\n * Compute the effective retention period in days, with floor applied.\n * Combines base retention (from importance/type) with source and valueCategory multipliers.\n */\nexport function getEffectiveRetentionDays(doc: MemorixDocument): number {\n const typeOverride = TYPE_RETENTION_OVERRIDE[doc.type];\n if (typeOverride !== undefined) {\n // Type-specific override: use the override directly, ignoring importance-based base retention.\n // Source multiplier still applies so that e.g. hook-sourced probes decay even faster.\n // valueCategory multiplier is intentionally excluded for type-override types:\n // probe + core must NOT extend to 14 days -- probe is always short-lived.\n const raw = typeOverride * getSourceRetentionMultiplier(doc);\n return Math.max(MIN_RETENTION_DAYS, raw);\n }\n const importance = getImportanceLevel(doc);\n const raw = RETENTION_DAYS[importance] * getSourceRetentionMultiplier(doc) * getValueCategoryMultiplier(doc);\n return Math.max(MIN_RETENTION_DAYS, raw);\n}\n\n/**\n * Check if an observation is immune from archiving/decay.\n * Immune observations maintain a minimum relevance score.\n */\nexport function isImmune(doc: MemorixDocument): boolean {\n // Probe observations are operational heartbeats -- never immune, regardless of valueCategory or access.\n if (doc.type === 'probe') return false;\n\n // A candidate has not earned durable status. Never let an automatic core\n // classification turn unqualified capture into permanently retained memory.\n if (doc.admissionState === 'candidate' || doc.admissionState === 'ephemeral') return false;\n\n // formation-classified core memories are immune regardless of type\n if (doc.valueCategory === 'core') return true;\n\n const importance = getImportanceLevel(doc);\n // Only 'critical' importance grants type-based immunity.\n // 'high' importance types (gotcha/decision/trade-off/reasoning) keep their long\n // 180-day retention period but are no longer permanently immune — this prevents\n // unbounded growth of never-accessed high-type observations.\n if (importance === 'critical') return true;\n if ((doc.accessCount ?? 0) >= MIN_ACCESS_FOR_IMMUNITY) return true;\n\n const concepts = doc.concepts?.split(', ').map((c) => c.toLowerCase()) ?? [];\n return concepts.some((c) => PROTECTED_TAGS.has(c));\n}\n\n/**\n * Return a human-readable reason for why an observation is immune, or null if not immune.\n */\nexport function getImmunityReason(doc: MemorixDocument): string | null {\n // Probe observations are never immune\n if (doc.type === 'probe') return null;\n\n // Automatic traces and candidates have not earned durable status. Keep the\n // explanation aligned with isImmune() even when an earlier classifier gave\n // a candidate the core value category.\n if (doc.admissionState === 'candidate' || doc.admissionState === 'ephemeral') return null;\n\n if (doc.valueCategory === 'core') return 'core valueCategory (formation-classified)';\n const importance = getImportanceLevel(doc);\n if (importance === 'critical') return 'critical importance';\n if ((doc.accessCount ?? 0) >= MIN_ACCESS_FOR_IMMUNITY) return `frequently accessed (${doc.accessCount}×)`;\n const concepts = doc.concepts?.split(', ').map((c) => c.toLowerCase()) ?? [];\n if (concepts.some((c) => PROTECTED_TAGS.has(c))) return 'protected tag';\n return null;\n}\n\n// ── Relevance Scoring ────────────────────────────────────────────────\n\nexport interface RelevanceScore {\n observationId: number;\n totalScore: number;\n baseImportance: number;\n decayFactor: number;\n accessBoost: number;\n ageDays: number;\n isImmune: boolean;\n}\n\n/**\n * Get the importance level for an observation based on its type.\n */\nexport function getImportanceLevel(doc: MemorixDocument): ImportanceLevel {\n return TYPE_IMPORTANCE[doc.type] ?? 'medium';\n}\n\n/**\n * Calculate the relevance score for a single observation.\n *\n * Formula (from mcp-memory-service):\n * score = baseImportance × e^(-ageDays / retentionPeriod) × accessBoost\n *\n * Access boost (from mcp-memory-service):\n * 1 + 0.1 × accessCount (10% boost per access, capped at 2.0)\n */\nexport function calculateRelevance(\n doc: MemorixDocument,\n referenceTime?: Date,\n): RelevanceScore {\n const now = referenceTime ?? new Date();\n const importance = getImportanceLevel(doc);\n const base = BASE_IMPORTANCE[importance];\n const retention = getEffectiveRetentionDays(doc);\n\n // Age in days\n const createdAt = new Date(doc.createdAt);\n const ageDays = Math.max(0, (now.getTime() - createdAt.getTime()) / (1000 * 60 * 60 * 24));\n\n // Exponential decay\n const decayFactor = Math.exp(-ageDays / retention);\n\n // Access boost: 10% per access, capped at 2.0×\n const accessCount = doc.accessCount ?? 0;\n const accessBoost = Math.min(2.0, 1 + 0.1 * accessCount);\n\n let totalScore = base * decayFactor * accessBoost;\n\n // Immune observations get minimum 0.5 relevance\n const immune = isImmune(doc);\n if (immune) {\n totalScore = Math.max(totalScore, 0.5);\n }\n\n return {\n observationId: doc.observationId,\n totalScore,\n baseImportance: base,\n decayFactor,\n accessBoost,\n ageDays,\n isImmune: immune,\n };\n}\n\n/**\n * Score and rank observations by relevance.\n * Returns sorted (highest relevance first) with scores.\n */\nexport function rankByRelevance(\n docs: MemorixDocument[],\n referenceTime?: Date,\n): RelevanceScore[] {\n return docs\n .map((doc) => calculateRelevance(doc, referenceTime))\n .sort((a, b) => b.totalScore - a.totalScore);\n}\n\n// ── Retention Lifecycle ──────────────────────────────────────────────\n\nexport type RetentionZone = 'active' | 'stale' | 'archive-candidate';\n\n/**\n * Classify an observation into a retention zone.\n *\n * Lifecycle (from MemCP):\n * Active: recently accessed or high importance\n * Stale: not accessed, beyond 50% of retention period\n * Archive-candidate: not accessed, beyond 100% of retention period, not immune\n */\nexport function getRetentionZone(doc: MemorixDocument, referenceTime?: Date): RetentionZone {\n const now = referenceTime ?? new Date();\n const importance = getImportanceLevel(doc);\n const retention = getEffectiveRetentionDays(doc);\n\n const createdAt = new Date(doc.createdAt);\n const ageDays = (now.getTime() - createdAt.getTime()) / (1000 * 60 * 60 * 24);\n\n // Recently accessed = active regardless of age\n if (doc.lastAccessedAt) {\n const lastAccess = new Date(doc.lastAccessedAt);\n const daysSinceAccess = (now.getTime() - lastAccess.getTime()) / (1000 * 60 * 60 * 24);\n if (daysSinceAccess < 7) return 'active';\n }\n\n if (isImmune(doc)) return 'active';\n if (ageDays > retention) return 'archive-candidate';\n if (ageDays > retention * 0.5) return 'stale';\n return 'active';\n}\n\n/**\n * Get archive candidates from a list of observations.\n * Returns observations that are beyond their retention period and not immune.\n */\nexport function getArchiveCandidates(\n docs: MemorixDocument[],\n referenceTime?: Date,\n): MemorixDocument[] {\n return docs.filter((doc) => getRetentionZone(doc, referenceTime) === 'archive-candidate');\n}\n\n/**\n * Get retention summary statistics.\n */\nexport function getRetentionSummary(\n docs: MemorixDocument[],\n referenceTime?: Date,\n): { active: number; stale: number; archiveCandidates: number; immune: number } {\n let active = 0;\n let stale = 0;\n let archiveCandidates = 0;\n let immune = 0;\n\n for (const doc of docs) {\n const zone = getRetentionZone(doc, referenceTime);\n if (zone === 'active') active++;\n else if (zone === 'stale') stale++;\n else archiveCandidates++;\n if (isImmune(doc)) immune++;\n }\n\n return { active, stale, archiveCandidates, immune };\n}\n\n// ── Retention Explainability ─────────────────────────────────────────\n\nexport interface RetentionExplanation {\n observationId: number;\n importanceLevel: ImportanceLevel;\n baseRetentionDays: number;\n sourceMultiplier: number;\n valueCategoryMultiplier: number;\n effectiveRetentionDays: number;\n zone: RetentionZone;\n immune: boolean;\n /** Human-readable reason for immunity, or null when not immune. */\n immunityReason: string | null;\n ageDays: number;\n /** Short human-readable summary of the retention posture. */\n summary: string;\n}\n\n/**\n * Produce a structured explanation of why an observation has its current\n * retention posture. Designed for operator-facing reporting.\n */\nexport function explainRetention(\n doc: MemorixDocument,\n referenceTime?: Date,\n): RetentionExplanation {\n const importance = getImportanceLevel(doc);\n const baseRetention = RETENTION_DAYS[importance];\n const srcMul = getSourceRetentionMultiplier(doc);\n const vcMul = getValueCategoryMultiplier(doc);\n const effective = getEffectiveRetentionDays(doc);\n const zone = getRetentionZone(doc, referenceTime);\n const immuneFlag = isImmune(doc);\n const immunityReason = getImmunityReason(doc);\n\n const now = referenceTime ?? new Date();\n const ageDays = Math.max(\n 0,\n (now.getTime() - new Date(doc.createdAt).getTime()) / (1000 * 60 * 60 * 24),\n );\n\n // Build a concise human-readable summary\n const parts: string[] = [];\n parts.push(`${importance} importance (${baseRetention}d base)`);\n if (srcMul !== 1.0) parts.push(`source ${srcMul}×`);\n if (vcMul !== 1.0) parts.push(`valueCategory ${vcMul}×`);\n parts.push(`→ ${effective}d effective`);\n if (immuneFlag) {\n parts.push(`immune: ${immunityReason}`);\n } else {\n parts.push(`zone: ${zone}`);\n }\n\n return {\n observationId: doc.observationId,\n importanceLevel: importance,\n baseRetentionDays: baseRetention,\n sourceMultiplier: srcMul,\n valueCategoryMultiplier: vcMul,\n effectiveRetentionDays: effective,\n zone,\n immune: immuneFlag,\n immunityReason,\n ageDays: Math.round(ageDays),\n // Summary is rendered inside markdown table cells in memorix_retention output,\n // so avoid pipe separators that would split the row into extra columns.\n summary: parts.join(' ; '),\n };\n}\n\n// ── Auto-Archive ────────────────────────────────────────────────────\n\nexport interface ArchiveExpiredBatchOptions {\n projectId: string;\n afterId?: number;\n limit?: number;\n referenceTime?: Date;\n accessMap?: Map<number, { accessCount: number; lastAccessedAt: string }>;\n /** Omit only for trusted background maintenance. */\n reader?: ObservationReader;\n}\n\nexport interface ArchiveExpiredBatchResult {\n archived: number;\n scanned: number;\n nextCursor?: number;\n}\n\nfunction toRetentionDocument(\n obs: Observation,\n accessMap?: Map<number, { accessCount: number; lastAccessedAt: string }>,\n): MemorixDocument {\n const access = accessMap?.get(obs.id);\n return {\n id: `obs-${obs.id}`,\n observationId: obs.id,\n entityName: obs.entityName,\n type: obs.type,\n title: obs.title,\n narrative: obs.narrative,\n facts: obs.facts.join('\\n'),\n filesModified: obs.filesModified.join('\\n'),\n concepts: obs.concepts.join(', '),\n tokens: obs.tokens,\n createdAt: obs.createdAt,\n projectId: obs.projectId,\n accessCount: access?.accessCount ?? 0,\n lastAccessedAt: access?.lastAccessedAt ?? '',\n status: obs.status ?? 'active',\n source: obs.source ?? 'agent',\n sourceDetail: obs.sourceDetail ?? '',\n valueCategory: obs.valueCategory ?? '',\n admissionState: obs.admissionState ?? '',\n admissionReason: obs.admissionReason ?? '',\n };\n}\n\n/**\n * Archive one bounded page of a project's active memories. The caller owns the\n * cursor, which makes the operation safe to run from a durable maintenance job.\n */\nexport async function archiveExpiredBatch(\n _projectDir: string,\n options: ArchiveExpiredBatchOptions,\n): Promise<ArchiveExpiredBatchResult> {\n const store = getObservationStore();\n const limit = Math.min(500, Math.max(1, Math.floor(options.limit ?? 100)));\n const afterId = Math.max(0, Math.floor(options.afterId ?? 0));\n const page = await store.loadByProject(options.projectId, {\n status: 'active',\n afterId,\n limit: limit + 1,\n });\n const hasMore = page.length > limit;\n const scanned = hasMore ? page.slice(0, limit) : page;\n const candidateIds = scanned\n .filter((observation) => !options.reader || canManageObservation(observation, options.reader))\n .filter((observation) => getRetentionZone(\n toRetentionDocument(observation, options.accessMap),\n options.referenceTime,\n ) === 'archive-candidate')\n .map((observation) => observation.id);\n\n const archived = candidateIds.length === 0\n ? 0\n : await store.atomic(async (tx) => {\n const updates = await Promise.all(\n candidateIds.map((id) => tx.setStatus(id, 'archived', 'active')),\n );\n return updates.filter(Boolean).length;\n });\n\n const nextCursor = hasMore && scanned.length > 0\n ? scanned[scanned.length - 1].id\n : undefined;\n return nextCursor === undefined\n ? { archived, scanned: scanned.length }\n : { archived, scanned: scanned.length, nextCursor };\n}\n\n/**\n * Archive expired observations by setting status='archived' in-place.\n *\n * Phase 2 change: instead of moving observations to a separate\n * observations.archived.json file, we update their status in the\n * canonical store (SQLite or JSON). This eliminates the separate\n * archive file and keeps all observation data in one place.\n *\n * Returns the count of archived observations.\n */\nexport async function archiveExpired(\n projectDir: string,\n referenceTime?: Date,\n accessMap?: Map<number, { accessCount: number; lastAccessedAt: string }>,\n projectId?: string,\n reader?: ObservationReader,\n): Promise<{ archived: number; remaining: number }> {\n const store = getObservationStore();\n if (projectId) {\n let afterId: number | undefined;\n let archived = 0;\n do {\n const batch = await archiveExpiredBatch(projectDir, {\n projectId,\n afterId,\n referenceTime,\n accessMap,\n reader,\n });\n archived += batch.archived;\n afterId = batch.nextCursor;\n } while (afterId !== undefined);\n\n const remainingObservations = await store.loadByProject(projectId, { status: 'active' });\n const remaining = reader\n ? remainingObservations.filter((observation) => canManageObservation(observation, reader)).length\n : remainingObservations.length;\n return { archived, remaining };\n }\n\n return await store.atomic(async (tx) => {\n const allObs = await tx.loadAll();\n\n // Only consider active observations for archiving\n const activeObs = allObs.filter((observation) =>\n (observation.status ?? 'active') === 'active' &&\n (!projectId || observation.projectId === projectId),\n );\n const archivedIds: number[] = [];\n\n for (const obs of activeObs) {\n const doc = toRetentionDocument(obs, accessMap);\n const zone = getRetentionZone(doc, referenceTime);\n if (zone === 'archive-candidate') {\n archivedIds.push(obs.id);\n }\n }\n\n if (archivedIds.length === 0) {\n return { archived: 0, remaining: activeObs.length };\n }\n\n const updates = await Promise.all(archivedIds.map((id) => tx.setStatus(id, 'archived', 'active')));\n const archived = updates.filter(Boolean).length;\n\n return { archived, remaining: activeObs.length - archived };\n });\n}\n","import { execFile } from 'node:child_process';\nimport { createHash } from 'node:crypto';\nimport { promisify } from 'node:util';\nimport type {\n CodeGraphProviderKind,\n CodeStateScanCompleteness,\n CodeStateSnapshotInput,\n CodeStateWorktreeState,\n} from './types.js';\n\nconst execFileAsync = promisify(execFile);\nconst GIT_TIMEOUT_MS = 3_000;\nconst GIT_MAX_BUFFER_BYTES = 256 * 1024;\n\ninterface GitResult {\n ok: boolean;\n output: Buffer;\n}\n\nasync function runGit(rootPath: string, args: string[]): Promise<GitResult> {\n try {\n const result = await execFileAsync('git', ['-C', rootPath, ...args], {\n encoding: 'buffer',\n windowsHide: true,\n timeout: GIT_TIMEOUT_MS,\n maxBuffer: GIT_MAX_BUFFER_BYTES,\n });\n const output = Buffer.isBuffer(result.stdout)\n ? result.stdout\n : Buffer.from(result.stdout ?? '');\n return { ok: true, output };\n } catch {\n return { ok: false, output: Buffer.alloc(0) };\n }\n}\n\nfunction changedPathCount(status: Buffer): number {\n const entries = status.toString('utf8').split('\\0');\n let count = 0;\n for (let index = 0; index < entries.length; index++) {\n const entry = entries[index];\n if (!entry) continue;\n count++;\n const code = entry.slice(0, 2);\n if (code.includes('R') || code.includes('C')) index++;\n }\n return count;\n}\n\nfunction fingerprint(baseRevision: string | undefined, status: Buffer): string {\n return createHash('sha256')\n .update(baseRevision ?? '')\n .update('\\0')\n .update(status)\n .digest('hex');\n}\n\nexport interface CollectCodeStateInput {\n projectId: string;\n projectRoot: string;\n provider: CodeGraphProviderKind;\n indexedAt: string;\n completeness: CodeStateScanCompleteness;\n}\n\n/**\n * Capture bounded Git metadata for a completed scan. No source file contents\n * are copied into the snapshot, and an unavailable Git executable is explicit\n * instead of being treated as a clean worktree.\n */\nexport async function collectCodeStateSnapshot(\n input: CollectCodeStateInput,\n): Promise<CodeStateSnapshotInput> {\n const [revision, status] = await Promise.all([\n runGit(input.projectRoot, ['rev-parse', 'HEAD']),\n runGit(input.projectRoot, ['status', '--porcelain=v1', '-z', '--untracked-files=normal']),\n ]);\n const baseRevision = revision.ok\n ? revision.output.toString('utf8').trim() || undefined\n : undefined;\n const worktreeState: CodeStateWorktreeState = status.ok\n ? (status.output.length > 0 ? 'dirty' : 'clean')\n : 'unavailable';\n\n return {\n projectId: input.projectId,\n provider: input.provider,\n ...(baseRevision ? { baseRevision } : {}),\n worktreeFingerprint: fingerprint(baseRevision, status.ok ? status.output : Buffer.alloc(0)),\n worktreeState,\n changedPathCount: status.ok ? changedPathCount(status.output) : 0,\n indexedAt: input.indexedAt,\n completeness: input.completeness,\n };\n}\n","export const DEFAULT_CODEGRAPH_EXCLUDES = [\n 'node_modules/**',\n 'dist/**',\n 'build/**',\n 'coverage/**',\n '.next/**',\n '.turbo/**',\n '.git/**',\n '.tmp/**',\n '.worktrees/**',\n '.claude/worktrees/**',\n 'vendor/**',\n '.venv/**',\n 'venv/**',\n '.tox/**',\n 'target/**',\n '.gradle/**',\n '.mvn/**',\n 'obj/**',\n 'Pods/**',\n 'DerivedData/**',\n];\n\nexport function normalizeCodeGraphExcludePatterns(exclude?: string[]): string[] {\n return [...new Set([\n ...DEFAULT_CODEGRAPH_EXCLUDES,\n ...(exclude ?? []).map(pattern => pattern.trim()).filter(Boolean),\n ])];\n}\n\nexport function isCodeGraphExcludedPath(path: string, exclude?: string[]): boolean {\n const normalized = normalizeCodePath(path);\n return normalizeCodeGraphExcludePatterns(exclude).some((pattern) => matchesPattern(normalized, normalizeCodePath(pattern)));\n}\n\nfunction normalizeCodePath(path: string): string {\n return path.replace(/\\\\/g, '/').replace(/^\\.\\/+/, '');\n}\n\nfunction matchesPattern(path: string, pattern: string): boolean {\n if (pattern.endsWith('/**')) {\n const base = pattern.slice(0, -3);\n if (base.startsWith('**/')) {\n const suffix = base.slice(3);\n return path === suffix || path.endsWith(`/${suffix}`) || path.includes(`/${suffix}/`);\n }\n if (!base.includes('/')) {\n return path === base || path.startsWith(`${base}/`) || path.includes(`/${base}/`);\n }\n return path === base || path.startsWith(`${base}/`);\n }\n if (pattern.startsWith('**/')) {\n const suffix = pattern.slice(3);\n return path === suffix || path.endsWith(`/${suffix}`);\n }\n return path === pattern || path.startsWith(`${pattern}/`);\n}\n","import { createHash } from 'node:crypto';\nimport { readdirSync, readFileSync, statSync, type Dirent } from 'node:fs';\nimport { join, relative } from 'node:path';\nimport type { CodeEdge, CodeFile, CodeStateSnapshot, CodeSymbol } from './types.js';\nimport { collectCodeStateSnapshot } from './code-state.js';\nimport { makeCodeEdgeId, makeCodeFileId, makeCodeSymbolId, normalizeCodePath } from './ids.js';\nimport { isCodeGraphExcludedPath, normalizeCodeGraphExcludePatterns } from './exclude.js';\nimport { CodeGraphStore, type CodeGraphFileDelta } from './store.js';\n\nexport interface LiteIndexOptions {\n projectId: string;\n projectRoot: string;\n exclude?: string[];\n maxFiles?: number;\n maxFileBytes?: number;\n}\n\nexport interface LiteIndexResult {\n files: CodeFile[];\n symbols: CodeSymbol[];\n edges: CodeEdge[];\n skippedOversizedFiles: number;\n unreadableFiles: number;\n}\n\nexport interface LiteRefreshResult {\n scannedFiles: number;\n changedFiles: number;\n unchangedFiles: number;\n metadataOnlyFiles: number;\n removedFiles: number;\n indexedSymbols: number;\n indexedEdges: number;\n skippedOversizedFiles: number;\n unreadableFiles: number;\n removalScanDeferred: boolean;\n snapshot: CodeStateSnapshot;\n}\n\nexport const DEFAULT_CODEGRAPH_MAX_FILE_BYTES = 2 * 1024 * 1024;\n\nconst LANGUAGE_BY_EXTENSION = new Map<string, string>([\n ['.ts', 'typescript'],\n ['.tsx', 'typescript'],\n ['.js', 'javascript'],\n ['.jsx', 'javascript'],\n ['.mjs', 'javascript'],\n ['.cjs', 'javascript'],\n ['.py', 'python'],\n ['.go', 'go'],\n ['.rs', 'rust'],\n ['.java', 'java'],\n ['.cs', 'csharp'],\n ['.c', 'c'],\n ['.h', 'c'],\n ['.cpp', 'cpp'],\n ['.cc', 'cpp'],\n ['.cxx', 'cpp'],\n ['.hpp', 'cpp'],\n ['.hh', 'cpp'],\n ['.hxx', 'cpp'],\n ['.php', 'php'],\n ['.rb', 'ruby'],\n ['.kt', 'kotlin'],\n ['.kts', 'kotlin'],\n]);\n\nconst SUPPORTED_EXTENSIONS = new Set(LANGUAGE_BY_EXTENSION.keys());\n\ninterface SymbolPattern {\n kind: CodeSymbol['kind'];\n re: RegExp;\n}\n\ninterface LanguageProfile {\n symbols: SymbolPattern[];\n imports: RegExp[];\n}\n\nconst identifier = String.raw`([A-Za-z_$][\\w$]*)`;\nconst languageProfiles: Record<string, LanguageProfile> = {\n typescript: {\n symbols: [\n { kind: 'function', re: new RegExp(String.raw`(?:export\\s+)?(?:async\\s+)?function\\s+${identifier}\\s*\\([^)]*\\)`, 'g') },\n { kind: 'class', re: new RegExp(String.raw`(?:export\\s+)?class\\s+${identifier}\\b`, 'g') },\n { kind: 'interface', re: new RegExp(String.raw`(?:export\\s+)?interface\\s+${identifier}\\b`, 'g') },\n { kind: 'type', re: new RegExp(String.raw`(?:export\\s+)?type\\s+${identifier}\\b`, 'g') },\n { kind: 'constant', re: new RegExp(String.raw`(?:export\\s+)?const\\s+${identifier}\\s*=`, 'g') },\n ],\n imports: [/import\\s+(?:[^'\"]+\\s+from\\s+)?['\"]([^'\"]+)['\"]/g],\n },\n javascript: {\n symbols: [\n { kind: 'function', re: new RegExp(String.raw`(?:export\\s+)?(?:async\\s+)?function\\s+${identifier}\\s*\\([^)]*\\)`, 'g') },\n { kind: 'class', re: new RegExp(String.raw`(?:export\\s+)?class\\s+${identifier}\\b`, 'g') },\n { kind: 'constant', re: new RegExp(String.raw`(?:export\\s+)?const\\s+${identifier}\\s*=`, 'g') },\n ],\n imports: [/import\\s+(?:[^'\"]+\\s+from\\s+)?['\"]([^'\"]+)['\"]/g, /require\\(['\"]([^'\"]+)['\"]\\)/g],\n },\n python: {\n symbols: [\n { kind: 'class', re: /^class\\s+([A-Za-z_][\\w]*)\\b/gm },\n { kind: 'function', re: /^def\\s+([A-Za-z_][\\w]*)\\s*\\(/gm },\n { kind: 'function', re: /^async\\s+def\\s+([A-Za-z_][\\w]*)\\s*\\(/gm },\n ],\n imports: [/^import\\s+([A-Za-z_][\\w.]*)(?:\\s+as\\s+\\w+)?/gm, /^from\\s+([A-Za-z_][\\w.]*)\\s+import\\s+/gm],\n },\n go: {\n symbols: [\n { kind: 'function', re: /^func\\s+(?:\\([^)]+\\)\\s*)?([A-Za-z_][\\w]*)\\s*\\(/gm },\n { kind: 'type', re: /^type\\s+([A-Za-z_][\\w]*)\\s+(?:struct|interface)\\b/gm },\n ],\n imports: [/import\\s+\"([^\"]+)\"/g, /import\\s*\\(([\\s\\S]*?)\\)/g],\n },\n rust: {\n symbols: [\n { kind: 'function', re: /(?:pub\\s+)?fn\\s+([A-Za-z_][\\w]*)\\s*\\(/g },\n { kind: 'class', re: /(?:pub\\s+)?struct\\s+([A-Za-z_][\\w]*)\\b/g },\n { kind: 'type', re: /(?:pub\\s+)?enum\\s+([A-Za-z_][\\w]*)\\b/g },\n { kind: 'interface', re: /(?:pub\\s+)?trait\\s+([A-Za-z_][\\w]*)\\b/g },\n ],\n imports: [/use\\s+([^;]+);/g],\n },\n java: {\n symbols: [\n { kind: 'class', re: /\\b(?:public|private|protected)?\\s*(?:abstract\\s+|final\\s+)?class\\s+([A-Za-z_][\\w]*)\\b/g },\n { kind: 'interface', re: /\\b(?:public|private|protected)?\\s*interface\\s+([A-Za-z_][\\w]*)\\b/g },\n { kind: 'method', re: /\\b(?:public|private|protected)\\s+(?:static\\s+)?(?:final\\s+)?[A-Za-z_<>\\[\\], ?]+\\s+([A-Za-z_][\\w]*)\\s*\\([^)]*\\)\\s*\\{/g },\n ],\n imports: [/import\\s+([^;]+);/g],\n },\n csharp: {\n symbols: [\n { kind: 'class', re: /\\b(?:public|private|protected|internal)?\\s*(?:abstract\\s+|sealed\\s+|static\\s+)?class\\s+([A-Za-z_][\\w]*)\\b/g },\n { kind: 'interface', re: /\\b(?:public|private|protected|internal)?\\s*interface\\s+([A-Za-z_][\\w]*)\\b/g },\n { kind: 'method', re: /\\b(?:public|private|protected|internal)\\s+(?:static\\s+)?[A-Za-z_<>\\[\\], ?]+\\s+([A-Za-z_][\\w]*)\\s*\\([^)]*\\)\\s*\\{/g },\n ],\n imports: [/using\\s+([^;]+);/g],\n },\n c: {\n symbols: [\n { kind: 'type', re: /\\bstruct\\s+([A-Za-z_][\\w]*)\\b/g },\n { kind: 'function', re: /^(?:[A-Za-z_][\\w]*\\s+)+([A-Za-z_][\\w]*)\\s*\\([^;{}]*\\)\\s*\\{/gm },\n ],\n imports: [/#include\\s+[<\"]([^>\"]+)[>\"]/g],\n },\n cpp: {\n symbols: [\n { kind: 'class', re: /\\bclass\\s+([A-Za-z_][\\w]*)\\b/g },\n { kind: 'type', re: /\\bstruct\\s+([A-Za-z_][\\w]*)\\b/g },\n { kind: 'function', re: /^(?:[A-Za-z_:][\\w:<>,~*&\\s]*\\s+)+([A-Za-z_][\\w]*)\\s*\\([^;{}]*\\)\\s*\\{/gm },\n ],\n imports: [/#include\\s+[<\"]([^>\"]+)[>\"]/g],\n },\n php: {\n symbols: [\n { kind: 'class', re: /\\bclass\\s+([A-Za-z_][\\w]*)\\b/g },\n { kind: 'interface', re: /\\binterface\\s+([A-Za-z_][\\w]*)\\b/g },\n { kind: 'function', re: /\\bfunction\\s+([A-Za-z_][\\w]*)\\s*\\(/g },\n ],\n imports: [/(?:require|include)(?:_once)?\\s*\\(?\\s*['\"]([^'\"]+)['\"]/g],\n },\n ruby: {\n symbols: [\n { kind: 'class', re: /^class\\s+([A-Za-z_][\\w]*(?:::[A-Za-z_][\\w]*)*)/gm },\n { kind: 'function', re: /^def\\s+([A-Za-z_][\\w]*[!?=]?)/gm },\n ],\n imports: [/require\\s+['\"]([^'\"]+)['\"]/g],\n },\n kotlin: {\n symbols: [\n { kind: 'class', re: /\\bclass\\s+([A-Za-z_][\\w]*)\\b/g },\n { kind: 'interface', re: /\\binterface\\s+([A-Za-z_][\\w]*)\\b/g },\n { kind: 'function', re: /\\bfun\\s+([A-Za-z_][\\w]*)\\s*\\(/g },\n ],\n imports: [/import\\s+([A-Za-z_][\\w.]+)/g],\n },\n};\n\nfunction hashText(text: string): string {\n return createHash('sha256').update(text).digest('hex');\n}\n\nfunction extension(path: string): string {\n const index = path.lastIndexOf('.');\n return index === -1 ? '' : path.slice(index);\n}\n\nfunction languageForPath(path: string): string {\n const ext = extension(path);\n return LANGUAGE_BY_EXTENSION.get(ext) ?? 'unknown';\n}\n\nfunction resolveMaxFileBytes(value: number | undefined): number {\n if (!Number.isFinite(value)) return DEFAULT_CODEGRAPH_MAX_FILE_BYTES;\n return Math.max(1, Math.floor(value!));\n}\n\nfunction walk(root: string, exclude: string[], maxFiles: number): string[] {\n const out: string[] = [];\n const visit = (dir: string) => {\n if (out.length >= maxFiles) return;\n let entries: Dirent<string>[];\n try {\n entries = readdirSync(dir, { withFileTypes: true });\n } catch {\n return;\n }\n\n for (const entry of entries) {\n const abs = join(dir, entry.name);\n const rel = normalizeCodePath(relative(root, abs));\n if (isCodeGraphExcludedPath(rel, exclude)) continue;\n if (entry.isDirectory()) {\n if (entry.name === '.git' || entry.name === '.worktrees' || entry.name === '.tmp' || entry.name === 'node_modules') continue;\n if (rel === '.claude/worktrees' || rel.startsWith('.claude/worktrees/')) continue;\n visit(abs);\n if (out.length >= maxFiles) return;\n continue;\n }\n if (!entry.isFile()) continue;\n if (!SUPPORTED_EXTENSIONS.has(extension(entry.name))) continue;\n out.push(abs);\n if (out.length >= maxFiles) return;\n }\n };\n visit(root);\n return out;\n}\n\nfunction lineOf(text: string, index: number): number {\n return text.slice(0, index).split(/\\r?\\n/).length;\n}\n\nfunction extractSymbols(projectId: string, file: CodeFile, text: string, indexedAt: string): CodeSymbol[] {\n const symbols: CodeSymbol[] = [];\n const profile = file.language ? languageProfiles[file.language] : undefined;\n const patterns = profile?.symbols ?? [];\n\n for (const { kind, re } of patterns) {\n re.lastIndex = 0;\n for (const match of text.matchAll(re)) {\n const name = match[1];\n if (!name || name.includes('\\n')) continue;\n const startLine = lineOf(text, match.index ?? 0);\n const id = makeCodeSymbolId({ projectId, path: file.path, qualifiedName: name, kind });\n symbols.push({\n id,\n projectId,\n fileId: file.id,\n path: file.path,\n name,\n qualifiedName: name,\n kind,\n startLine,\n endLine: startLine,\n signature: match[0].slice(0, 160),\n contentHash: hashText(match[0]),\n indexedAt,\n });\n }\n }\n return symbols;\n}\n\nfunction extractImportEdges(projectId: string, file: CodeFile, text: string, indexedAt: string): CodeEdge[] {\n const edges: CodeEdge[] = [];\n const profile = file.language ? languageProfiles[file.language] : undefined;\n const imports = profile?.imports ?? [];\n\n for (const re of imports) {\n re.lastIndex = 0;\n for (const match of text.matchAll(re)) {\n const target = (match[1] ?? '').trim();\n if (!target) continue;\n if (target.includes('\\n')) {\n for (const line of target.split(/\\r?\\n/).map(item => item.trim().replace(/^\"|\"$/g, '')).filter(Boolean)) {\n const id = makeCodeEdgeId(projectId, file.id, 'imports', line);\n edges.push({\n id,\n projectId,\n fromFileId: file.id,\n type: 'imports',\n confidence: 0.7,\n evidence: line,\n indexedAt,\n });\n }\n continue;\n }\n const id = makeCodeEdgeId(projectId, file.id, 'imports', target);\n edges.push({\n id,\n projectId,\n fromFileId: file.id,\n type: 'imports',\n confidence: 0.7,\n evidence: target,\n indexedAt,\n });\n }\n }\n return edges;\n}\n\ninterface LiteFileIndexAttempt {\n delta?: CodeGraphFileDelta;\n unreadable: boolean;\n}\n\nfunction indexFileLite(\n projectId: string,\n projectRoot: string,\n abs: string,\n indexedAt: string,\n fileStat?: ReturnType<typeof statSync>,\n): LiteFileIndexAttempt {\n const rel = normalizeCodePath(relative(projectRoot, abs));\n try {\n const text = readFileSync(abs, 'utf-8');\n const stat = fileStat ?? statSync(abs);\n const file: CodeFile = {\n id: makeCodeFileId(projectId, rel),\n projectId,\n path: rel,\n language: languageForPath(rel),\n contentHash: hashText(text),\n // Preserve filesystem precision. Rounding here made same-size edits in\n // a short Windows timestamp window indistinguishable to refresh.\n mtimeMs: Number(stat.mtimeMs),\n sizeBytes: Number(stat.size),\n indexedAt,\n };\n return {\n delta: {\n file,\n symbols: extractSymbols(projectId, file, text, indexedAt),\n edges: extractImportEdges(projectId, file, text, indexedAt),\n },\n unreadable: false,\n };\n } catch {\n return { unreadable: true };\n }\n}\n\nexport async function indexProjectLite(options: LiteIndexOptions): Promise<LiteIndexResult> {\n const exclude = normalizeCodeGraphExcludePatterns(options.exclude);\n const maxFiles = options.maxFiles ?? 5000;\n const maxFileBytes = resolveMaxFileBytes(options.maxFileBytes);\n const indexedAt = new Date().toISOString();\n const paths = walk(options.projectRoot, exclude, maxFiles);\n const files: CodeFile[] = [];\n const symbols: CodeSymbol[] = [];\n const edges: CodeEdge[] = [];\n let skippedOversizedFiles = 0;\n let unreadableFiles = 0;\n\n for (const abs of paths) {\n let stat: ReturnType<typeof statSync>;\n try {\n stat = statSync(abs);\n } catch {\n unreadableFiles++;\n continue;\n }\n if (Number(stat.size) > maxFileBytes) {\n skippedOversizedFiles++;\n continue;\n }\n const attempt = indexFileLite(options.projectId, options.projectRoot, abs, indexedAt, stat);\n if (!attempt.delta) {\n if (attempt.unreadable) unreadableFiles++;\n continue;\n }\n files.push(attempt.delta.file);\n symbols.push(...attempt.delta.symbols);\n edges.push(...attempt.delta.edges);\n }\n\n return { files, symbols, edges, skippedOversizedFiles, unreadableFiles };\n}\n\n/**\n * Refresh the Lite graph incrementally. A directory walk is still necessary to\n * discover deletes, but unchanged files are not read, hashed, or reparsed.\n */\nexport async function refreshProjectLite(\n store: CodeGraphStore,\n options: LiteIndexOptions,\n): Promise<LiteRefreshResult> {\n const exclude = normalizeCodeGraphExcludePatterns(options.exclude);\n const maxFiles = options.maxFiles ?? 5000;\n const maxFileBytes = resolveMaxFileBytes(options.maxFileBytes);\n const indexedAt = new Date().toISOString();\n const paths = walk(options.projectRoot, exclude, maxFiles);\n const existingByPath = new Map(store.listFiles(options.projectId).map((file) => [file.path, file]));\n const changed: CodeGraphFileDelta[] = [];\n const metadataOnly: CodeFile[] = [];\n const seenPaths = new Set<string>();\n const oversizedExistingFileIds = new Set<string>();\n let unchangedFiles = 0;\n let skippedOversizedFiles = 0;\n let unreadableFiles = 0;\n\n for (const abs of paths) {\n const rel = normalizeCodePath(relative(options.projectRoot, abs));\n // A discovered but temporarily unreadable path is not deletion evidence.\n seenPaths.add(rel);\n let stat: ReturnType<typeof statSync>;\n try {\n stat = statSync(abs);\n } catch {\n unreadableFiles++;\n continue;\n }\n const existing = existingByPath.get(rel);\n const mtimeMs = Number(stat.mtimeMs);\n const sizeBytes = Number(stat.size);\n if (sizeBytes > maxFileBytes) {\n skippedOversizedFiles++;\n if (existing) oversizedExistingFileIds.add(existing.id);\n continue;\n }\n if (existing && existing.mtimeMs === mtimeMs && existing.sizeBytes === sizeBytes) {\n unchangedFiles++;\n continue;\n }\n\n const attempt = indexFileLite(options.projectId, options.projectRoot, abs, indexedAt, stat);\n if (!attempt.delta) {\n if (attempt.unreadable) unreadableFiles++;\n continue;\n }\n const delta = attempt.delta;\n if (existing?.contentHash === delta.file.contentHash) {\n metadataOnly.push(delta.file);\n unchangedFiles++;\n } else {\n changed.push(delta);\n }\n }\n\n // At the file cap, absence from this partial walk is not proof of deletion.\n const removalScanDeferred = paths.length >= maxFiles;\n const removedFileIds = [...new Set([\n ...oversizedExistingFileIds,\n ...(removalScanDeferred\n ? []\n : [...existingByPath.values()]\n .filter((file) => !seenPaths.has(file.path))\n .map((file) => file.id)),\n ])];\n store.applyFileDeltas(options.projectId, {\n changed,\n metadataOnly,\n removedFileIds,\n });\n const completeness = {\n scannedFiles: paths.length,\n maxFiles,\n changedFiles: changed.length,\n unchangedFiles,\n metadataOnlyFiles: metadataOnly.length,\n removedFiles: removedFileIds.length,\n skippedOversizedFiles,\n unreadableFiles,\n removalScanDeferred,\n };\n const snapshot = store.recordCodeStateSnapshot(await collectCodeStateSnapshot({\n projectId: options.projectId,\n projectRoot: options.projectRoot,\n provider: 'lite',\n indexedAt,\n completeness,\n }));\n return {\n scannedFiles: paths.length,\n changedFiles: changed.length,\n unchangedFiles,\n metadataOnlyFiles: metadataOnly.length,\n removedFiles: removedFileIds.length,\n indexedSymbols: changed.reduce((total, delta) => total + delta.symbols.length, 0),\n indexedEdges: changed.reduce((total, delta) => total + delta.edges.length, 0),\n skippedOversizedFiles,\n unreadableFiles,\n removalScanDeferred,\n snapshot,\n };\n}\n","import { createHash, randomUUID } from 'node:crypto';\nimport { sanitizeCredentials } from '../memory/secret-filter.js';\nimport { getDatabase } from '../store/sqlite-db.js';\nimport type {\n ClaimConflict,\n ClaimEvent,\n ClaimEvidenceRef,\n KnowledgeClaim,\n KnowledgeClaimStatus,\n} from './types.js';\n\nfunction optionalText(value: unknown): string | undefined {\n return typeof value === 'string' && value ? value : undefined;\n}\n\nfunction rowToClaim(row: any): KnowledgeClaim {\n return {\n id: row.id,\n projectId: row.projectId,\n subject: row.subject,\n predicate: row.predicate,\n objectValue: row.objectValue,\n scope: row.scope,\n claimKey: row.claimKey,\n conflictKey: row.conflictKey,\n status: row.status,\n confidence: Number(row.confidence),\n observedAt: row.observedAt,\n ...(optionalText(row.validFrom) ? { validFrom: row.validFrom } : {}),\n ...(optionalText(row.validTo) ? { validTo: row.validTo } : {}),\n ...(optionalText(row.supersededBy) ? { supersededBy: row.supersededBy } : {}),\n reviewState: row.reviewState,\n origin: row.origin,\n createdAt: row.createdAt,\n updatedAt: row.updatedAt,\n };\n}\n\nfunction rowToEvidence(row: any): ClaimEvidenceRef {\n return {\n id: row.id,\n claimId: row.claimId,\n evidenceKind: row.evidenceKind,\n evidenceId: row.evidenceId,\n relation: row.relation,\n ...(optionalText(row.snapshotId) ? { snapshotId: row.snapshotId } : {}),\n ...(optionalText(row.locator) ? { locator: row.locator } : {}),\n ...(optionalText(row.capturedHash) ? { capturedHash: row.capturedHash } : {}),\n createdAt: row.createdAt,\n };\n}\n\nfunction rowToEvent(row: any): ClaimEvent {\n return {\n id: row.id,\n projectId: row.projectId,\n claimId: row.claimId,\n kind: row.kind,\n ...(optionalText(row.fromStatus) ? { fromStatus: row.fromStatus } : {}),\n ...(optionalText(row.toStatus) ? { toStatus: row.toStatus } : {}),\n ...(optionalText(row.relatedClaimId) ? { relatedClaimId: row.relatedClaimId } : {}),\n ...(optionalText(row.detail) ? { detail: row.detail } : {}),\n createdAt: row.createdAt,\n };\n}\n\nfunction evidenceKey(input: Omit<ClaimEvidenceRef, 'id' | 'claimId' | 'createdAt'>): string {\n return createHash('sha256').update(JSON.stringify([\n input.evidenceKind,\n input.evidenceId,\n input.relation,\n input.snapshotId ?? '',\n input.locator ?? '',\n input.capturedHash ?? '',\n ])).digest('hex');\n}\n\n/**\n * SQLite access for the claim ledger. Domain policy belongs in claims.ts; this\n * class only preserves records and their audit trail atomically.\n */\nexport class ClaimStore {\n private db: any = null;\n\n async init(dataDir: string): Promise<void> {\n this.db = getDatabase(dataDir);\n }\n\n transaction<T>(fn: () => T): T {\n return this.db.transaction(fn)();\n }\n\n getClaim(id: string): KnowledgeClaim | undefined {\n const row = this.db.prepare('SELECT * FROM knowledge_claims WHERE id = ?').get(id);\n return row ? rowToClaim(row) : undefined;\n }\n\n listClaims(\n projectId: string,\n options: { statuses?: readonly KnowledgeClaimStatus[]; limit?: number } = {},\n ): KnowledgeClaim[] {\n const limit = Math.max(1, Math.min(1_000, Math.floor(options.limit ?? 500)));\n if (options.statuses && options.statuses.length > 0) {\n return this.db.prepare(`\n SELECT * FROM knowledge_claims\n WHERE projectId = ? AND status IN (SELECT value FROM json_each(?))\n ORDER BY updatedAt DESC, id\n LIMIT ?\n `).all(projectId, JSON.stringify([...new Set(options.statuses)]), limit).map(rowToClaim);\n }\n return this.db.prepare(`\n SELECT * FROM knowledge_claims\n WHERE projectId = ?\n ORDER BY updatedAt DESC, id\n LIMIT ?\n `).all(projectId, limit).map(rowToClaim);\n }\n\n findReusableClaim(projectId: string, claimKey: string): KnowledgeClaim | undefined {\n const row = this.db.prepare(`\n SELECT * FROM knowledge_claims\n WHERE projectId = ? AND claimKey = ? AND status IN ('active', 'disputed')\n ORDER BY updatedAt DESC\n LIMIT 1\n `).get(projectId, claimKey);\n return row ? rowToClaim(row) : undefined;\n }\n\n listClaimsByConflictKey(projectId: string, conflictKey: string): KnowledgeClaim[] {\n return this.db.prepare(`\n SELECT * FROM knowledge_claims\n WHERE projectId = ? AND conflictKey = ?\n ORDER BY createdAt ASC, id\n `).all(projectId, conflictKey).map(rowToClaim);\n }\n\n listConflicts(projectId: string): ClaimConflict[] {\n const rows = this.db.prepare(`\n SELECT conflictKey\n FROM knowledge_claims\n WHERE projectId = ? AND status IN ('active', 'disputed') AND reviewState = 'approved'\n GROUP BY conflictKey\n HAVING COUNT(DISTINCT claimKey) > 1\n ORDER BY conflictKey\n `).all(projectId) as Array<{ conflictKey: string }>;\n return rows.map(({ conflictKey }) => ({\n conflictKey,\n claims: this.listClaimsByConflictKey(projectId, conflictKey)\n .filter(claim => claim.status === 'active' || claim.status === 'disputed'),\n }));\n }\n\n insertClaim(claim: KnowledgeClaim): void {\n this.db.prepare(`\n INSERT INTO knowledge_claims (\n id, projectId, subject, predicate, objectValue, scope, claimKey, conflictKey,\n status, confidence, observedAt, validFrom, validTo, supersededBy,\n reviewState, origin, createdAt, updatedAt\n ) VALUES (\n @id, @projectId, @subject, @predicate, @objectValue, @scope, @claimKey, @conflictKey,\n @status, @confidence, @observedAt, @validFrom, @validTo, @supersededBy,\n @reviewState, @origin, @createdAt, @updatedAt\n )\n `).run({\n ...claim,\n validFrom: claim.validFrom ?? null,\n validTo: claim.validTo ?? null,\n supersededBy: claim.supersededBy ?? null,\n });\n }\n\n updateClaim(claim: KnowledgeClaim): void {\n this.db.prepare(`\n UPDATE knowledge_claims SET\n subject = @subject,\n predicate = @predicate,\n objectValue = @objectValue,\n scope = @scope,\n claimKey = @claimKey,\n conflictKey = @conflictKey,\n status = @status,\n confidence = @confidence,\n observedAt = @observedAt,\n validFrom = @validFrom,\n validTo = @validTo,\n supersededBy = @supersededBy,\n reviewState = @reviewState,\n origin = @origin,\n updatedAt = @updatedAt\n WHERE id = @id\n `).run({\n ...claim,\n validFrom: claim.validFrom ?? null,\n validTo: claim.validTo ?? null,\n supersededBy: claim.supersededBy ?? null,\n });\n }\n\n touchClaim(id: string, updatedAt: string): void {\n this.db.prepare('UPDATE knowledge_claims SET updatedAt = ? WHERE id = ?').run(updatedAt, id);\n }\n\n insertEvidence(input: Omit<ClaimEvidenceRef, 'id' | 'createdAt'> & { createdAt?: string }): boolean {\n const createdAt = input.createdAt ?? new Date().toISOString();\n const key = evidenceKey(input);\n const result = this.db.prepare(`\n INSERT OR IGNORE INTO knowledge_claim_evidence (\n id, claimId, evidenceKind, evidenceId, relation, snapshotId,\n locator, capturedHash, evidenceKey, createdAt\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n `).run(\n randomUUID(),\n input.claimId,\n input.evidenceKind,\n input.evidenceId,\n input.relation,\n input.snapshotId ?? null,\n input.locator ? sanitizeCredentials(input.locator) : null,\n input.capturedHash ?? null,\n key,\n createdAt,\n );\n return Number(result.changes ?? 0) > 0;\n }\n\n listEvidence(claimId: string): ClaimEvidenceRef[] {\n return this.db.prepare(`\n SELECT * FROM knowledge_claim_evidence\n WHERE claimId = ?\n ORDER BY createdAt ASC, id\n `).all(claimId).map(rowToEvidence);\n }\n\n recordEvent(input: Omit<ClaimEvent, 'id' | 'createdAt'> & { createdAt?: string }): ClaimEvent {\n const event: ClaimEvent = {\n id: randomUUID(),\n ...input,\n ...(input.detail ? { detail: sanitizeCredentials(input.detail) } : {}),\n createdAt: input.createdAt ?? new Date().toISOString(),\n };\n this.db.prepare(`\n INSERT INTO knowledge_claim_events (\n id, projectId, claimId, kind, fromStatus, toStatus,\n relatedClaimId, detail, createdAt\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)\n `).run(\n event.id,\n event.projectId,\n event.claimId,\n event.kind,\n event.fromStatus ?? null,\n event.toStatus ?? null,\n event.relatedClaimId ?? null,\n event.detail ?? null,\n event.createdAt,\n );\n return event;\n }\n\n listEvents(claimId: string): ClaimEvent[] {\n return this.db.prepare(`\n SELECT * FROM knowledge_claim_events\n WHERE claimId = ?\n ORDER BY createdAt ASC, id\n `).all(claimId).map(rowToEvent);\n }\n}\n","import { createHash, randomUUID } from 'node:crypto';\nimport { countTextTokens } from '../compact/token-budget.js';\nimport type { CodeGraphStore } from '../codegraph/store.js';\nimport type { CodeStateSnapshot, ObservationCodeRef } from '../codegraph/types.js';\nimport { sanitizeCredentials } from '../memory/secret-filter.js';\nimport type { Observation, ObservationType } from '../types.js';\nimport { ClaimStore } from './claim-store.js';\nimport type {\n ClaimConflict,\n ClaimEvidenceInput,\n ClaimEvidenceRef,\n ClaimSelection,\n ClaimWriteResult,\n KnowledgeClaim,\n KnowledgeClaimInput,\n KnowledgeClaimReviewState,\n KnowledgeClaimStatus,\n} from './types.js';\n\nconst MAX_TERM_LENGTH = 2_000;\nconst MAX_EVIDENCE_ID_LENGTH = 1_000;\nconst TOKEN_PATTERN = /[\\p{L}\\p{N}_./:-]+/gu;\n\nconst PREDICATE_BY_OBSERVATION_TYPE: Partial<Record<ObservationType, string>> = {\n decision: 'decision',\n 'trade-off': 'trade-off',\n 'why-it-exists': 'rationale',\n 'what-changed': 'changed',\n 'problem-solution': 'workaround',\n gotcha: 'caution',\n 'how-it-works': 'behavior',\n discovery: 'finding',\n reasoning: 'rationale',\n};\n\nfunction compactText(value: string, field: string): string {\n if (typeof value !== 'string') throw new Error('Claim ' + field + ' must be text');\n const sanitized = sanitizeCredentials(value).trim().replace(/\\s+/g, ' ');\n if (!sanitized) throw new Error('Claim ' + field + ' is required');\n if (sanitized.length > MAX_TERM_LENGTH) throw new Error('Claim ' + field + ' is too long');\n return sanitized;\n}\n\nfunction normalizedTerm(value: string): string {\n return compactText(value, 'identity').toLocaleLowerCase('en-US');\n}\n\nfunction hashIdentity(parts: string[]): string {\n return createHash('sha256').update(parts.join(String.fromCharCode(31))).digest('hex');\n}\n\nexport function buildClaimIdentity(input: Pick<KnowledgeClaimInput, 'subject' | 'predicate' | 'objectValue' | 'scope'>): {\n claimKey: string;\n conflictKey: string;\n} {\n const subject = normalizedTerm(input.subject);\n const predicate = normalizedTerm(input.predicate);\n const objectValue = normalizedTerm(input.objectValue);\n return {\n claimKey: hashIdentity([subject, predicate, objectValue, input.scope]),\n conflictKey: hashIdentity([subject, predicate, input.scope]),\n };\n}\n\nfunction clampConfidence(value: number | undefined): number {\n if (value === undefined) return 0.7;\n if (!Number.isFinite(value) || value < 0 || value > 1) {\n throw new Error('Claim confidence must be a number between 0 and 1');\n }\n return value;\n}\n\nfunction validateEvidence(input: ClaimEvidenceInput[]): ClaimEvidenceInput[] {\n if (!Array.isArray(input) || input.length === 0) {\n throw new Error('A knowledge claim requires at least one evidence reference');\n }\n return input.map((evidence) => {\n if (!evidence || typeof evidence !== 'object') {\n throw new Error('Claim evidence must be an object');\n }\n const evidenceId = compactText(evidence.evidenceId, 'evidence id');\n if (evidenceId.length > MAX_EVIDENCE_ID_LENGTH) {\n throw new Error('Claim evidence id is too long');\n }\n if (!['observation', 'git', 'code', 'test', 'document', 'workflow', 'run'].includes(evidence.evidenceKind)) {\n throw new Error('Claim evidence kind is invalid');\n }\n if (!['supports', 'contradicts', 'derives', 'verifies'].includes(evidence.relation)) {\n throw new Error('Claim evidence relation is invalid');\n }\n return {\n evidenceKind: evidence.evidenceKind,\n evidenceId,\n relation: evidence.relation,\n ...(evidence.snapshotId ? { snapshotId: compactText(evidence.snapshotId, 'evidence snapshot id') } : {}),\n ...(evidence.locator ? { locator: compactText(evidence.locator, 'evidence locator') } : {}),\n ...(evidence.capturedHash ? { capturedHash: compactText(evidence.capturedHash, 'evidence hash') } : {}),\n };\n });\n}\n\nfunction normalizeClaimInput(input: KnowledgeClaimInput): {\n claim: KnowledgeClaim;\n evidence: ClaimEvidenceInput[];\n} {\n if (!['project', 'workspace', 'team', 'workflow', 'task'].includes(input.scope)) {\n throw new Error('Claim scope is invalid');\n }\n const projectId = compactText(input.projectId, 'project id');\n const subject = compactText(input.subject, 'subject');\n const predicate = compactText(input.predicate, 'predicate');\n const objectValue = compactText(input.objectValue, 'object value');\n const identity = buildClaimIdentity({ subject, predicate, objectValue, scope: input.scope });\n const origin = input.origin ?? 'explicit';\n let reviewState: KnowledgeClaimReviewState = input.reviewState ?? 'approved';\n let status: KnowledgeClaimStatus = input.status ?? 'active';\n if (origin === 'model') {\n if (input.reviewState === 'approved' || input.status === 'active') {\n throw new Error('A model-origin claim cannot be approved or active without explicit review');\n }\n reviewState = input.reviewState ?? 'draft';\n status = input.status ?? 'unknown';\n }\n if (!['approved', 'needs-review', 'draft', 'rejected'].includes(reviewState)) {\n throw new Error('Claim review state is invalid');\n }\n if (!['active', 'superseded', 'disputed', 'unknown'].includes(status)) {\n throw new Error('Claim status is invalid');\n }\n const now = new Date().toISOString();\n return {\n claim: {\n id: randomUUID(),\n projectId,\n subject,\n predicate,\n objectValue,\n scope: input.scope,\n claimKey: identity.claimKey,\n conflictKey: identity.conflictKey,\n status,\n confidence: clampConfidence(input.confidence),\n observedAt: input.observedAt ?? now,\n ...(input.validFrom ? { validFrom: input.validFrom } : {}),\n ...(input.validTo ? { validTo: input.validTo } : {}),\n reviewState,\n origin,\n createdAt: now,\n updatedAt: now,\n },\n evidence: validateEvidence(input.evidence),\n };\n}\n\nfunction activeConflictClaims(store: ClaimStore, projectId: string, conflictKey: string): KnowledgeClaim[] {\n return store.listClaimsByConflictKey(projectId, conflictKey).filter(claim =>\n (claim.status === 'active' || claim.status === 'disputed') && claim.reviewState === 'approved');\n}\n\nfunction reconcileConflicts(\n store: ClaimStore,\n projectId: string,\n conflictKey: string,\n now: string,\n): ClaimConflict[] {\n const claims = activeConflictClaims(store, projectId, conflictKey);\n const hasConflict = new Set(claims.map(claim => claim.claimKey)).size > 1;\n for (const claim of claims) {\n const nextStatus: KnowledgeClaimStatus = hasConflict ? 'disputed' : 'active';\n if (claim.status === nextStatus) continue;\n store.updateClaim({ ...claim, status: nextStatus, updatedAt: now });\n store.recordEvent({\n projectId,\n claimId: claim.id,\n kind: hasConflict ? 'conflicted' : 'requalified',\n fromStatus: claim.status,\n toStatus: nextStatus,\n detail: hasConflict\n ? 'A different approved assertion has the same subject, predicate, and scope.'\n : 'No remaining approved competing assertion exists.',\n createdAt: now,\n });\n }\n return store.listConflicts(projectId).filter(conflict => conflict.conflictKey === conflictKey);\n}\n\nfunction persistEvidence(store: ClaimStore, claim: KnowledgeClaim, evidence: ClaimEvidenceInput[], now: string): void {\n let added = false;\n for (const item of evidence) {\n added = store.insertEvidence({ claimId: claim.id, ...item, createdAt: now }) || added;\n }\n if (added) {\n store.touchClaim(claim.id, now);\n store.recordEvent({\n projectId: claim.projectId,\n claimId: claim.id,\n kind: 'evidence-added',\n detail: 'Additional source evidence was attached.',\n createdAt: now,\n });\n }\n}\n\n/** Write one claim without allowing a summary to replace its source evidence. */\nexport function writeClaim(store: ClaimStore, input: KnowledgeClaimInput): ClaimWriteResult {\n const normalized = normalizeClaimInput(input);\n return store.transaction(() => {\n const existing = store.findReusableClaim(normalized.claim.projectId, normalized.claim.claimKey);\n if (existing) {\n persistEvidence(store, existing, normalized.evidence, normalized.claim.updatedAt);\n return {\n claim: store.getClaim(existing.id) ?? existing,\n created: false,\n conflicts: store.listConflicts(existing.projectId)\n .filter(conflict => conflict.conflictKey === existing.conflictKey),\n };\n }\n\n store.insertClaim(normalized.claim);\n for (const evidence of normalized.evidence) {\n store.insertEvidence({ claimId: normalized.claim.id, ...evidence, createdAt: normalized.claim.createdAt });\n }\n store.recordEvent({\n projectId: normalized.claim.projectId,\n claimId: normalized.claim.id,\n kind: 'created',\n toStatus: normalized.claim.status,\n detail: 'Claim created with source evidence.',\n createdAt: normalized.claim.createdAt,\n });\n const conflicts = reconcileConflicts(\n store,\n normalized.claim.projectId,\n normalized.claim.conflictKey,\n normalized.claim.updatedAt,\n );\n return {\n claim: store.getClaim(normalized.claim.id) ?? normalized.claim,\n created: true,\n conflicts,\n };\n });\n}\n\n/**\n * Deliberately approve or reject a source-backed claim after its evidence has\n * been checked. Derived agent observations never cross this boundary by\n * themselves.\n */\nexport function reviewClaim(\n store: ClaimStore,\n input: {\n claimId: string;\n reviewState: Extract<KnowledgeClaimReviewState, 'approved' | 'rejected'>;\n detail: string;\n },\n): KnowledgeClaim {\n if (input.reviewState !== 'approved' && input.reviewState !== 'rejected') {\n throw new Error('A claim review must approve or reject the claim');\n }\n const detail = compactText(input.detail, 'review detail');\n return store.transaction(() => {\n const claim = store.getClaim(input.claimId);\n if (!claim) throw new Error('Claim was not found');\n if (input.reviewState === 'approved' && claim.status === 'superseded') {\n throw new Error('A superseded claim cannot be approved');\n }\n const now = new Date().toISOString();\n const nextStatus: KnowledgeClaimStatus = input.reviewState === 'rejected'\n ? 'unknown'\n : claim.status === 'unknown' && claim.reviewState === 'rejected'\n ? 'active'\n : claim.status;\n const updated: KnowledgeClaim = {\n ...claim,\n status: nextStatus,\n reviewState: input.reviewState,\n updatedAt: now,\n };\n store.updateClaim(updated);\n store.recordEvent({\n projectId: claim.projectId,\n claimId: claim.id,\n kind: 'reviewed',\n fromStatus: claim.status,\n toStatus: updated.status,\n detail: 'Review: ' + claim.reviewState + ' -> ' + input.reviewState + '. ' + detail,\n createdAt: now,\n });\n reconcileConflicts(store, claim.projectId, claim.conflictKey, now);\n return store.getClaim(claim.id) ?? updated;\n });\n}\n\nexport function supersedeClaim(\n store: ClaimStore,\n input: {\n claimId: string;\n replacementClaimId: string;\n evidence: ClaimEvidenceInput[];\n },\n): { superseded: KnowledgeClaim; replacement: KnowledgeClaim } {\n const evidence = validateEvidence(input.evidence);\n return store.transaction(() => {\n const claim = store.getClaim(input.claimId);\n const replacement = store.getClaim(input.replacementClaimId);\n if (!claim || !replacement) throw new Error('Both claims must exist before supersession');\n if (claim.projectId !== replacement.projectId || claim.conflictKey !== replacement.conflictKey) {\n throw new Error('A replacement claim must address the same project assertion');\n }\n if (claim.id === replacement.id) throw new Error('A claim cannot supersede itself');\n const now = new Date().toISOString();\n persistEvidence(store, claim, evidence, now);\n const updated: KnowledgeClaim = {\n ...claim,\n status: 'superseded',\n validTo: now,\n supersededBy: replacement.id,\n updatedAt: now,\n };\n store.updateClaim(updated);\n store.recordEvent({\n projectId: claim.projectId,\n claimId: claim.id,\n kind: 'superseded',\n fromStatus: claim.status,\n toStatus: 'superseded',\n relatedClaimId: replacement.id,\n detail: 'Superseded by an evidence-backed replacement claim.',\n createdAt: now,\n });\n reconcileConflicts(store, claim.projectId, claim.conflictKey, now);\n return {\n superseded: store.getClaim(claim.id) ?? updated,\n replacement: store.getClaim(replacement.id) ?? replacement,\n };\n });\n}\n\nfunction hashObservation(observation: Observation): string {\n return createHash('sha256').update(JSON.stringify([\n observation.title,\n observation.narrative,\n observation.facts,\n observation.filesModified,\n observation.updatedAt ?? observation.createdAt,\n ])).digest('hex');\n}\n\nfunction evidenceFromCodeRef(ref: ObservationCodeRef): ClaimEvidenceInput {\n return {\n evidenceKind: 'code',\n evidenceId: 'code-ref:' + ref.id,\n relation: 'supports',\n ...(ref.snapshotId ? { snapshotId: ref.snapshotId } : {}),\n locator: 'code-ref/' + ref.id,\n ...(ref.capturedSymbolHash || ref.capturedFileHash\n ? { capturedHash: ref.capturedSymbolHash ?? ref.capturedFileHash }\n : {}),\n };\n}\n\n/**\n * Converts only explicit or Git-ingested observations into conservative,\n * reviewable source claims. Hook/model-derived memories remain ordinary memory\n * until an agent or operator explicitly promotes them.\n */\nexport function deriveLowRiskClaimsFromObservation(\n store: ClaimStore,\n observation: Observation,\n codeStore?: CodeGraphStore,\n): KnowledgeClaim[] {\n const predicate = PREDICATE_BY_OBSERVATION_TYPE[observation.type];\n const isExplicit = observation.sourceDetail === 'explicit';\n const isGit = observation.source === 'git' || observation.sourceDetail === 'git-ingest';\n if (!predicate || observation.status !== 'active' || (!isExplicit && !isGit)) return [];\n\n const evidence: ClaimEvidenceInput[] = [{\n evidenceKind: 'observation',\n evidenceId: 'observation:' + observation.id,\n relation: 'supports',\n locator: 'observation/' + observation.id,\n capturedHash: hashObservation(observation),\n }];\n if (observation.commitHash) {\n evidence.push({\n evidenceKind: 'git',\n evidenceId: 'git:' + observation.commitHash,\n relation: 'verifies',\n locator: 'git:' + observation.commitHash,\n capturedHash: observation.commitHash,\n });\n }\n const refs = codeStore?.listObservationRefs(observation.projectId, observation.id) ?? [];\n for (const ref of refs) evidence.push(evidenceFromCodeRef(ref));\n\n const confidence = Math.min(0.9, (isGit ? 0.75 : 0.7) + refs.filter(ref => ref.status === 'current').length * 0.05);\n const result = writeClaim(store, {\n projectId: observation.projectId,\n subject: observation.entityName,\n predicate,\n objectValue: observation.title,\n scope: 'project',\n confidence,\n observedAt: observation.updatedAt ?? observation.createdAt,\n reviewState: isGit ? 'approved' : 'needs-review',\n origin: isGit ? 'git' : 'derived',\n evidence,\n });\n return [result.claim];\n}\n\nfunction incompleteSnapshot(snapshot: CodeStateSnapshot | undefined): boolean {\n if (!snapshot) return false;\n return snapshot.completeness.skippedOversizedFiles > 0\n || (snapshot.completeness.unreadableFiles ?? 0) > 0\n || snapshot.completeness.removalScanDeferred;\n}\n\nfunction requalification(\n claim: KnowledgeClaim,\n refs: Map<string, ObservationCodeRef>,\n evidence: ClaimEvidenceRef[],\n snapshot: CodeStateSnapshot | undefined,\n): { status: KnowledgeClaimStatus; confidence: number; reviewState: KnowledgeClaimReviewState; reason?: string } | undefined {\n if (claim.status === 'superseded' || claim.reviewState === 'draft' || claim.reviewState === 'rejected') return undefined;\n const codeEvidence = evidence.filter(item => item.evidenceKind === 'code');\n if (codeEvidence.length === 0) return undefined;\n const linkedRefs = codeEvidence\n .map(item => refs.get(item.evidenceId.replace(/^code-ref:/, '')))\n .filter((ref): ref is ObservationCodeRef => !!ref);\n const missingOrStale = linkedRefs.length !== codeEvidence.length || linkedRefs.some(ref => ref.status === 'stale');\n if (missingOrStale) {\n return {\n status: 'unknown',\n confidence: Math.min(claim.confidence, 0.2),\n reviewState: 'needs-review',\n reason: 'Bound code evidence is no longer current.',\n };\n }\n if (linkedRefs.some(ref => ref.status === 'suspect')) {\n return {\n status: claim.status === 'disputed' ? 'disputed' : 'active',\n confidence: Math.min(claim.confidence, 0.5),\n reviewState: 'needs-review',\n reason: 'Bound file evidence changed and needs review.',\n };\n }\n if (incompleteSnapshot(snapshot)) {\n return {\n status: claim.status === 'disputed' ? 'disputed' : 'active',\n confidence: Math.min(claim.confidence, 0.55),\n reviewState: 'needs-review',\n reason: 'The latest code scan is incomplete.',\n };\n }\n return undefined;\n}\n\n/** Re-score code-bound claims after a completed CodeGraph refresh. */\nexport function requalifyClaimsForCodeState(\n store: ClaimStore,\n codeStore: CodeGraphStore,\n projectId: string,\n): { requalified: number; incompleteSnapshot: boolean } {\n const snapshot = codeStore.latestSnapshot(projectId);\n const refs = new Map(codeStore.listProjectObservationRefs(projectId).map(ref => [ref.id, ref]));\n let requalified = 0;\n store.transaction(() => {\n for (const claim of store.listClaims(projectId)) {\n const next = requalification(claim, refs, store.listEvidence(claim.id), snapshot);\n if (!next) continue;\n if (\n next.status === claim.status\n && next.confidence === claim.confidence\n && next.reviewState === claim.reviewState\n ) {\n continue;\n }\n const updated = {\n ...claim,\n status: next.status,\n confidence: next.confidence,\n reviewState: next.reviewState,\n updatedAt: new Date().toISOString(),\n };\n store.updateClaim(updated);\n store.recordEvent({\n projectId,\n claimId: claim.id,\n kind: 'requalified',\n fromStatus: claim.status,\n toStatus: next.status,\n detail: next.reason,\n createdAt: updated.updatedAt,\n });\n requalified += 1;\n }\n });\n return { requalified, incompleteSnapshot: incompleteSnapshot(snapshot) };\n}\n\nfunction normalizedTokens(value: string): Set<string> {\n const raw = sanitizeCredentials(value)\n .toLocaleLowerCase('en-US')\n .match(TOKEN_PATTERN)\n ?? [];\n return new Set(raw\n .map(token => token.replace(/^[,;:!?]+|[,;:!?.]+$/g, ''))\n .filter(token => token.length > 1));\n}\n\nfunction taskTokens(task: string): Set<string> {\n return normalizedTokens(task);\n}\n\nfunction scoreClaim(claim: KnowledgeClaim, tokens: Set<string>): number {\n const text = [claim.subject, claim.predicate, claim.objectValue]\n .join(' ')\n .toLocaleLowerCase('en-US');\n const words = normalizedTokens(text);\n let matches = 0;\n for (const token of tokens) {\n if (words.has(token)) matches += 1;\n }\n if (matches === 0) return 0;\n const statusWeight = claim.status === 'active' ? 0.25 : claim.status === 'disputed' ? 0.2 : 0.1;\n return matches * 10 + claim.confidence + statusWeight;\n}\n\nfunction formatClaim(claim: KnowledgeClaim): string {\n return sanitizeCredentials([claim.subject, claim.predicate, claim.objectValue].join(' '));\n}\n\n/**\n * A deterministic compact selector used by the later Workset builder. It\n * returns no generic claim dump when no task terms match.\n */\nexport function selectClaimsForTask(\n store: ClaimStore,\n input: { projectId: string; task: string; limit?: number; maxTokens?: number },\n): ClaimSelection {\n const limit = Math.max(1, Math.min(12, Math.floor(input.limit ?? 4)));\n const maxTokens = Math.max(16, Math.min(1_000, Math.floor(input.maxTokens ?? 160)));\n const tokens = taskTokens(input.task);\n if (tokens.size === 0) return { claims: [], cautions: [], tokenCount: 0, reasons: {} };\n\n const candidates = store.listClaims(input.projectId, {\n statuses: ['active', 'disputed', 'unknown'],\n limit: 1_000,\n }).filter(claim => claim.reviewState !== 'draft' && claim.reviewState !== 'rejected');\n const scored = candidates\n .map(claim => ({ claim, score: scoreClaim(claim, tokens) }))\n .filter(item => item.score > 0)\n .sort((left, right) => right.score - left.score || left.claim.id.localeCompare(right.claim.id));\n if (scored.length === 0) return { claims: [], cautions: [], tokenCount: 0, reasons: {} };\n\n const selected = new Map<string, KnowledgeClaim>();\n for (const { claim } of scored.slice(0, limit)) selected.set(claim.id, claim);\n for (const claim of [...selected.values()]) {\n for (const sibling of store.listClaimsByConflictKey(input.projectId, claim.conflictKey)) {\n if (sibling.status === 'active' || sibling.status === 'disputed') selected.set(sibling.id, sibling);\n }\n }\n\n const ordered = [...selected.values()]\n .sort((left, right) => scoreClaim(right, tokens) - scoreClaim(left, tokens) || left.id.localeCompare(right.id));\n const included: KnowledgeClaim[] = [];\n let tokenCount = 0;\n for (const claim of ordered) {\n const nextTokens = countTextTokens(formatClaim(claim));\n if (included.length > 0 && tokenCount + nextTokens > maxTokens) continue;\n included.push(claim);\n tokenCount += nextTokens;\n }\n\n const cautions = new Set<string>();\n const reasons: Record<string, string> = {};\n for (const claim of included) {\n reasons[claim.id] = 'task terms matched source-qualified claim';\n if (claim.status === 'disputed') cautions.add('claim-conflict');\n if (claim.status === 'unknown' || claim.reviewState === 'needs-review') {\n cautions.add('claim-needs-review');\n }\n }\n return { claims: included, cautions: [...cautions].sort(), tokenCount, reasons };\n}\n","import { createHash } from 'node:crypto';\nimport { promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport matter from 'gray-matter';\nimport { atomicWriteFile } from '../store/file-lock.js';\nimport type { KnowledgePage, KnowledgePageFrontmatter, KnowledgePageKind, KnowledgePageReviewState, KnowledgePageStatus } from './workspace-types.js';\n\nconst PAGE_KINDS: KnowledgePageKind[] = ['topic', 'decision', 'risk', 'index', 'schema', 'log'];\nconst PAGE_STATUSES: KnowledgePageStatus[] = ['active', 'proposed'];\nconst REVIEW_STATES: KnowledgePageReviewState[] = ['approved', 'needs-review'];\nconst LINK_PATTERN = /\\[[^\\]]+\\]\\(([^)]+)\\)/g;\n\nfunction hashContent(content: string): string {\n return createHash('sha256').update(content).digest('hex');\n}\n\nfunction stringField(data: Record<string, unknown>, key: string): string {\n const value = data[key];\n if (typeof value !== 'string' || !value.trim()) {\n throw new Error('missing required field ' + key);\n }\n return value.trim();\n}\n\nfunction stringArray(data: Record<string, unknown>, key: string): string[] {\n const value = data[key];\n if (!Array.isArray(value) || value.some(item => typeof item !== 'string')) {\n throw new Error('field ' + key + ' must be a string array');\n }\n return value.map(item => item.trim()).filter(Boolean);\n}\n\nfunction optionalString(data: Record<string, unknown>, key: string): string | undefined {\n const value = data[key];\n if (value === undefined || value === null || value === '') return undefined;\n if (typeof value !== 'string') throw new Error('field ' + key + ' must be text');\n return value.trim() || undefined;\n}\n\nexport function validateKnowledgePageFrontmatter(data: Record<string, unknown>): KnowledgePageFrontmatter {\n const kind = stringField(data, 'kind') as KnowledgePageKind;\n const status = stringField(data, 'status') as KnowledgePageStatus;\n const reviewState = stringField(data, 'reviewState') as KnowledgePageReviewState;\n if (!PAGE_KINDS.includes(kind)) throw new Error('field kind is invalid');\n if (!PAGE_STATUSES.includes(status)) throw new Error('field status is invalid');\n if (!REVIEW_STATES.includes(reviewState)) throw new Error('field reviewState is invalid');\n return {\n id: stringField(data, 'id'),\n title: stringField(data, 'title'),\n kind,\n status,\n reviewState,\n claimIds: stringArray(data, 'claimIds'),\n evidenceRefs: stringArray(data, 'evidenceRefs'),\n ...(optionalString(data, 'snapshotId') ? { snapshotId: optionalString(data, 'snapshotId') } : {}),\n tags: stringArray(data, 'tags'),\n sourceHash: stringField(data, 'sourceHash'),\n generatedAt: stringField(data, 'generatedAt'),\n updatedAt: stringField(data, 'updatedAt'),\n };\n}\n\nexport function extractInternalMarkdownLinks(body: string): string[] {\n const links = new Set<string>();\n for (const match of body.matchAll(LINK_PATTERN)) {\n const raw = match[1].trim();\n if (!raw || raw.startsWith('#') || /^[a-z][a-z0-9+.-]*:/i.test(raw)) continue;\n const pathPart = raw.split('#', 1)[0].replace(/\\\\/g, '/');\n if (!pathPart.endsWith('.md')) continue;\n links.add(pathPart);\n }\n return [...links].sort();\n}\n\nexport function resolvePageLink(sourceRelativePath: string, target: string): string | undefined {\n const sourceDir = path.posix.dirname(sourceRelativePath.replace(/\\\\/g, '/'));\n const normalized = path.posix.normalize(path.posix.join(sourceDir, target.replace(/\\\\/g, '/')));\n if (!normalized || normalized === '.' || normalized === '..' || normalized.startsWith('../')) return undefined;\n return normalized;\n}\n\nexport function renderKnowledgePage(frontmatter: KnowledgePageFrontmatter, body: string): string {\n const normalizedBody = body.trimEnd() + '\\n';\n return matter.stringify(normalizedBody, {\n id: frontmatter.id,\n title: frontmatter.title,\n kind: frontmatter.kind,\n status: frontmatter.status,\n reviewState: frontmatter.reviewState,\n claimIds: frontmatter.claimIds,\n evidenceRefs: frontmatter.evidenceRefs,\n ...(frontmatter.snapshotId ? { snapshotId: frontmatter.snapshotId } : {}),\n tags: frontmatter.tags,\n sourceHash: frontmatter.sourceHash,\n generatedAt: frontmatter.generatedAt,\n updatedAt: frontmatter.updatedAt,\n });\n}\n\nexport async function readKnowledgePage(absolutePath: string, workspaceRoot?: string): Promise<KnowledgePage> {\n const raw = await fs.readFile(absolutePath, 'utf8');\n try {\n const parsed = matter(raw);\n const frontmatter = validateKnowledgePageFrontmatter(parsed.data as Record<string, unknown>);\n return {\n absolutePath,\n relativePath: workspaceRoot\n ? path.relative(workspaceRoot, absolutePath).split(path.sep).join('/')\n : path.basename(absolutePath),\n frontmatter,\n body: parsed.content.trim(),\n contentHash: hashContent(raw),\n links: extractInternalMarkdownLinks(parsed.content),\n };\n } catch (error) {\n const detail = error instanceof Error ? error.message : 'invalid page data';\n throw new Error('Malformed knowledge page frontmatter in ' + absolutePath + ': ' + detail);\n }\n}\n\nexport async function writeKnowledgePage(absolutePath: string, content: string): Promise<string> {\n await fs.mkdir(path.dirname(absolutePath), { recursive: true });\n await atomicWriteFile(absolutePath, content);\n return hashContent(content);\n}\n\nexport function pageContentHash(content: string): string {\n return hashContent(content);\n}\n","import { createHash } from 'node:crypto';\nimport { promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport type { CodeGraphStore } from '../codegraph/store.js';\nimport { withFileLock } from '../store/file-lock.js';\nimport { ClaimStore } from './claim-store.js';\nimport { extractInternalMarkdownLinks, pageContentHash, readKnowledgePage, renderKnowledgePage, resolvePageLink, writeKnowledgePage } from './markdown.js';\nimport { KnowledgeWorkspaceStore } from './workspace-store.js';\nimport { getKnowledgeWorkspacePaths, resolveKnowledgeWorkspaceFile } from './workspace.js';\nimport type {\n KnowledgePage,\n KnowledgePageFrontmatter,\n KnowledgePageRecord,\n KnowledgeProposal,\n KnowledgeProposalReason,\n KnowledgeWorkspace,\n WikiLintIssue,\n WikiLintResult,\n} from './workspace-types.js';\n\nexport { readKnowledgePage } from './markdown.js';\n\nexport interface CompileKnowledgeWorkspaceResult {\n proposals: KnowledgeProposal[];\n published: KnowledgePageRecord[];\n}\n\nfunction hash(value: string): string {\n return createHash('sha256').update(value).digest('hex');\n}\n\nfunction now(): string {\n return new Date().toISOString();\n}\n\nasync function storeFor(workspace: KnowledgeWorkspace): Promise<KnowledgeWorkspaceStore> {\n if (!workspace.dataDir) throw new Error('Knowledge workspace has no operational data directory');\n const store = new KnowledgeWorkspaceStore();\n await store.init(workspace.dataDir);\n return store;\n}\n\nfunction topicSlug(subject: string): string {\n const safe = subject\n .toLocaleLowerCase('en-US')\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '')\n .slice(0, 48);\n return (safe || 'topic') + '-' + hash(subject).slice(0, 8);\n}\n\nfunction groupClaims(claims: ReturnType<ClaimStore['listClaims']>): Map<string, ReturnType<ClaimStore['listClaims']>> {\n const groups = new Map<string, ReturnType<ClaimStore['listClaims']>>();\n for (const claim of claims) {\n const group = groups.get(claim.subject) ?? [];\n group.push(claim);\n groups.set(claim.subject, group);\n }\n return groups;\n}\n\nfunction selectPublishableClaims(claims: ClaimStore, projectId: string) {\n return claims.listClaims(projectId, { statuses: ['active'], limit: 1_000 })\n .filter(claim => claim.reviewState === 'approved');\n}\n\nfunction evidenceRefs(claims: ReturnType<ClaimStore['listClaims']>, store: ClaimStore): string[] {\n const refs = new Set<string>();\n for (const claim of claims) {\n for (const evidence of store.listEvidence(claim.id)) {\n refs.add('claim:' + claim.id + ':evidence:' + evidence.id);\n }\n }\n return [...refs].sort();\n}\n\nfunction snapshotIdForClaims(claims: ReturnType<ClaimStore['listClaims']>, store: ClaimStore): string | undefined {\n const ids = new Set<string>();\n for (const claim of claims) {\n for (const evidence of store.listEvidence(claim.id)) {\n if (evidence.snapshotId) ids.add(evidence.snapshotId);\n }\n }\n return ids.size === 1 ? [...ids][0] : undefined;\n}\n\nfunction sourceHashForClaims(claims: ReturnType<ClaimStore['listClaims']>, store: ClaimStore): string {\n const source = claims.map(claim => ({\n id: claim.id,\n status: claim.status,\n confidence: claim.confidence,\n evidence: store.listEvidence(claim.id).map(item => ({\n id: item.id,\n kind: item.evidenceKind,\n evidenceId: item.evidenceId,\n relation: item.relation,\n snapshotId: item.snapshotId ?? '',\n capturedHash: item.capturedHash ?? '',\n })),\n }));\n return hash(JSON.stringify(source));\n}\n\nfunction renderTopicBody(title: string, claims: ReturnType<ClaimStore['listClaims']>, store: ClaimStore): string {\n const lines = [\n '# ' + title,\n '',\n 'This page is compiled from approved source-qualified claims.',\n '',\n '## Current claims',\n '',\n ];\n for (const claim of claims) {\n lines.push('- ' + claim.predicate + ': ' + claim.objectValue + ' (claim ' + claim.id + ')');\n }\n lines.push('');\n lines.push('## Evidence');\n lines.push('');\n for (const claim of claims) {\n lines.push('### Claim ' + claim.id);\n const evidence = store.listEvidence(claim.id);\n if (evidence.length === 0) {\n lines.push('- Missing evidence.');\n continue;\n }\n for (const item of evidence) {\n const location = item.locator ? ' at ' + item.locator : '';\n const snapshot = item.snapshotId ? ' (snapshot ' + item.snapshotId + ')' : '';\n lines.push('- ' + item.evidenceKind + ': ' + item.evidenceId + location + snapshot);\n }\n }\n lines.push('');\n return lines.join('\\n');\n}\n\nfunction candidatePage(\n workspace: KnowledgeWorkspace,\n title: string,\n claims: ReturnType<ClaimStore['listClaims']>,\n store: ClaimStore,\n): { page: KnowledgePage; content: string; targetRelativePath: string; proposalRelativePath: string } {\n const sourceHash = sourceHashForClaims(claims, store);\n const generatedAt = now();\n const slug = topicSlug(title);\n const targetRelativePath = 'pages/' + slug + '.md';\n const proposalRelativePath = 'proposals/' + slug + '.md';\n const frontmatter: KnowledgePageFrontmatter = {\n id: 'page:' + hash(workspace.projectId + ':' + title).slice(0, 24),\n title,\n kind: 'topic',\n status: 'proposed',\n reviewState: 'needs-review',\n claimIds: claims.map(claim => claim.id).sort(),\n evidenceRefs: evidenceRefs(claims, store),\n ...(snapshotIdForClaims(claims, store) ? { snapshotId: snapshotIdForClaims(claims, store) } : {}),\n tags: ['generated', 'topic'],\n sourceHash,\n generatedAt,\n updatedAt: generatedAt,\n };\n const content = renderKnowledgePage(frontmatter, renderTopicBody(title, claims, store));\n const proposalPath = resolveKnowledgeWorkspaceFile(workspace, proposalRelativePath);\n return {\n page: {\n absolutePath: proposalPath,\n relativePath: proposalRelativePath,\n frontmatter,\n body: renderTopicBody(title, claims, store),\n contentHash: pageContentHash(content),\n links: [],\n },\n content,\n targetRelativePath,\n proposalRelativePath,\n };\n}\n\nasync function fileHashIfPresent(filePath: string): Promise<string | undefined> {\n try {\n return pageContentHash(await fs.readFile(filePath, 'utf8'));\n } catch (error) {\n const code = error && typeof error === 'object' && 'code' in error\n ? (error as { code?: string }).code\n : undefined;\n if (code === 'ENOENT') return undefined;\n throw error;\n }\n}\n\nasync function writeIndex(workspace: KnowledgeWorkspace, store: KnowledgeWorkspaceStore): Promise<void> {\n const paths = getKnowledgeWorkspacePaths(workspace);\n const published = store.listPages(workspace.id)\n .filter(page => page.status === 'active')\n .sort((left, right) => left.title.localeCompare(right.title));\n const pending = store.listProposals(workspace.id, 'pending')\n .sort((left, right) => left.proposalPath.localeCompare(right.proposalPath));\n const lines = ['# Knowledge Workspace', '', '## Published pages', ''];\n if (published.length === 0) {\n lines.push('No published pages yet.');\n } else {\n for (const page of published) lines.push('- [' + page.title + '](' + page.relativePath + ')');\n }\n lines.push('');\n lines.push('## Review queue');\n lines.push('');\n if (pending.length === 0) {\n lines.push('No pending proposals.');\n } else {\n for (const proposal of pending) {\n const relative = path.relative(paths.root, proposal.proposalPath).split(path.sep).join('/');\n lines.push('- [' + path.basename(proposal.proposalPath, '.md') + '](' + relative + ')');\n }\n }\n lines.push('');\n await writeKnowledgePage(paths.index, lines.join('\\n'));\n}\n\nasync function appendLog(workspace: KnowledgeWorkspace, line: string): Promise<void> {\n const logPath = getKnowledgeWorkspacePaths(workspace).log;\n await fs.appendFile(logPath, '- ' + now() + ' ' + line + '\\n', 'utf8');\n}\n\nfunction toPageRecord(\n workspace: KnowledgeWorkspace,\n page: KnowledgePage,\n status: KnowledgePageRecord['status'],\n contentHash: string,\n manualContentHash?: string,\n): KnowledgePageRecord {\n return {\n id: page.frontmatter.id,\n workspaceId: workspace.id,\n relativePath: page.relativePath.replace(/^proposals\\//, 'pages/'),\n title: page.frontmatter.title,\n kind: page.frontmatter.kind,\n status,\n reviewState: page.frontmatter.reviewState,\n contentHash,\n sourceHash: page.frontmatter.sourceHash,\n claimIds: page.frontmatter.claimIds,\n ...(page.frontmatter.snapshotId ? { snapshotId: page.frontmatter.snapshotId } : {}),\n tags: page.frontmatter.tags,\n generatedAt: page.frontmatter.generatedAt,\n updatedAt: page.frontmatter.updatedAt,\n ...(manualContentHash ? { manualContentHash } : {}),\n };\n}\n\nexport async function compileKnowledgeWorkspace(input: {\n workspace: KnowledgeWorkspace;\n claims: ClaimStore;\n}): Promise<CompileKnowledgeWorkspaceResult> {\n const store = await storeFor(input.workspace);\n const published: KnowledgePageRecord[] = [];\n const proposals: KnowledgeProposal[] = [];\n const claims = selectPublishableClaims(input.claims, input.workspace.projectId);\n\n await withFileLock(getKnowledgeWorkspacePaths(input.workspace).root, async () => {\n for (const [title, group] of groupClaims(claims)) {\n const candidate = candidatePage(input.workspace, title, group, input.claims);\n const targetPath = resolveKnowledgeWorkspaceFile(input.workspace, candidate.targetRelativePath);\n const proposalPath = resolveKnowledgeWorkspaceFile(input.workspace, candidate.proposalRelativePath);\n let existing = store.getPage(input.workspace.id, candidate.targetRelativePath);\n const actualTargetHash = await fileHashIfPresent(targetPath);\n if (actualTargetHash && !existing) {\n const manualRecord = {\n ...toPageRecord(input.workspace, candidate.page, 'active', actualTargetHash, actualTargetHash),\n reviewState: 'needs-review' as const,\n sourceHash: 'manual:' + actualTargetHash,\n };\n store.upsertPage(manualRecord);\n existing = manualRecord;\n }\n\n if (\n actualTargetHash\n && existing\n && existing.status === 'active'\n && !existing.manualContentHash\n && actualTargetHash === existing.contentHash\n && existing.sourceHash === candidate.page.frontmatter.sourceHash\n ) {\n published.push(existing);\n continue;\n }\n\n let reason: KnowledgeProposalReason = 'new-page';\n let baseContentHash: string | undefined;\n if (actualTargetHash) {\n baseContentHash = existing?.contentHash;\n if (\n !existing\n || existing.status !== 'active'\n || !!existing.manualContentHash\n || actualTargetHash !== existing.contentHash\n ) {\n reason = 'manual-edit-protected';\n } else {\n reason = 'source-changed';\n }\n }\n\n if (!actualTargetHash) {\n store.upsertPage(toPageRecord(input.workspace, candidate.page, 'proposed', candidate.page.contentHash));\n }\n await writeKnowledgePage(proposalPath, candidate.content);\n const proposal = store.createProposal({\n workspaceId: input.workspace.id,\n pageId: candidate.page.frontmatter.id,\n targetPath,\n proposalPath,\n ...(baseContentHash ? { baseContentHash } : {}),\n sourceHash: candidate.page.frontmatter.sourceHash,\n reason,\n });\n proposals.push(proposal);\n await appendLog(input.workspace, 'proposed ' + candidate.targetRelativePath + ' (' + reason + ').');\n }\n store.markWorkspaceCompiled(input.workspace.id);\n await writeIndex(input.workspace, store);\n });\n return { proposals, published };\n}\n\nexport async function applyKnowledgeProposal(input: {\n workspace: KnowledgeWorkspace;\n proposalId: string;\n /** Explicit review acknowledgement before replacing a manually edited page. */\n allowManualOverwrite?: boolean;\n}): Promise<{ proposal: KnowledgeProposal; targetPath: string }> {\n const store = await storeFor(input.workspace);\n const proposal = store.getProposal(input.proposalId);\n if (!proposal || proposal.workspaceId !== input.workspace.id) {\n throw new Error('Knowledge proposal was not found for this workspace');\n }\n if (proposal.status !== 'pending') throw new Error('Knowledge proposal is not pending review');\n const root = getKnowledgeWorkspacePaths(input.workspace).root;\n const targetPath = path.resolve(proposal.targetPath);\n const proposalPath = path.resolve(proposal.proposalPath);\n if (!targetPath.startsWith(root + path.sep) || !proposalPath.startsWith(root + path.sep)) {\n throw new Error('Knowledge proposal path escapes its workspace');\n }\n\n await withFileLock(root, async () => {\n const actualTargetHash = await fileHashIfPresent(targetPath);\n if (\n proposal.baseContentHash\n && actualTargetHash !== proposal.baseContentHash\n && !input.allowManualOverwrite\n ) {\n throw new Error('The target page has manual changes; review the proposal before applying it');\n }\n if (!proposal.baseContentHash && actualTargetHash && !input.allowManualOverwrite) {\n throw new Error('The target page already exists and has no known safe base revision');\n }\n const proposalPage = await readKnowledgePage(proposalPath, root);\n const activeFrontmatter: KnowledgePageFrontmatter = {\n ...proposalPage.frontmatter,\n status: 'active',\n reviewState: 'approved',\n updatedAt: now(),\n };\n const content = renderKnowledgePage(activeFrontmatter, proposalPage.body);\n const contentHash = await writeKnowledgePage(targetPath, content);\n const activePage = await readKnowledgePage(targetPath, root);\n const record = toPageRecord(input.workspace, activePage, 'active', contentHash);\n store.upsertPage(record);\n store.replacePageClaims(record.id, record.claimIds);\n store.replacePageLinks(record.id, activePage.links.map(link => resolvePageLink(record.relativePath, link)).filter((link): link is string => !!link));\n store.markProposalApplied(proposal.id);\n await appendLog(\n input.workspace,\n 'applied ' + record.relativePath + (input.allowManualOverwrite ? ' after explicit manual overwrite review.' : '.'),\n );\n await writeIndex(input.workspace, store);\n });\n return { proposal: store.getProposal(proposal.id)!, targetPath };\n}\n\nasync function markdownFiles(directory: string): Promise<string[]> {\n const files: string[] = [];\n let entries: Array<import('node:fs').Dirent>;\n try {\n entries = await fs.readdir(directory, { withFileTypes: true });\n } catch {\n return files;\n }\n for (const entry of entries) {\n const filePath = path.join(directory, entry.name);\n if (entry.isDirectory()) {\n files.push(...await markdownFiles(filePath));\n } else if (entry.isFile() && entry.name.toLowerCase().endsWith('.md')) {\n files.push(filePath);\n }\n }\n return files;\n}\n\nexport async function lintKnowledgeWorkspace(input: {\n workspace: KnowledgeWorkspace;\n claims: ClaimStore;\n codeStore?: CodeGraphStore;\n}): Promise<WikiLintResult> {\n const store = await storeFor(input.workspace);\n const paths = getKnowledgeWorkspacePaths(input.workspace);\n const issues: WikiLintIssue[] = [];\n const validPages: KnowledgePage[] = [];\n const files = await markdownFiles(paths.pages);\n\n for (const filePath of files) {\n try {\n validPages.push(await readKnowledgePage(filePath, paths.root));\n } catch (error) {\n issues.push({\n kind: 'malformed-frontmatter',\n severity: 'error',\n message: error instanceof Error ? error.message : 'Malformed knowledge page.',\n relativePath: path.relative(paths.root, filePath).split(path.sep).join('/'),\n });\n }\n }\n\n const indexed = new Set<string>();\n try {\n const index = await fs.readFile(paths.index, 'utf8');\n for (const link of extractInternalMarkdownLinks(index)) {\n const resolved = resolvePageLink('index.md', link);\n if (resolved) indexed.add(resolved);\n }\n } catch {\n issues.push({\n kind: 'broken-link',\n severity: 'error',\n message: 'Knowledge index is missing.',\n relativePath: 'index.md',\n });\n }\n\n const latestSnapshotId = input.codeStore?.latestSnapshot(input.workspace.projectId)?.id;\n for (const page of validPages) {\n if (!indexed.has(page.relativePath)) {\n issues.push({\n kind: 'orphan-page',\n severity: 'warning',\n message: 'Page is not linked from index.md.',\n relativePath: page.relativePath,\n });\n }\n for (const link of page.links) {\n const target = resolvePageLink(page.relativePath, link);\n if (!target || !await fileHashIfPresent(resolveKnowledgeWorkspaceFile(input.workspace, target))) {\n issues.push({\n kind: 'broken-link',\n severity: 'error',\n message: 'Internal Markdown link does not resolve to a workspace page.',\n relativePath: page.relativePath,\n });\n }\n }\n for (const claimId of page.frontmatter.claimIds) {\n const claim = input.claims.getClaim(claimId);\n if (!claim) {\n issues.push({\n kind: 'missing-claim',\n severity: 'error',\n message: 'Page references a claim that is not present in the ledger.',\n relativePath: page.relativePath,\n claimId,\n });\n continue;\n }\n if (input.claims.listEvidence(claim.id).length === 0) {\n issues.push({\n kind: 'missing-evidence',\n severity: 'error',\n message: 'Page claim has no source evidence.',\n relativePath: page.relativePath,\n claimId,\n });\n }\n if (claim.status === 'superseded') {\n issues.push({\n kind: 'superseded-claim',\n severity: 'error',\n message: 'Page still presents a superseded primary claim.',\n relativePath: page.relativePath,\n claimId,\n });\n }\n if (claim.status === 'disputed') {\n issues.push({\n kind: 'unresolved-conflict',\n severity: 'error',\n message: 'Page claim has an unresolved competing assertion.',\n relativePath: page.relativePath,\n claimId,\n });\n }\n }\n if (latestSnapshotId && page.frontmatter.snapshotId && page.frontmatter.snapshotId !== latestSnapshotId) {\n issues.push({\n kind: 'stale-snapshot',\n severity: 'warning',\n message: 'Page was compiled against an older code snapshot.',\n relativePath: page.relativePath,\n });\n }\n }\n\n for (const proposal of store.listProposals(input.workspace.id, 'pending')) {\n if (proposal.reason === 'manual-edit-protected') {\n issues.push({\n kind: 'manual-edit-protected',\n severity: 'warning',\n message: 'A newer proposal was held because the target page has manual edits.',\n relativePath: path.relative(paths.root, proposal.targetPath).split(path.sep).join('/'),\n });\n }\n }\n\n const valid = !issues.some(issue => issue.severity === 'error');\n store.markWorkspaceLinted(input.workspace.id, valid ? 'ready' : 'needs-review');\n return { valid, pagesScanned: validPages.length, issues };\n}\n","import matter from 'gray-matter';\nimport type { AgentTarget, WorkflowEntry } from '../types.js';\n\n/**\n * WorkflowSyncer — converts workflows between agent formats.\n *\n * Supported conversions:\n * Windsurf .windsurf/workflows/*.md → Codex SKILL.md\n * Windsurf .windsurf/workflows/*.md → Cursor .cursor/rules/*.mdc\n * Windsurf .windsurf/workflows/*.md → Claude Code CLAUDE.md section\n */\nexport class WorkflowSyncer {\n /**\n * Parse a Windsurf workflow markdown file into a WorkflowEntry.\n */\n parseWindsurfWorkflow(fileName: string, raw: string): WorkflowEntry {\n const name = fileName.replace(/\\.md$/i, '');\n let description = '';\n let content = raw;\n\n try {\n const parsed = matter(raw);\n description = parsed.data?.description ?? '';\n content = parsed.content.trim();\n } catch {\n // No frontmatter — use raw content\n }\n\n return {\n name,\n description,\n content,\n source: 'windsurf',\n filePath: `.windsurf/workflows/${fileName}`,\n };\n }\n\n /**\n * Convert a workflow to Codex SKILL.md format.\n */\n toCodexSkill(wf: WorkflowEntry): { filePath: string; content: string } {\n const safeName = this.sanitizeName(wf.name);\n const fm: Record<string, string> = { name: safeName };\n if (wf.description) {\n fm.description = wf.description;\n }\n const content = matter.stringify(wf.content, fm);\n return {\n filePath: `.agents/skills/${safeName}/SKILL.md`,\n content,\n };\n }\n\n /**\n * Convert a workflow to Cursor .mdc rule format.\n */\n toCursorRule(wf: WorkflowEntry): { filePath: string; content: string } {\n const safeName = this.sanitizeName(wf.name);\n const fm: Record<string, string> = {};\n if (wf.description) {\n fm.description = wf.description;\n }\n fm.globs = '';\n fm.alwaysApply = 'false';\n const content = matter.stringify(wf.content, fm);\n return {\n filePath: `.cursor/rules/${safeName}.mdc`,\n content,\n };\n }\n\n /**\n * Convert a workflow to a CLAUDE.md section string.\n */\n toClaudeSection(wf: WorkflowEntry): string {\n const lines: string[] = [];\n lines.push(`## Workflow: ${wf.name}`);\n if (wf.description) {\n lines.push('');\n lines.push(`> ${wf.description}`);\n }\n lines.push('');\n lines.push(wf.content);\n return lines.join('\\n');\n }\n\n /**\n * Convert all workflows to the target agent format.\n * Returns an array of { filePath, content } for each generated file.\n */\n convertAll(\n workflows: WorkflowEntry[],\n target: AgentTarget,\n ): { filePath: string; content: string }[] {\n if (target === 'windsurf') {\n // No conversion needed — already in Windsurf format\n return [];\n }\n\n if (target === 'codex') {\n return workflows.map((wf) => this.toCodexSkill(wf));\n }\n\n if (target === 'cursor') {\n return workflows.map((wf) => this.toCursorRule(wf));\n }\n\n if (target === 'claude-code') {\n // Merge all workflows into a single CLAUDE.md\n const sections = workflows.map((wf) => this.toClaudeSection(wf));\n return [\n {\n filePath: 'CLAUDE.md',\n content: sections.join('\\n\\n'),\n },\n ];\n }\n\n return [];\n }\n\n // ---- Helpers ----\n\n private sanitizeName(name: string): string {\n return name\n .replace(/[^a-zA-Z0-9_-]/g, '-')\n .replace(/-+/g, '-')\n .replace(/^-|-$/g, '')\n || 'workflow';\n }\n}\n","import { randomUUID } from 'node:crypto';\nimport { getDatabase } from '../store/sqlite-db.js';\nimport type {\n WorkflowRun,\n WorkflowRunInput,\n WorkflowRunOutcome,\n WorkflowSpec,\n WorkflowVerificationVerdict,\n} from './workflow-types.js';\n\nfunction parseJson<T>(value: unknown, fallback: T): T {\n if (typeof value !== 'string' || !value) return fallback;\n try {\n return JSON.parse(value) as T;\n } catch {\n return fallback;\n }\n}\n\nfunction optionalText(value: unknown): string | undefined {\n return typeof value === 'string' && value.trim() ? value : undefined;\n}\n\nfunction rowToWorkflow(row: any): WorkflowSpec {\n return parseJson<WorkflowSpec>(row.specJson, {\n id: row.id,\n workspaceId: row.workspaceId,\n title: row.title,\n description: '',\n status: row.status,\n version: row.version,\n taskLenses: [],\n triggers: [],\n assumptions: [],\n requiredContext: [],\n guardrails: [],\n allowedTools: [],\n phases: [],\n verificationGates: [],\n claimIds: [],\n evidenceRefs: [],\n codeRefs: [],\n compatibleAgents: [],\n body: '',\n sourcePath: row.sourcePath,\n sourceHash: row.sourceHash,\n contentHash: row.contentHash,\n createdAt: row.createdAt,\n updatedAt: row.updatedAt,\n });\n}\n\nfunction rowToRun(row: any): WorkflowRun {\n return {\n id: row.id,\n workflowId: row.workflowId,\n projectId: row.projectId,\n task: row.task,\n ...(optionalText(row.startingSnapshotId) ? { startingSnapshotId: row.startingSnapshotId } : {}),\n selectedEvidence: parseJson<string[]>(row.selectedEvidenceJson, []),\n phaseState: parseJson<WorkflowRun['phaseState']>(row.phaseStateJson, {}),\n outcome: row.outcome as WorkflowRunOutcome,\n verificationVerdict: row.verificationVerdict as WorkflowVerificationVerdict,\n ...(optionalText(row.failureReason) ? { failureReason: row.failureReason } : {}),\n startedAt: row.startedAt,\n ...(optionalText(row.completedAt) ? { completedAt: row.completedAt } : {}),\n };\n}\n\nexport class WorkflowStore {\n private db: any = null;\n\n async init(dataDir: string): Promise<void> {\n this.db = getDatabase(dataDir);\n }\n\n upsertWorkflow(workflow: WorkflowSpec): WorkflowSpec {\n this.db.prepare(\n 'INSERT INTO knowledge_workflows (id, workspaceId, sourcePath, title, status, version, sourceHash, contentHash, specJson, importedFrom, createdAt, updatedAt) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT(workspaceId, sourcePath) DO UPDATE SET id = excluded.id, title = excluded.title, status = excluded.status, version = excluded.version, sourceHash = excluded.sourceHash, contentHash = excluded.contentHash, specJson = excluded.specJson, importedFrom = excluded.importedFrom, updatedAt = excluded.updatedAt',\n ).run(\n workflow.id,\n workflow.workspaceId,\n workflow.sourcePath,\n workflow.title,\n workflow.status,\n workflow.version,\n workflow.sourceHash,\n workflow.contentHash,\n JSON.stringify(workflow),\n workflow.importedFrom ?? null,\n workflow.createdAt,\n workflow.updatedAt,\n );\n return this.getWorkflowByPath(workflow.workspaceId, workflow.sourcePath)!;\n }\n\n getWorkflow(id: string): WorkflowSpec | undefined {\n const row = this.db.prepare('SELECT * FROM knowledge_workflows WHERE id = ?').get(id);\n return row ? rowToWorkflow(row) : undefined;\n }\n\n getWorkflowByPath(workspaceId: string, sourcePath: string): WorkflowSpec | undefined {\n const row = this.db.prepare('SELECT * FROM knowledge_workflows WHERE workspaceId = ? AND sourcePath = ?').get(workspaceId, sourcePath);\n return row ? rowToWorkflow(row) : undefined;\n }\n\n listWorkflows(workspaceId: string, status?: WorkflowSpec['status']): WorkflowSpec[] {\n const rows = status\n ? this.db.prepare('SELECT * FROM knowledge_workflows WHERE workspaceId = ? AND status = ? ORDER BY title, id').all(workspaceId, status)\n : this.db.prepare('SELECT * FROM knowledge_workflows WHERE workspaceId = ? ORDER BY title, id').all(workspaceId);\n return rows.map(rowToWorkflow);\n }\n\n recordRun(input: WorkflowRunInput): WorkflowRun {\n const run: WorkflowRun = {\n id: randomUUID(),\n workflowId: input.workflowId,\n projectId: input.projectId,\n task: input.task.trim(),\n ...(input.startingSnapshotId ? { startingSnapshotId: input.startingSnapshotId } : {}),\n selectedEvidence: [...new Set(input.selectedEvidence ?? [])],\n phaseState: input.phaseState ?? {},\n outcome: input.outcome,\n verificationVerdict: input.verificationVerdict ?? (input.outcome === 'failed' ? 'failed' : 'not-run'),\n ...(input.failureReason?.trim() ? { failureReason: input.failureReason.trim() } : {}),\n startedAt: input.startedAt ?? new Date().toISOString(),\n ...(input.completedAt ? { completedAt: input.completedAt } : input.outcome !== 'in-progress' ? { completedAt: new Date().toISOString() } : {}),\n };\n this.db.prepare(\n 'INSERT INTO knowledge_workflow_runs (id, workflowId, projectId, task, startingSnapshotId, selectedEvidenceJson, phaseStateJson, outcome, verificationVerdict, failureReason, startedAt, completedAt) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)',\n ).run(\n run.id,\n run.workflowId,\n run.projectId,\n run.task,\n run.startingSnapshotId ?? null,\n JSON.stringify(run.selectedEvidence),\n JSON.stringify(run.phaseState),\n run.outcome,\n run.verificationVerdict,\n run.failureReason ?? null,\n run.startedAt,\n run.completedAt ?? null,\n );\n return this.getRun(run.id)!;\n }\n\n getRun(id: string): WorkflowRun | undefined {\n const row = this.db.prepare('SELECT * FROM knowledge_workflow_runs WHERE id = ?').get(id);\n return row ? rowToRun(row) : undefined;\n }\n\n listRuns(projectId: string, workflowId?: string, limit = 20): WorkflowRun[] {\n const boundedLimit = Math.max(1, Math.min(Math.floor(limit), 100));\n const rows = workflowId\n ? this.db.prepare('SELECT * FROM knowledge_workflow_runs WHERE projectId = ? AND workflowId = ? ORDER BY startedAt DESC LIMIT ?').all(projectId, workflowId, boundedLimit)\n : this.db.prepare('SELECT * FROM knowledge_workflow_runs WHERE projectId = ? ORDER BY startedAt DESC LIMIT ?').all(projectId, boundedLimit);\n return rows.map(rowToRun);\n }\n\n recentFailureCautions(projectId: string, workflowId: string, limit = 2): string[] {\n return this.listRuns(projectId, workflowId, limit)\n .filter(run => run.outcome === 'failed' || run.verificationVerdict === 'failed')\n .map(run => run.failureReason\n ? 'Previous run failed: ' + run.failureReason\n : 'Previous run has a failed verification gate.');\n }\n}\n","import type { ProjectContextExplain } from './project-context.js';\n\nexport type TaskLensId =\n | 'bugfix'\n | 'feature'\n | 'release'\n | 'onboarding'\n | 'refactor'\n | 'docs'\n | 'test'\n | 'general';\n\nexport interface TaskLens {\n id: TaskLensId;\n description: string;\n sourceLimit: number;\n cautionLimit: number;\n hideUnrelatedCautionDetails: boolean;\n hideUnrelatedReliableDetails: boolean;\n}\n\ntype ProjectContextSource = ProjectContextExplain['sources'][number];\n\nconst STOP_WORDS = new Set([\n 'a',\n 'an',\n 'and',\n 'as',\n 'for',\n 'in',\n 'into',\n 'of',\n 'on',\n 'onto',\n 'the',\n 'this',\n 'that',\n 'to',\n 'with',\n 'work',\n 'project',\n 'continue',\n '继续',\n '项目',\n]);\n\nconst LENSES: Record<TaskLensId, TaskLens> = {\n bugfix: {\n id: 'bugfix',\n description: 'debug the failure with current code and the smallest repro first',\n sourceLimit: 6,\n cautionLimit: 4,\n hideUnrelatedCautionDetails: true,\n hideUnrelatedReliableDetails: false,\n },\n feature: {\n id: 'feature',\n description: 'build a scoped feature from nearby source, types, and user flow',\n sourceLimit: 6,\n cautionLimit: 3,\n hideUnrelatedCautionDetails: true,\n hideUnrelatedReliableDetails: false,\n },\n release: {\n id: 'release',\n description: 'prepare a release using current metadata, changelog, build, and package checks',\n sourceLimit: 4,\n cautionLimit: 2,\n hideUnrelatedCautionDetails: true,\n hideUnrelatedReliableDetails: true,\n },\n onboarding: {\n id: 'onboarding',\n description: 'understand the project shape before trusting old implementation details',\n sourceLimit: 4,\n cautionLimit: 2,\n hideUnrelatedCautionDetails: true,\n hideUnrelatedReliableDetails: true,\n },\n refactor: {\n id: 'refactor',\n description: 'change structure carefully by reading shared code, call sites, and tests',\n sourceLimit: 6,\n cautionLimit: 4,\n hideUnrelatedCautionDetails: true,\n hideUnrelatedReliableDetails: false,\n },\n docs: {\n id: 'docs',\n description: 'update documentation against current code and public entry points',\n sourceLimit: 5,\n cautionLimit: 2,\n hideUnrelatedCautionDetails: true,\n hideUnrelatedReliableDetails: true,\n },\n test: {\n id: 'test',\n description: 'work from tests, fixtures, harnesses, and the related source files',\n sourceLimit: 6,\n cautionLimit: 3,\n hideUnrelatedCautionDetails: true,\n hideUnrelatedReliableDetails: false,\n },\n general: {\n id: 'general',\n description: 'balanced project handoff with current facts, code memory, and verification hints',\n sourceLimit: 8,\n cautionLimit: 5,\n hideUnrelatedCautionDetails: false,\n hideUnrelatedReliableDetails: false,\n },\n};\n\nconst KEYWORDS: Record<Exclude<TaskLensId, 'general'>, string[]> = {\n bugfix: [\n 'bug',\n 'crash',\n 'incident',\n 'debug',\n 'error',\n 'fail',\n 'failing',\n 'fix',\n 'fixing',\n 'issue',\n 'regression',\n 'repro',\n '报错',\n '崩溃',\n '故障',\n '失败',\n '修复',\n '问题',\n ],\n feature: ['add', 'build', 'feature', 'implement', 'new', 'support', '新增', '实现', '支持', '功能'],\n release: ['bump', 'changelog', 'npm', 'pack', 'publish', 'release', 'version', '发版', '发布', '版本'],\n onboarding: ['architecture', 'handoff', 'onboard', 'overview', 'understand', '接手', '了解', '理解', '架构'],\n refactor: ['cleanup', 'migrate', 'refactor', 'rename', 'restructure', '重构', '迁移', '改造'],\n docs: ['doc', 'docs', 'readme', '文档', '说明'],\n test: ['coverage', 'fixture', 'smoke', 'spec', 'test', 'tests', 'testing', 'vitest', '测试'],\n};\n\n// Continuation is a delivery intent, not a task lens. A request can both resume\n// prior work and be a bugfix, feature, or release task, so callers keep the\n// normal lens and add a bounded prior-work projection separately.\nconst CONTINUATION_KEYWORDS = [\n 'continue',\n 'resume',\n 'pick up',\n 'carry on',\n 'previous session',\n '继续',\n '接手',\n '恢复',\n '延续',\n '上次会话',\n];\n\nconst LENS_PRIORITY: Exclude<TaskLensId, 'general'>[] = [\n 'bugfix',\n 'release',\n 'test',\n 'refactor',\n 'feature',\n 'docs',\n 'onboarding',\n];\n\nfunction normalizePath(path: string): string {\n return path.replace(/\\\\/g, '/');\n}\n\nfunction tokenize(text: string): string[] {\n return (text.toLowerCase().match(/[a-z0-9_./-]+|[\\u4e00-\\u9fff]+/g) ?? [])\n .map(token => token.trim())\n .filter(token => token.length > 1 && !STOP_WORDS.has(token));\n}\n\n/**\n * Match a task keyword only when the task states it as an action or intent,\n * rather than prohibiting that action. Workflow selection shares this rule so\n * a safety constraint cannot reintroduce an intent rejected by task routing.\n */\nexport function containsTaskKeyword(text: string, keyword: string): boolean {\n const matcher = /^[a-z0-9_-]+$/i.test(keyword)\n ? new RegExp(`(^|[^a-z0-9_-])${keyword.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')}(?=[^a-z0-9_-]|$)`, 'gi')\n : new RegExp(keyword.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'), 'gi');\n let match: RegExpExecArray | null;\n while ((match = matcher.exec(text)) !== null) {\n const keywordIndex = match.index + (match[1]?.length ?? 0);\n if (!isNegatedTaskKeyword(text, keywordIndex)) return true;\n }\n return false;\n}\n\n/**\n * Task text often carries safety constraints such as \"do not publish\". Those\n * constraints must not route a debugging task into the release workflow.\n * Keep this deliberately small and local: it only suppresses a keyword inside\n * the same sentence when the sentence explicitly negates an action.\n */\nfunction isNegatedTaskKeyword(text: string, keywordIndex: number): boolean {\n const boundary = Math.max(\n text.lastIndexOf('.', keywordIndex - 1),\n text.lastIndexOf('!', keywordIndex - 1),\n text.lastIndexOf('?', keywordIndex - 1),\n text.lastIndexOf(';', keywordIndex - 1),\n text.lastIndexOf('\\n', keywordIndex - 1),\n text.lastIndexOf('\\u3002', keywordIndex - 1),\n text.lastIndexOf('\\uff01', keywordIndex - 1),\n text.lastIndexOf('\\uff1f', keywordIndex - 1),\n text.lastIndexOf('\\uff1b', keywordIndex - 1),\n );\n let prefix = text.slice(boundary + 1, keywordIndex).toLowerCase();\n const contrast = /(?:,|\\uff0c)\\s*(?:but|however|instead|yet|\\u4f46\\u662f|\\u4f46|\\u800c\\u662f)\\s*/gi;\n let contrastMatch: RegExpExecArray | null;\n let contrastEnd = -1;\n while ((contrastMatch = contrast.exec(prefix)) !== null) contrastEnd = contrast.lastIndex;\n if (contrastEnd >= 0) prefix = prefix.slice(contrastEnd);\n if (/\\b(?:do|does|did|should|must|can|could|will|would|may|might)\\s+not\\b/.test(prefix)) return true;\n if (/\\b(?:don't|dont|never|without|avoid|skip)\\b/.test(prefix)) return true;\n if (/(?:^|[\\s,])no\\s+(?:[a-z0-9_-]+\\s*){0,4}$/i.test(prefix)) return true;\n const chineseClauseStart = Math.max(prefix.lastIndexOf(','), prefix.lastIndexOf('\\uff0c'), prefix.lastIndexOf('\\u3001'));\n const chineseClause = prefix.slice(chineseClauseStart + 1);\n return /(?:\\u4e0d\\u8981|\\u4e0d\\u5e94|\\u4e0d\\u53ef|\\u4e0d\\u80fd|\\u4e0d\\u4f1a|\\u7981\\u6b62|\\u52ff|\\u4e0d)\\s*(?:\\u7acb\\u5373|\\u76f4\\u63a5|\\u518d|\\u73b0\\u5728|\\u64c5\\u81ea|\\u5148)?\\s*$/.test(chineseClause);\n}\n\nexport function resolveTaskLens(task?: string): TaskLens {\n const normalized = (task ?? '').toLowerCase();\n if (!normalized.trim()) return LENSES.general;\n\n let best: { id: TaskLensId; score: number; priority: number } = {\n id: 'general',\n score: 0,\n priority: Number.MAX_SAFE_INTEGER,\n };\n\n for (const id of LENS_PRIORITY) {\n const score = KEYWORDS[id].reduce((sum, keyword) => sum + (containsTaskKeyword(normalized, keyword) ? 1 : 0), 0);\n const priority = LENS_PRIORITY.indexOf(id);\n if (score > best.score || (score === best.score && score > 0 && priority < best.priority)) {\n best = { id, score, priority };\n }\n }\n\n return best.score > 0 ? LENSES[best.id] : LENSES.general;\n}\n\n/**\n * Detect when the caller is asking to continue existing work. This stays\n * separate from task-lens routing so \"continue fixing the timeout\" remains a\n * bugfix, while still receiving a compact prior-work brief.\n */\nexport function isContinuationTask(task?: string): boolean {\n const normalized = (task ?? '').trim().toLowerCase();\n return normalized.length > 0 && CONTINUATION_KEYWORDS.some((keyword) =>\n containsTaskKeyword(normalized, keyword),\n );\n}\n\nfunction pathKindScore(path: string, lens: TaskLens): number {\n const normalized = normalizePath(path).toLowerCase();\n const name = normalized.split('/').pop() ?? normalized;\n const inDocs = normalized.startsWith('docs/') || name === 'readme.md' || name.includes('readme');\n const isTest = /(^|\\/)(tests?|__tests__|spec|fixtures?)\\//.test(normalized)\n || /\\.(test|spec)\\.[cm]?[jt]sx?$/.test(normalized)\n || /\\.(test|spec)\\.py$/.test(normalized);\n const isSource = normalized.startsWith('src/') || normalized.includes('/src/');\n const isPackage = name === 'package.json' || name === 'package-lock.json' || name === 'pnpm-lock.yaml' || name === 'yarn.lock';\n const isChangelog = name === 'changelog.md' || name === 'changes.md';\n const isWorkflow = normalized.startsWith('.github/workflows/');\n\n switch (lens.id) {\n case 'bugfix':\n return (isTest ? 80 : 0) + (isSource ? 50 : 0) + (normalized.includes('debug') ? 20 : 0);\n case 'test':\n return (isTest ? 90 : 0) + (isSource ? 45 : 0);\n case 'release':\n return (isChangelog ? 100 : 0) + (isPackage ? 90 : 0) + (isWorkflow ? 70 : 0) + (inDocs ? 35 : 0);\n case 'onboarding':\n return (name === 'readme.md' ? 100 : 0) + (inDocs ? 80 : 0) + (isPackage ? 45 : 0) + (isSource ? 20 : 0);\n case 'docs':\n return (inDocs ? 100 : 0) + (isChangelog ? 60 : 0) + (isSource ? 25 : 0);\n case 'refactor':\n return (isSource ? 70 : 0) + (isTest ? 65 : 0);\n case 'feature':\n return (isSource ? 80 : 0) + (isTest ? 45 : 0) + (inDocs ? 20 : 0);\n default:\n if (isSource || isTest) return 60;\n if (normalized.startsWith('packages/') && normalized.includes('/src/')) return 45;\n if (inDocs) return 20;\n return 0;\n }\n}\n\nfunction tokenScore(text: string, tokens: string[]): number {\n if (tokens.length === 0) return 0;\n const normalized = text.toLowerCase();\n return tokens.reduce((sum, token) => sum + (normalized.includes(token) ? 12 : 0), 0);\n}\n\nfunction sourceTaskMatchScore(source: ProjectContextSource, task?: string): number {\n const tokens = tokenize(task ?? '');\n if (tokens.length === 0) return 0;\n const text = [\n source.title,\n source.path ?? '',\n source.symbol ?? '',\n ].join('\\n').toLowerCase();\n const matches = tokens.filter(token => text.includes(token)).length;\n if (matches >= 2) return 40;\n if (matches === 1) return 24;\n return 0;\n}\n\nfunction fallbackPathRank(path: string): number {\n const normalized = normalizePath(path);\n if (normalized.startsWith('src/')) return 0;\n if (normalized.startsWith('tests/') || normalized.startsWith('test/')) return 1;\n if (normalized.startsWith('packages/') && normalized.includes('/src/')) return 2;\n if (normalized.startsWith('docs/') || normalized.toLowerCase() === 'readme.md') return 3;\n return 4;\n}\n\nexport function rankLensPaths(paths: string[], lens: TaskLens, task?: string): string[] {\n const tokens = tokenize(task ?? '');\n return [...new Set(paths.map(normalizePath))]\n .map((path, index) => ({\n path,\n index,\n score: pathKindScore(path, lens) + tokenScore(path, tokens),\n fallback: fallbackPathRank(path),\n }))\n .sort((a, b) => b.score - a.score || a.fallback - b.fallback || a.index - b.index || a.path.localeCompare(b.path))\n .map(item => item.path);\n}\n\nexport function lensPathCandidates(lens: TaskLens): string[] {\n switch (lens.id) {\n case 'release':\n return ['CHANGELOG.md', 'package.json', 'package-lock.json', '.github/workflows/ci.yml', '.github/workflows/test.yml', 'README.md'];\n case 'onboarding':\n return ['README.md', 'docs/README.md', 'docs/API_REFERENCE.md', 'package.json'];\n case 'docs':\n return ['README.md', 'README.zh-CN.md', 'docs/README.md', 'docs/API_REFERENCE.md', 'CHANGELOG.md'];\n case 'test':\n case 'bugfix':\n return ['tests', 'test'];\n default:\n return [];\n }\n}\n\nexport function scoreLensSource(source: ProjectContextSource, lens: TaskLens, task?: string): number {\n const tokens = tokenize(task ?? '');\n const text = [source.title, source.type, source.path ?? '', source.symbol ?? ''].join('\\n');\n return pathKindScore(source.path ?? '', lens) + tokenScore(text, tokens) + sourceTaskMatchScore(source, task);\n}\n\nexport function rankLensSources<T extends ProjectContextSource>(sources: T[], lens: TaskLens, task?: string): T[] {\n return [...sources]\n .map((source, index) => ({\n source,\n index,\n score: scoreLensSource(source, lens, task),\n }))\n .sort((a, b) => b.score - a.score || a.source.observationId - b.source.observationId || a.index - b.index)\n .map(item => item.source);\n}\n\nexport function lensVerificationHints(lens: TaskLens): string[] {\n switch (lens.id) {\n case 'bugfix':\n return [\n 'run the smallest failing test or repro first',\n 'inspect the changed code path before trusting old memory',\n ];\n case 'test':\n return [\n 'run the exact focused test file or test name first',\n 'inspect fixtures and harness setup before changing assertions',\n ];\n case 'release':\n return [\n 'run build, tests, package smoke, and publish dry-run where available',\n 'verify package metadata, changelog, and Git state before publishing',\n ];\n case 'onboarding':\n return [\n 'read the docs/start files first, then inspect only the code paths needed for the task',\n 'treat old implementation memories as leads until current code confirms them',\n ];\n case 'refactor':\n return [\n 'inspect call sites and tests before editing shared code',\n 'run the narrow affected test plus one regression smoke',\n ];\n case 'docs':\n return [\n 'check headings, links, commands, and examples against current code',\n 'run the smallest docs or package smoke available',\n ];\n case 'feature':\n return [\n 'inspect the closest existing implementation pattern before adding new code',\n 'run focused tests plus one user-flow smoke after changes',\n ];\n default:\n return [\n 'inspect the Start here files before editing',\n 'run the smallest relevant test or smoke command after changes',\n ];\n }\n}\n\nexport function shouldShowLensSource(source: ProjectContextSource, lens: TaskLens, task?: string): boolean {\n if (lens.id === 'general') return true;\n const score = scoreLensSource(source, lens, task);\n if (lens.id === 'onboarding' || lens.id === 'release' || lens.id === 'docs') return score >= 40;\n return score > 0;\n}\n","import { createHash } from 'node:crypto';\nimport { promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport matter from 'gray-matter';\nimport type { AgentTarget } from '../types.js';\nimport { atomicWriteFile, withFileLock } from '../store/file-lock.js';\nimport { WorkflowSyncer } from '../workspace/workflow-sync.js';\nimport { getKnowledgeWorkspacePaths, resolveKnowledgeWorkspaceFile } from './workspace.js';\nimport { WorkflowStore } from './workflow-store.js';\nimport { containsTaskKeyword } from '../codegraph/task-lens.js';\nimport type {\n WorkflowAdapterPreview,\n WorkflowAdapterTarget,\n WorkflowPhase,\n WorkflowRun,\n WorkflowRunInput,\n WorkflowSelection,\n WorkflowSpec,\n WorkflowStatus,\n} from './workflow-types.js';\nimport type { KnowledgeWorkspace } from './workspace-types.js';\n\nconst KNOWN_AGENTS: AgentTarget[] = [\n 'windsurf',\n 'cursor',\n 'claude-code',\n 'codex',\n 'copilot',\n 'antigravity',\n 'gemini-cli',\n 'openclaw',\n 'hermes',\n 'omp',\n 'kiro',\n 'opencode',\n 'trae',\n];\n\nexport const WORKFLOW_ADAPTER_TARGETS: WorkflowAdapterTarget[] = [\n 'codex',\n 'claude-code',\n 'cursor',\n 'windsurf',\n];\n\nconst STATUS_VALUES: WorkflowStatus[] = ['draft', 'active', 'archived'];\n\nfunction hash(value: string): string {\n return createHash('sha256').update(value).digest('hex');\n}\n\nfunction now(): string {\n return new Date().toISOString();\n}\n\nfunction slug(value: string): string {\n const normalized = value\n .trim()\n .toLowerCase()\n .replace(/[^a-z0-9\\u4e00-\\u9fff]+/g, '-')\n .replace(/^-+|-+$/g, '')\n .slice(0, 72);\n return normalized || 'workflow';\n}\n\nfunction titleFromName(name: string): string {\n return name\n .replace(/[-_]+/g, ' ')\n .split(' ')\n .filter(Boolean)\n .map(part => part.slice(0, 1).toUpperCase() + part.slice(1))\n .join(' ') || 'Imported Workflow';\n}\n\nfunction requiredText(data: Record<string, unknown>, key: string): string {\n const value = data[key];\n if (typeof value !== 'string' || !value.trim()) {\n throw new Error('workflow frontmatter requires ' + key);\n }\n return value.trim();\n}\n\nfunction optionalText(data: Record<string, unknown>, key: string): string | undefined {\n const value = data[key];\n if (value === undefined || value === null || value === '') return undefined;\n if (typeof value !== 'string') throw new Error('workflow frontmatter field ' + key + ' must be text');\n return value.trim() || undefined;\n}\n\nfunction optionalStringArray(data: Record<string, unknown>, key: string): string[] {\n const value = data[key];\n if (value === undefined || value === null) return [];\n if (!Array.isArray(value) || value.some(item => typeof item !== 'string')) {\n throw new Error('workflow frontmatter field ' + key + ' must be a string array');\n }\n return [...new Set(value.map(item => item.trim()).filter(Boolean))];\n}\n\nfunction optionalNumber(data: Record<string, unknown>, key: string, fallback: number): number {\n const value = data[key];\n if (value === undefined || value === null || value === '') return fallback;\n if (typeof value !== 'number' || !Number.isInteger(value) || value < 1) {\n throw new Error('workflow frontmatter field ' + key + ' must be a positive integer');\n }\n return value;\n}\n\nfunction optionalStatus(data: Record<string, unknown>): WorkflowStatus {\n const value = data.status;\n if (value === undefined || value === null || value === '') return 'draft';\n if (typeof value !== 'string' || !STATUS_VALUES.includes(value as WorkflowStatus)) {\n throw new Error('workflow frontmatter field status is invalid');\n }\n return value as WorkflowStatus;\n}\n\nfunction normalizeAgents(values: string[]): AgentTarget[] {\n const unknown = values.filter(value => !KNOWN_AGENTS.includes(value as AgentTarget));\n if (unknown.length > 0) {\n throw new Error('workflow frontmatter has unsupported agent: ' + unknown[0]);\n }\n return values as AgentTarget[];\n}\n\nfunction phaseFromValue(value: unknown, index: number): WorkflowPhase {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n throw new Error('workflow frontmatter phases must contain objects');\n }\n const data = value as Record<string, unknown>;\n const title = requiredText(data, 'title');\n const phaseId = optionalText(data, 'id') ?? slug(title) + '-' + (index + 1);\n return {\n id: phaseId,\n title,\n instructions: optionalText(data, 'instructions') ?? '',\n branches: optionalStringArray(data, 'branches'),\n expectedOutputs: optionalStringArray(data, 'expectedOutputs'),\n verificationGates: optionalStringArray(data, 'verificationGates'),\n };\n}\n\nfunction phasesFromBody(body: string): WorkflowPhase[] {\n const headers = [...body.matchAll(/^##\\s+(.+?)\\s*$/gm)];\n if (headers.length === 0) {\n const instructions = body.trim();\n return instructions\n ? [{\n id: 'execute',\n title: 'Execute',\n instructions,\n branches: [],\n expectedOutputs: [],\n verificationGates: [],\n }]\n : [];\n }\n return headers.map((match, index) => {\n const title = match[1].trim();\n const start = (match.index ?? 0) + match[0].length;\n const end = index + 1 < headers.length\n ? (headers[index + 1].index ?? body.length)\n : body.length;\n return {\n id: slug(title) + '-' + (index + 1),\n title,\n instructions: body.slice(start, end).trim(),\n branches: [],\n expectedOutputs: [],\n verificationGates: [],\n };\n });\n}\n\nfunction normalizeSourcePath(sourcePath: string): string {\n const normalized = sourcePath.replace(/\\\\/g, '/');\n if (\n !normalized.startsWith('workflows/')\n || !normalized.toLowerCase().endsWith('.md')\n || normalized.includes('../')\n || path.posix.normalize(normalized) !== normalized\n ) {\n throw new Error('workflow source path must be a safe workflows/*.md path');\n }\n return normalized;\n}\n\nfunction sourceHashFor(workflow: Omit<WorkflowSpec, 'sourceHash' | 'contentHash'> | WorkflowSpec): string {\n return hash(JSON.stringify({\n id: workflow.id,\n title: workflow.title,\n description: workflow.description,\n status: workflow.status,\n version: workflow.version,\n taskLenses: workflow.taskLenses,\n triggers: workflow.triggers,\n assumptions: workflow.assumptions,\n requiredContext: workflow.requiredContext,\n guardrails: workflow.guardrails,\n allowedTools: workflow.allowedTools,\n phases: workflow.phases,\n verificationGates: workflow.verificationGates,\n claimIds: workflow.claimIds,\n evidenceRefs: workflow.evidenceRefs,\n codeRefs: workflow.codeRefs,\n compatibleAgents: workflow.compatibleAgents,\n body: workflow.body,\n sourcePath: workflow.sourcePath,\n importedFrom: workflow.importedFrom ?? null,\n }));\n}\n\nfunction workflowFrontmatter(workflow: WorkflowSpec, sourceHash: string): Record<string, unknown> {\n return {\n id: workflow.id,\n title: workflow.title,\n description: workflow.description,\n status: workflow.status,\n version: workflow.version,\n taskLenses: workflow.taskLenses,\n triggers: workflow.triggers,\n assumptions: workflow.assumptions,\n requiredContext: workflow.requiredContext,\n guardrails: workflow.guardrails,\n allowedTools: workflow.allowedTools,\n phases: workflow.phases.map(phase => ({\n id: phase.id,\n title: phase.title,\n ...(phase.instructions ? { instructions: phase.instructions } : {}),\n ...(phase.branches.length ? { branches: phase.branches } : {}),\n ...(phase.expectedOutputs.length ? { expectedOutputs: phase.expectedOutputs } : {}),\n ...(phase.verificationGates.length ? { verificationGates: phase.verificationGates } : {}),\n })),\n verificationGates: workflow.verificationGates,\n claimIds: workflow.claimIds,\n evidenceRefs: workflow.evidenceRefs,\n codeRefs: workflow.codeRefs,\n compatibleAgents: workflow.compatibleAgents,\n sourceHash,\n createdAt: workflow.createdAt,\n updatedAt: workflow.updatedAt,\n ...(workflow.importedFrom ? { importedFrom: workflow.importedFrom } : {}),\n };\n}\n\nexport function renderWorkflowMarkdown(workflow: WorkflowSpec): string {\n const sourceHash = sourceHashFor(workflow);\n return matter.stringify(workflow.body.trimEnd() + '\\n', workflowFrontmatter(workflow, sourceHash));\n}\n\nfunction parsedWorkflow(data: Record<string, unknown>, body: string, input: {\n workspaceId: string;\n sourcePath: string;\n contentHash: string;\n}): WorkflowSpec {\n const phasesValue = data.phases;\n const parsedPhases = phasesValue === undefined || phasesValue === null\n ? phasesFromBody(body)\n : Array.isArray(phasesValue)\n ? phasesValue.map(phaseFromValue)\n : (() => { throw new Error('workflow frontmatter field phases must be an array'); })();\n const candidate: WorkflowSpec = {\n id: requiredText(data, 'id'),\n workspaceId: input.workspaceId,\n title: requiredText(data, 'title'),\n description: optionalText(data, 'description') ?? '',\n status: optionalStatus(data),\n version: optionalNumber(data, 'version', 1),\n taskLenses: optionalStringArray(data, 'taskLenses'),\n triggers: optionalStringArray(data, 'triggers'),\n assumptions: optionalStringArray(data, 'assumptions'),\n requiredContext: optionalStringArray(data, 'requiredContext'),\n guardrails: optionalStringArray(data, 'guardrails'),\n allowedTools: optionalStringArray(data, 'allowedTools'),\n phases: parsedPhases,\n verificationGates: optionalStringArray(data, 'verificationGates'),\n claimIds: optionalStringArray(data, 'claimIds'),\n evidenceRefs: optionalStringArray(data, 'evidenceRefs'),\n codeRefs: optionalStringArray(data, 'codeRefs'),\n compatibleAgents: normalizeAgents(optionalStringArray(data, 'compatibleAgents').length\n ? optionalStringArray(data, 'compatibleAgents')\n : optionalStringArray(data, 'allowedAgents')),\n body: body.trim(),\n sourcePath: normalizeSourcePath(input.sourcePath),\n sourceHash: '',\n contentHash: input.contentHash,\n createdAt: optionalText(data, 'createdAt') ?? now(),\n updatedAt: optionalText(data, 'updatedAt') ?? now(),\n ...(optionalText(data, 'importedFrom') ? { importedFrom: optionalText(data, 'importedFrom') } : {}),\n };\n if (candidate.phases.length === 0) {\n throw new Error('workflow must contain at least one phase or a non-empty body');\n }\n return { ...candidate, sourceHash: sourceHashFor(candidate) };\n}\n\nexport function parseWorkflowMarkdown(raw: string, input: {\n workspaceId: string;\n sourcePath: string;\n}): WorkflowSpec {\n let parsed: matter.GrayMatterFile<string>;\n try {\n parsed = matter(raw);\n } catch (error) {\n throw new Error('Malformed workflow Markdown: ' + (error instanceof Error ? error.message : String(error)));\n }\n return parsedWorkflow(parsed.data as Record<string, unknown>, parsed.content, {\n workspaceId: input.workspaceId,\n sourcePath: input.sourcePath,\n contentHash: hash(raw),\n });\n}\n\nfunction workflowStoreDataDir(workspace: KnowledgeWorkspace): string {\n if (!workspace.dataDir) throw new Error('Knowledge workspace is missing its local data directory');\n return workspace.dataDir;\n}\n\nasync function storeFor(workspace: KnowledgeWorkspace): Promise<WorkflowStore> {\n const store = new WorkflowStore();\n await store.init(workflowStoreDataDir(workspace));\n return store;\n}\n\nfunction materializeWorkflow(workflow: WorkflowSpec): WorkflowSpec {\n const updatedAt = workflow.updatedAt || now();\n const withDates = {\n ...workflow,\n createdAt: workflow.createdAt || updatedAt,\n updatedAt,\n };\n const sourceHash = sourceHashFor(withDates);\n const content = renderWorkflowMarkdown({ ...withDates, sourceHash, contentHash: '' });\n return {\n ...withDates,\n sourceHash,\n contentHash: hash(content),\n };\n}\n\nexport async function writeCanonicalWorkflow(input: {\n workspace: KnowledgeWorkspace;\n workflow: WorkflowSpec;\n}): Promise<WorkflowSpec> {\n const paths = getKnowledgeWorkspacePaths(input.workspace);\n const workflow = materializeWorkflow({\n ...input.workflow,\n workspaceId: input.workspace.id,\n sourcePath: normalizeSourcePath(input.workflow.sourcePath),\n });\n const filePath = resolveKnowledgeWorkspaceFile(input.workspace, workflow.sourcePath);\n const content = renderWorkflowMarkdown(workflow);\n await withFileLock(paths.root, async () => {\n await fs.mkdir(path.dirname(filePath), { recursive: true });\n await atomicWriteFile(filePath, content);\n });\n const store = await storeFor(input.workspace);\n return store.upsertWorkflow({ ...workflow, contentHash: hash(content) });\n}\n\nasync function markdownFiles(directory: string): Promise<string[]> {\n let entries: Array<import('node:fs').Dirent>;\n try {\n entries = await fs.readdir(directory, { withFileTypes: true });\n } catch {\n return [];\n }\n const files: string[] = [];\n for (const entry of entries) {\n const absolutePath = path.join(directory, entry.name);\n if (entry.isDirectory()) {\n files.push(...await markdownFiles(absolutePath));\n } else if (entry.isFile() && entry.name.toLowerCase().endsWith('.md')) {\n files.push(absolutePath);\n }\n }\n return files;\n}\n\n/**\n * Make manually authored canonical files visible to selection without changing\n * them. Invalid files are returned as diagnostics instead of being treated as\n * active project instructions.\n */\nexport async function syncCanonicalWorkflows(workspace: KnowledgeWorkspace): Promise<{\n workflows: WorkflowSpec[];\n errors: Array<{ sourcePath: string; message: string }>;\n}> {\n const paths = getKnowledgeWorkspacePaths(workspace);\n const store = await storeFor(workspace);\n const workflows: WorkflowSpec[] = [];\n const errors: Array<{ sourcePath: string; message: string }> = [];\n for (const absolutePath of await markdownFiles(paths.workflows)) {\n const sourcePath = path.relative(paths.root, absolutePath).split(path.sep).join('/');\n try {\n const raw = await fs.readFile(absolutePath, 'utf8');\n const workflow = parseWorkflowMarkdown(raw, { workspaceId: workspace.id, sourcePath });\n workflows.push(store.upsertWorkflow(workflow));\n } catch (error) {\n errors.push({\n sourcePath,\n message: error instanceof Error ? error.message : String(error),\n });\n }\n }\n return { workflows, errors };\n}\n\nconst LENS_TERMS: Record<string, string[]> = {\n release: ['release', 'publish', 'npm', 'version', '发版', '发布'],\n bugfix: ['bug', 'fix', 'error', 'failure', 'issue', 'repair', '修复', '报错', '故障'],\n migration: ['migration', 'migrate', 'upgrade', '迁移', '升级'],\n review: ['review', 'audit', 'pr', 'code review', '审查', '评审'],\n onboarding: ['onboard', 'onboarding', 'understand', 'introduce', '接手', '了解'],\n refactor: ['refactor', 'cleanup', 'restructure', '重构', '整理'],\n test: ['test', 'verify', 'smoke', '测试', '验证'],\n};\n\nconst GENERIC_WORKFLOW_LENSES = new Set(['review', 'test']);\nconst GENERIC_WORKFLOW_TERMS = new Set(['review', 'audit', 'test', 'verify', 'smoke']);\n\nfunction inferTaskLenses(value: string): string[] {\n const text = value.toLowerCase();\n return Object.entries(LENS_TERMS)\n .filter(([, terms]) => terms.some(term => text.includes(term)))\n .map(([lens]) => lens);\n}\n\nfunction taskScore(workflow: WorkflowSpec, task: string): { score: number; reasons: string[] } {\n const text = task.toLowerCase();\n let score = 0;\n const reasons: string[] = [];\n const matchedLenses = new Set<string>();\n const matchedTriggers = new Set<string>();\n for (const lens of workflow.taskLenses) {\n const terms = LENS_TERMS[lens.toLowerCase()] ?? [lens.toLowerCase()];\n if (terms.some(term => containsTaskKeyword(task, term))) {\n score += 20;\n reasons.push('matches ' + lens + ' workflow');\n matchedLenses.add(lens.toLowerCase());\n }\n }\n for (const trigger of workflow.triggers) {\n const term = trigger.toLowerCase().trim();\n if (term.length >= 2 && containsTaskKeyword(task, term)) {\n score += 8;\n reasons.push('matches trigger \"' + trigger + '\"');\n matchedTriggers.add(term);\n }\n }\n const hasSpecificLens = workflow.taskLenses.some(lens => !GENERIC_WORKFLOW_LENSES.has(lens.toLowerCase()));\n const hasSpecificMatch = [...matchedLenses].some(lens => !GENERIC_WORKFLOW_LENSES.has(lens))\n || [...matchedTriggers].some(trigger => !GENERIC_WORKFLOW_TERMS.has(trigger));\n if (hasSpecificLens && !hasSpecificMatch) return { score: 0, reasons: [] };\n return { score, reasons: [...new Set(reasons)] };\n}\n\nexport function selectWorkflows(input: {\n workflows: WorkflowSpec[];\n task: string;\n projectId?: string;\n store?: WorkflowStore;\n limit?: number;\n}): WorkflowSelection[] {\n const selected = input.workflows\n .filter(workflow => workflow.status === 'active')\n .map(workflow => {\n const match = taskScore(workflow, input.task);\n const cautions = input.store && input.projectId\n ? input.store.recentFailureCautions(input.projectId, workflow.id)\n : [];\n return {\n workflow,\n score: match.score,\n reasons: match.reasons,\n firstPhase: workflow.phases[0],\n cautions,\n };\n })\n .filter(item => item.score > 0)\n .sort((left, right) => right.score - left.score || left.workflow.title.localeCompare(right.workflow.title));\n return selected.slice(0, Math.max(1, Math.min(input.limit ?? 2, 2)));\n}\n\nfunction importedWorkflowSpec(input: {\n workspace: KnowledgeWorkspace;\n sourceName: string;\n sourcePath: string;\n raw: string;\n}): WorkflowSpec {\n let sourceMatter: matter.GrayMatterFile<string>;\n try {\n sourceMatter = matter(input.raw);\n } catch (error) {\n throw new Error('Malformed Windsurf workflow Markdown: ' + (error instanceof Error ? error.message : String(error)));\n }\n if (sourceMatter.data.id !== undefined) {\n const id = requiredText(sourceMatter.data as Record<string, unknown>, 'id');\n const sourcePath = 'workflows/' + slug(id) + '.md';\n const canonical = parsedWorkflow(sourceMatter.data as Record<string, unknown>, sourceMatter.content, {\n workspaceId: input.workspace.id,\n sourcePath,\n contentHash: hash(input.raw),\n });\n return materializeWorkflow({\n ...canonical,\n importedFrom: input.sourcePath.replace(/\\\\/g, '/'),\n });\n }\n const entry = new WorkflowSyncer().parseWindsurfWorkflow(input.sourceName, input.raw);\n const content = entry.content.trim() || '## Execute\\n\\nFollow the imported workflow.';\n const lenses = inferTaskLenses(entry.name + '\\n' + entry.description);\n const createdAt = now();\n const sourcePath = 'workflows/' + slug(entry.name) + '.md';\n const spec: WorkflowSpec = {\n id: 'workflow:' + hash(input.workspace.id + ':' + sourcePath).slice(0, 24),\n workspaceId: input.workspace.id,\n title: titleFromName(entry.name),\n description: entry.description || 'Imported from ' + input.sourcePath,\n status: 'active',\n version: 1,\n taskLenses: lenses,\n triggers: lenses,\n assumptions: [],\n requiredContext: [],\n guardrails: [],\n allowedTools: [],\n phases: phasesFromBody(content),\n verificationGates: [],\n claimIds: [],\n evidenceRefs: [],\n codeRefs: [],\n compatibleAgents: WORKFLOW_ADAPTER_TARGETS,\n body: content,\n sourcePath,\n sourceHash: '',\n contentHash: '',\n createdAt,\n updatedAt: createdAt,\n importedFrom: input.sourcePath.replace(/\\\\/g, '/'),\n };\n return materializeWorkflow(spec);\n}\n\n/**\n * Import legacy Windsurf workflows into canonical Markdown. The original\n * source is read only; existing canonical workflow files are not overwritten.\n */\nexport async function importWindsurfWorkflows(input: {\n workspace: KnowledgeWorkspace;\n projectRoot: string;\n}): Promise<{\n imported: WorkflowSpec[];\n skipped: Array<{ sourcePath: string; reason: string }>;\n}> {\n const sourceDirectory = path.join(path.resolve(input.projectRoot), '.windsurf', 'workflows');\n const paths = getKnowledgeWorkspacePaths(input.workspace);\n const imported: WorkflowSpec[] = [];\n const skipped: Array<{ sourcePath: string; reason: string }> = [];\n let entries: Array<import('node:fs').Dirent>;\n try {\n entries = await fs.readdir(sourceDirectory, { withFileTypes: true });\n } catch {\n return { imported, skipped };\n }\n for (const entry of entries.filter(item => item.isFile() && item.name.toLowerCase().endsWith('.md'))) {\n const originalPath = path.join(sourceDirectory, entry.name);\n const sourcePath = path.relative(path.resolve(input.projectRoot), originalPath).split(path.sep).join('/');\n try {\n const raw = await fs.readFile(originalPath, 'utf8');\n const workflow = importedWorkflowSpec({\n workspace: input.workspace,\n sourceName: entry.name,\n sourcePath,\n raw,\n });\n const targetPath = resolveKnowledgeWorkspaceFile(input.workspace, workflow.sourcePath);\n try {\n await fs.access(targetPath);\n skipped.push({ sourcePath, reason: 'canonical workflow already exists and was preserved' });\n continue;\n } catch {\n // The generated canonical path is available.\n }\n imported.push(await writeCanonicalWorkflow({ workspace: input.workspace, workflow }));\n } catch (error) {\n skipped.push({\n sourcePath,\n reason: error instanceof Error ? error.message : String(error),\n });\n }\n }\n await fs.mkdir(paths.workflows, { recursive: true });\n return { imported, skipped };\n}\n\nfunction isWithin(root: string, candidate: string): boolean {\n const relative = path.relative(root, candidate);\n return relative !== '' && relative !== '..' && !relative.startsWith('..' + path.sep) && !path.isAbsolute(relative);\n}\n\nfunction adapterRelativePath(workflow: WorkflowSpec, agent: WorkflowAdapterTarget): string {\n const name = 'memorix-workflow-' + slug(workflow.id.replace(/^workflow:/, ''));\n if (agent === 'codex') return '.agents/skills/' + name + '/SKILL.md';\n if (agent === 'claude-code') return '.claude/skills/' + name + '/SKILL.md';\n if (agent === 'cursor') return '.cursor/rules/' + name + '.mdc';\n return '.windsurf/workflows/' + name + '.md';\n}\n\nfunction adapterMarker(workflow: WorkflowSpec): string {\n return '<!-- memorix:workflow-adapter id=\"' + workflow.id + '\" -->';\n}\n\nfunction adapterContent(workflow: WorkflowSpec, agent: WorkflowAdapterTarget): string {\n const marker = adapterMarker(workflow);\n const firstPhase = workflow.phases[0];\n const gates = workflow.verificationGates.length\n ? workflow.verificationGates\n : firstPhase.verificationGates;\n if (agent === 'codex' || agent === 'claude-code') {\n return matter.stringify([\n marker,\n '',\n '# ' + workflow.title,\n '',\n workflow.description,\n '',\n '## Start',\n '',\n firstPhase.instructions || firstPhase.title,\n '',\n '## Verification',\n '',\n ...(gates.length ? gates.map(gate => '- ' + gate) : ['- Follow the project verification standards.']),\n '',\n '## Full workflow',\n '',\n workflow.body.trim(),\n '',\n ].join('\\n'), {\n name: 'memorix-workflow-' + slug(workflow.id.replace(/^workflow:/, '')),\n description: workflow.description || workflow.title,\n });\n }\n if (agent === 'cursor') {\n return matter.stringify([\n marker,\n '',\n '# ' + workflow.title,\n '',\n workflow.body.trim(),\n '',\n ].join('\\n'), {\n description: workflow.description || workflow.title,\n globs: '',\n alwaysApply: false,\n });\n }\n return matter.stringify([\n marker,\n '',\n '# ' + workflow.title,\n '',\n workflow.body.trim(),\n '',\n ].join('\\n'), {\n description: workflow.description || workflow.title,\n });\n}\n\nfunction isWorkflowAdapterTarget(agent: AgentTarget): agent is WorkflowAdapterTarget {\n return WORKFLOW_ADAPTER_TARGETS.includes(agent as WorkflowAdapterTarget);\n}\n\nexport async function previewWorkflowAdapter(input: {\n workflow: WorkflowSpec;\n projectRoot: string;\n agent: AgentTarget;\n}): Promise<WorkflowAdapterPreview> {\n if (!isWorkflowAdapterTarget(input.agent)) {\n return {\n agent: input.agent,\n workflowId: input.workflow.id,\n status: 'unsupported',\n reason: 'This agent has no safe native workflow adapter. Use Memorix Project Context instead.',\n };\n }\n if (\n input.workflow.compatibleAgents.length > 0\n && !input.workflow.compatibleAgents.includes(input.agent)\n ) {\n return {\n agent: input.agent,\n workflowId: input.workflow.id,\n status: 'unsupported',\n reason: 'The canonical workflow does not declare compatibility with this agent.',\n };\n }\n const projectRoot = path.resolve(input.projectRoot);\n const targetPath = path.resolve(projectRoot, adapterRelativePath(input.workflow, input.agent));\n if (!isWithin(projectRoot, targetPath)) {\n throw new Error('Workflow adapter target escapes the project root');\n }\n const content = adapterContent(input.workflow, input.agent);\n let existing: string | undefined;\n try {\n existing = await fs.readFile(targetPath, 'utf8');\n } catch (error) {\n const code = error && typeof error === 'object' && 'code' in error\n ? (error as { code?: string }).code\n : undefined;\n if (code !== 'ENOENT') throw error;\n }\n if (existing === undefined) {\n return { agent: input.agent, workflowId: input.workflow.id, targetPath, content, status: 'create', reason: 'No existing project adapter file.' };\n }\n if (existing === content) {\n return { agent: input.agent, workflowId: input.workflow.id, targetPath, content, status: 'unchanged', reason: 'Existing Memorix adapter already matches the canonical workflow.' };\n }\n if (existing.includes(adapterMarker(input.workflow))) {\n return { agent: input.agent, workflowId: input.workflow.id, targetPath, content, status: 'update', reason: 'Existing Memorix-owned adapter will be updated.' };\n }\n return { agent: input.agent, workflowId: input.workflow.id, targetPath, content, status: 'conflict', reason: 'A user-owned project file already occupies this adapter path.' };\n}\n\nexport async function applyWorkflowAdapter(input: {\n workflow: WorkflowSpec;\n projectRoot: string;\n agent: AgentTarget;\n}): Promise<WorkflowAdapterPreview> {\n const initial = await previewWorkflowAdapter(input);\n if (initial.status === 'unsupported' || initial.status === 'conflict' || initial.status === 'unchanged') {\n return initial;\n }\n const projectRoot = path.resolve(input.projectRoot);\n return withFileLock(projectRoot, async () => {\n const current = await previewWorkflowAdapter(input);\n if (current.status !== 'create' && current.status !== 'update') return current;\n await fs.mkdir(path.dirname(current.targetPath!), { recursive: true });\n await atomicWriteFile(current.targetPath!, current.content!);\n return current;\n });\n}\n\nexport async function recordWorkflowRun(input: {\n workspace: KnowledgeWorkspace;\n run: WorkflowRunInput;\n}): Promise<WorkflowRun> {\n const store = await storeFor(input.workspace);\n const workflow = store.getWorkflow(input.run.workflowId);\n if (!workflow || workflow.workspaceId !== input.workspace.id) {\n throw new Error('Workflow was not found for this workspace');\n }\n if (!input.run.task.trim()) throw new Error('Workflow run task is required');\n return store.recordRun(input.run);\n}\n\nexport async function selectWorkspaceWorkflows(input: {\n workspace: KnowledgeWorkspace;\n task: string;\n limit?: number;\n}): Promise<{ selections: WorkflowSelection[]; errors: Array<{ sourcePath: string; message: string }> }> {\n const synced = await syncCanonicalWorkflows(input.workspace);\n const store = await storeFor(input.workspace);\n return {\n selections: selectWorkflows({\n workflows: synced.workflows,\n task: input.task,\n projectId: input.workspace.projectId,\n store,\n limit: input.limit,\n }),\n errors: synced.errors,\n };\n}\n","import { closeAllDatabases } from '../store/sqlite-db.js';\nimport { loadDotenv } from '../config/dotenv-loader.js';\nimport { initProjectRoot } from '../config/yaml-loader.js';\nimport { initLLM } from '../llm/provider.js';\nimport { initObservationStore } from '../store/obs-store.js';\nimport { initObservations } from '../memory/observations.js';\nimport {\n MAINTENANCE_JOB_KINDS,\n type MaintenanceJob,\n type MaintenanceJobRunResult,\n} from './maintenance-jobs.js';\nimport {\n ISOLATED_MAINTENANCE_JOB_KINDS,\n MAINTENANCE_RESULT_PREFIX,\n type IsolatedMaintenanceRequest,\n} from './isolated-maintenance.js';\nimport { createProjectMaintenanceHandler } from './project-maintenance.js';\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return Boolean(value) && typeof value === 'object' && !Array.isArray(value);\n}\n\nfunction isJob(value: unknown): value is MaintenanceJob {\n if (!isRecord(value)) return false;\n return typeof value.id === 'string'\n && typeof value.projectId === 'string'\n && typeof value.kind === 'string'\n && MAINTENANCE_JOB_KINDS.includes(value.kind as MaintenanceJob['kind'])\n && ISOLATED_MAINTENANCE_JOB_KINDS.includes(value.kind as MaintenanceJob['kind'])\n && isRecord(value.payload);\n}\n\nexport function parseMaintenanceRequest(raw: string): IsolatedMaintenanceRequest {\n let value: unknown;\n try {\n value = JSON.parse(raw);\n } catch {\n throw new Error('Maintenance runner received invalid JSON input');\n }\n if (!isRecord(value) || !isJob(value.job)) {\n throw new Error('Maintenance runner received an invalid job payload');\n }\n if (typeof value.projectRoot !== 'string' || !value.projectRoot) {\n throw new Error('Maintenance runner requires projectRoot');\n }\n if (typeof value.dataDir !== 'string' || !value.dataDir) {\n throw new Error('Maintenance runner requires dataDir');\n }\n return {\n job: value.job,\n projectRoot: value.projectRoot,\n dataDir: value.dataDir,\n };\n}\n\nexport async function executeMaintenanceRequest(\n request: IsolatedMaintenanceRequest,\n): Promise<MaintenanceJobRunResult> {\n initProjectRoot(request.projectRoot);\n loadDotenv(request.projectRoot);\n await initObservationStore(request.dataDir);\n await initObservations(request.dataDir);\n if (request.job.kind === 'consolidation') initLLM();\n\n const handler = createProjectMaintenanceHandler(\n request.job.projectId,\n request.dataDir,\n request.projectRoot,\n );\n return (await handler(request.job)) ?? { action: 'complete' };\n}\n\nfunction readStdin(): Promise<string> {\n return new Promise((resolve, reject) => {\n let raw = '';\n process.stdin.setEncoding('utf8');\n process.stdin.on('data', (chunk) => { raw += chunk; });\n process.stdin.once('error', reject);\n process.stdin.once('end', () => resolve(raw));\n });\n}\n\nexport async function main(): Promise<void> {\n try {\n const request = parseMaintenanceRequest(await readStdin());\n const result = await executeMaintenanceRequest(request);\n process.stdout.write(`${MAINTENANCE_RESULT_PREFIX}${JSON.stringify(result)}\\n`);\n } catch (error) {\n process.stderr.write(`[memorix] maintenance runner failed: ${error instanceof Error ? error.message : String(error)}\\n`);\n process.exitCode = 1;\n } finally {\n closeAllDatabases();\n }\n}\n\nif (process.argv[1] && process.argv[1].endsWith('maintenance-runner.js')) {\n void main();\n}\n","import { spawn, type ChildProcessWithoutNullStreams } from 'node:child_process';\nimport { existsSync } from 'node:fs';\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport type { MaintenanceJob, MaintenanceJobKind, MaintenanceJobRunResult } from './maintenance-jobs.js';\nimport { sanitizeCredentials } from '../memory/secret-filter.js';\n\nexport const MAINTENANCE_RESULT_PREFIX = '__MEMORIX_MAINTENANCE_RESULT__';\n\nexport const ISOLATED_MAINTENANCE_JOB_KINDS: readonly MaintenanceJobKind[] = [\n 'retention-archive',\n 'consolidation',\n 'codegraph-refresh',\n 'observation-qualify',\n 'claim-derive',\n 'claim-requalification',\n 'knowledge-compile',\n 'knowledge-lint',\n 'workflow-index',\n];\nconst DEFAULT_TIMEOUT_MS = 5 * 60_000;\nconst MAX_CHILD_OUTPUT_BYTES = 1_000_000;\n\nexport interface IsolatedMaintenanceRequest {\n job: MaintenanceJob;\n projectRoot: string;\n dataDir: string;\n}\n\nexport interface IsolatedMaintenanceOptions {\n runnerPath?: string;\n timeoutMs?: number;\n env?: NodeJS.ProcessEnv;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return Boolean(value) && typeof value === 'object' && !Array.isArray(value);\n}\n\nfunction isMaintenanceResult(value: unknown): value is MaintenanceJobRunResult {\n if (!isRecord(value)) return false;\n if (value.action === 'complete') return true;\n return value.action === 'reschedule' && typeof value.delayMs === 'number';\n}\n\nfunction childError(prefix: string, detail: string): Error {\n const cleaned = sanitizeCredentials(detail.trim()).slice(0, 4_000);\n return new Error(cleaned ? `${prefix}: ${cleaned}` : prefix);\n}\n\n/**\n * Resolve the runner beside the compiled package entry. The CLI bundle lives\n * in dist/cli while the library entry lives directly in dist.\n */\nexport function resolveMaintenanceRunnerPath(moduleUrl = import.meta.url): string {\n const moduleDir = path.dirname(fileURLToPath(moduleUrl));\n const distDir = path.basename(moduleDir) === 'cli'\n ? path.dirname(moduleDir)\n : path.basename(moduleDir) === 'runtime' && path.basename(path.dirname(moduleDir)) === 'src'\n ? path.join(path.dirname(path.dirname(moduleDir)), 'dist')\n : moduleDir;\n return path.join(distDir, 'maintenance-runner.js');\n}\n\nexport function parseMaintenanceRunnerOutput(output: string): MaintenanceJobRunResult {\n const line = output\n .split(/\\r?\\n/)\n .reverse()\n .find((candidate) => candidate.startsWith(MAINTENANCE_RESULT_PREFIX));\n if (!line) {\n throw childError('Maintenance runner did not return a result', output);\n }\n\n try {\n const parsed = JSON.parse(line.slice(MAINTENANCE_RESULT_PREFIX.length));\n if (!isMaintenanceResult(parsed)) {\n throw new Error('result shape is invalid');\n }\n return parsed;\n } catch (error) {\n throw childError(\n 'Maintenance runner returned an invalid result',\n error instanceof Error ? error.message : String(error),\n );\n }\n}\n\nfunction validateRequest(request: IsolatedMaintenanceRequest): void {\n if (!ISOLATED_MAINTENANCE_JOB_KINDS.includes(request.job.kind)) {\n throw new Error(`Maintenance job ${request.job.kind} cannot run in an isolated worker`);\n }\n if (!path.isAbsolute(request.projectRoot)) {\n throw new Error('Maintenance runner requires an absolute project root');\n }\n if (!path.isAbsolute(request.dataDir)) {\n throw new Error('Maintenance runner requires an absolute data directory');\n }\n}\n\nfunction collectOutput(\n stream: NodeJS.ReadableStream,\n limit: number,\n onOverflow: () => void,\n): Promise<string> {\n return new Promise((resolve, reject) => {\n let value = '';\n let size = 0;\n stream.setEncoding('utf8');\n stream.on('data', (chunk: string) => {\n size += Buffer.byteLength(chunk);\n if (size > limit) {\n onOverflow();\n reject(new Error('maintenance runner output exceeded its safety limit'));\n return;\n }\n value += chunk;\n });\n stream.on('error', reject);\n stream.on('end', () => resolve(value));\n });\n}\n\n/**\n * Runs CPU/disk-heavy maintenance out of the MCP process. The parent keeps\n * the durable queue lease; the child gets only one job and returns one result.\n */\nexport async function runMaintenanceInChildProcess(\n request: IsolatedMaintenanceRequest,\n options: IsolatedMaintenanceOptions = {},\n): Promise<MaintenanceJobRunResult> {\n validateRequest(request);\n const runnerPath = options.runnerPath ?? resolveMaintenanceRunnerPath();\n if (!existsSync(runnerPath)) {\n throw new Error(`Maintenance runner is unavailable at ${runnerPath}. Reinstall or rebuild Memorix.`);\n }\n\n const timeoutMs = Number.isFinite(options.timeoutMs)\n ? Math.max(1_000, Math.floor(options.timeoutMs!))\n : DEFAULT_TIMEOUT_MS;\n const env = { ...process.env, ...options.env };\n\n return new Promise<MaintenanceJobRunResult>((resolve, reject) => {\n let settled = false;\n let child: ChildProcessWithoutNullStreams;\n try {\n child = spawn(process.execPath, [runnerPath], {\n cwd: request.projectRoot,\n env,\n stdio: ['pipe', 'pipe', 'pipe'],\n windowsHide: true,\n });\n } catch (error) {\n reject(error);\n return;\n }\n\n const settle = (fn: () => void): void => {\n if (settled) return;\n settled = true;\n clearTimeout(timeout);\n fn();\n };\n const terminateForOutput = (): void => {\n child.kill();\n };\n const stdout = collectOutput(child.stdout, MAX_CHILD_OUTPUT_BYTES, terminateForOutput);\n const stderr = collectOutput(child.stderr, MAX_CHILD_OUTPUT_BYTES, terminateForOutput);\n const timeout = setTimeout(() => {\n child.kill();\n settle(() => reject(new Error(`Maintenance runner timed out after ${timeoutMs}ms`)));\n }, timeoutMs);\n\n child.once('error', (error) => settle(() => reject(error)));\n child.once('close', async (code, signal) => {\n try {\n const [out, err] = await Promise.all([stdout, stderr]);\n if (code !== 0) {\n settle(() => reject(childError(\n `Maintenance runner exited with ${signal ? `signal ${signal}` : `code ${code ?? 'unknown'}`}`,\n err || out,\n )));\n return;\n }\n settle(() => resolve(parseMaintenanceRunnerOutput(out)));\n } catch (error) {\n settle(() => reject(error));\n }\n });\n\n child.stdin.end(JSON.stringify(request));\n });\n}\n","import type {\n MaintenanceJobHandler,\n MaintenanceJobRunResult,\n} from './maintenance-jobs.js';\nimport { runMaintenanceInChildProcess } from './isolated-maintenance.js';\nimport {\n enqueueClaimRequalification,\n enqueueKnowledgeFollowups,\n enqueueObservationQualification,\n type MaintenanceQueue,\n} from './lifecycle.js';\n\nconst DEFAULT_VECTOR_BATCH_SIZE = 12;\nconst DEFAULT_RETENTION_BATCH_SIZE = 100;\nconst DEFAULT_CONSOLIDATION_BATCH_SIZE = 200;\nconst DEFAULT_CODEGRAPH_MAX_FILES = 5_000;\nconst DEFAULT_CLAIM_DERIVATION_BATCH_SIZE = 100;\nconst DEFAULT_OBSERVATION_QUALIFICATION_BATCH_SIZE = 100;\nconst VECTOR_RETRY_DELAY_MS = 5_000;\nconst DEDUP_PER_PAIR_TIMEOUT_MS = 5_000;\n\nfunction vectorBatchSize(payload: Record<string, unknown>): number {\n const value = payload.limit;\n if (typeof value !== 'number' || !Number.isFinite(value)) return DEFAULT_VECTOR_BATCH_SIZE;\n return Math.min(100, Math.max(1, Math.floor(value)));\n}\n\nfunction retentionBatchSize(payload: Record<string, unknown>): number {\n const value = payload.limit;\n if (typeof value !== 'number' || !Number.isFinite(value)) return DEFAULT_RETENTION_BATCH_SIZE;\n return Math.min(500, Math.max(1, Math.floor(value)));\n}\n\nfunction retentionCursor(payload: Record<string, unknown>): number {\n const value = payload.cursor;\n return typeof value === 'number' && Number.isFinite(value)\n ? Math.max(0, Math.floor(value))\n : 0;\n}\n\nfunction consolidationBatchSize(payload: Record<string, unknown>): number {\n const value = payload.limit;\n if (typeof value !== 'number' || !Number.isFinite(value)) return DEFAULT_CONSOLIDATION_BATCH_SIZE;\n return Math.min(500, Math.max(1, Math.floor(value)));\n}\n\nfunction consolidationCursor(payload: Record<string, unknown>): number {\n const value = payload.cursor;\n return typeof value === 'number' && Number.isFinite(value)\n ? Math.max(0, Math.floor(value))\n : 0;\n}\n\nfunction codeGraphMaxFiles(payload: Record<string, unknown>): number {\n const value = payload.maxFiles;\n if (typeof value !== 'number' || !Number.isFinite(value)) return DEFAULT_CODEGRAPH_MAX_FILES;\n return Math.min(20_000, Math.max(1, Math.floor(value)));\n}\n\nfunction claimDerivationBatchSize(payload: Record<string, unknown>): number {\n const value = payload.limit;\n if (typeof value !== 'number' || !Number.isFinite(value)) return DEFAULT_CLAIM_DERIVATION_BATCH_SIZE;\n return Math.min(500, Math.max(1, Math.floor(value)));\n}\n\nfunction claimDerivationCursor(payload: Record<string, unknown>): number {\n const value = payload.cursor;\n return typeof value === 'number' && Number.isFinite(value)\n ? Math.max(0, Math.floor(value))\n : 0;\n}\n\nfunction observationQualificationBatchSize(payload: Record<string, unknown>): number {\n const value = payload.limit;\n if (typeof value !== 'number' || !Number.isFinite(value)) return DEFAULT_OBSERVATION_QUALIFICATION_BATCH_SIZE;\n return Math.min(500, Math.max(1, Math.floor(value)));\n}\n\nfunction observationQualificationCursor(payload: Record<string, unknown>): number {\n const value = payload.cursor;\n return typeof value === 'number' && Number.isFinite(value)\n ? Math.max(0, Math.floor(value))\n : 0;\n}\n\nfunction observationId(payload: Record<string, unknown>): number | undefined {\n const value = payload.observationId;\n return typeof value === 'number' && Number.isSafeInteger(value) && value > 0\n ? value\n : undefined;\n}\n\nfunction workspaceMode(payload: Record<string, unknown>): 'local' | 'versioned' | undefined {\n return payload.workspaceMode === 'local' || payload.workspaceMode === 'versioned'\n ? payload.workspaceMode\n : undefined;\n}\n\nasync function loadWorkspaceForMaintenance(\n projectId: string,\n projectDir: string,\n mode?: 'local' | 'versioned',\n) {\n const { loadKnowledgeWorkspace } = await import('../knowledge/workspace.js');\n if (mode) return loadKnowledgeWorkspace({ projectId, dataDir: projectDir, mode });\n const [versioned, local] = await Promise.all([\n loadKnowledgeWorkspace({ projectId, dataDir: projectDir, mode: 'versioned' }),\n loadKnowledgeWorkspace({ projectId, dataDir: projectDir, mode: 'local' }),\n ]);\n return versioned ?? local;\n}\n\n/**\n * Creates handlers for one initialized project runtime. The worker itself is\n * project-scoped so it never claims a different project's queued work.\n */\nfunction withTimeout<T>(promise: Promise<T>, ms: number, label: string): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n const timer = setTimeout(() => reject(new Error(`${label} timed out after ${ms}ms`)), ms);\n promise.then(\n (value) => { clearTimeout(timer); resolve(value); },\n (error) => { clearTimeout(timer); reject(error); },\n );\n });\n}\n\nasync function runAutomaticConsolidation(\n projectId: string,\n projectDir: string,\n options: { afterId: number; limit: number },\n): Promise<{ nextCursor?: number }> {\n const { isLLMEnabled } = await import('../llm/provider.js');\n if (!isLLMEnabled()) {\n const { executeConsolidation } = await import('../memory/consolidation.js');\n const result = await executeConsolidation(projectDir, projectId, {\n threshold: 0.55,\n afterId: options.afterId,\n limit: options.limit,\n });\n return result.nextCursor === undefined ? {} : { nextCursor: result.nextCursor };\n }\n\n const [{ getObservationStore }, { deduplicateMemory }] = await Promise.all([\n import('../store/obs-store.js'),\n import('../llm/memory-manager.js'),\n ]);\n const store = getObservationStore();\n const page = await store.loadByProject(projectId, {\n status: 'active',\n afterId: options.afterId,\n limit: options.limit + 1,\n });\n const hasMore = page.length > options.limit;\n const allObservations = hasMore ? page.slice(0, options.limit) : page;\n const nextCursor = hasMore && allObservations.length > 0\n ? allObservations[allObservations.length - 1].id\n : undefined;\n if (allObservations.length <= 10) {\n return nextCursor === undefined ? {} : { nextCursor };\n }\n\n const grouped = new Map<string, typeof allObservations>();\n for (const observation of allObservations) {\n const key = `${observation.entityName}::${observation.type}`;\n const group = grouped.get(key) ?? [];\n group.push(observation);\n grouped.set(key, group);\n }\n\n const toResolve: number[] = [];\n const maxDedupCalls = 15;\n let dedupCalls = 0;\n for (const group of grouped.values()) {\n if (group.length < 2 || dedupCalls >= maxDedupCalls) continue;\n group.sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime());\n for (let index = 0; index < group.length - 1 && index < 3 && dedupCalls < maxDedupCalls; index++) {\n try {\n dedupCalls++;\n const older = group[index];\n const newer = group[index + 1];\n const decision = await withTimeout(\n deduplicateMemory(\n { title: newer.title, narrative: newer.narrative, facts: newer.facts },\n [{ id: older.id, title: older.title, narrative: older.narrative, facts: older.facts.join('\\n') }],\n ),\n DEDUP_PER_PAIR_TIMEOUT_MS,\n `Dedup pair #${older.id}<->#${newer.id}`,\n );\n if (decision && (decision.action === 'UPDATE' || decision.action === 'NONE')) {\n toResolve.push(decision.action === 'UPDATE' ? older.id : newer.id);\n } else if (decision?.action === 'DELETE' && decision.targetId) {\n toResolve.push(decision.targetId);\n }\n } catch {\n // One slow or malformed LLM decision must not abandon the maintenance job.\n }\n }\n }\n if (toResolve.length > 0) {\n await store.atomic(async (tx) => {\n await Promise.all(\n [...new Set(toResolve)].map((id) => tx.setStatus(id, 'resolved', 'active')),\n );\n });\n }\n return nextCursor === undefined ? {} : { nextCursor };\n}\n\nexport function createProjectMaintenanceHandler(\n projectId: string,\n projectDir: string,\n projectRoot?: string,\n options: { maintenanceQueue?: MaintenanceQueue } = {},\n): MaintenanceJobHandler {\n return async (job): Promise<MaintenanceJobRunResult> => {\n if (job.projectId !== projectId) {\n return { action: 'reschedule', delayMs: VECTOR_RETRY_DELAY_MS };\n }\n\n if (job.kind === 'retention-archive') {\n const { archiveExpiredBatch } = await import('../memory/retention.js');\n const limit = retentionBatchSize(job.payload);\n const result = await archiveExpiredBatch(projectDir, {\n projectId,\n afterId: retentionCursor(job.payload),\n limit,\n });\n if (result.nextCursor !== undefined) {\n return {\n action: 'reschedule',\n delayMs: 0,\n resetAttempts: true,\n payload: { cursor: result.nextCursor, limit },\n };\n }\n return { action: 'complete' };\n }\n\n if (job.kind === 'consolidation') {\n const limit = consolidationBatchSize(job.payload);\n const result = await runAutomaticConsolidation(projectId, projectDir, {\n afterId: consolidationCursor(job.payload),\n limit,\n });\n if (result.nextCursor !== undefined) {\n return {\n action: 'reschedule',\n delayMs: 0,\n resetAttempts: true,\n payload: { cursor: result.nextCursor, limit },\n };\n }\n return { action: 'complete' };\n }\n\n if (job.kind === 'codegraph-refresh') {\n if (!projectRoot) {\n throw new Error(`CodeGraph refresh requires a project root for ${projectId}`);\n }\n const [\n { CodeGraphStore },\n { refreshProjectLite },\n { backfillMissingObservationCodeRefs },\n { getObservationStore },\n { getResolvedConfig },\n ] = await Promise.all([\n import('../codegraph/store.js'),\n import('../codegraph/lite-provider.js'),\n import('../codegraph/binder.js'),\n import('../store/obs-store.js'),\n import('../config/resolved-config.js'),\n ]);\n const store = new CodeGraphStore();\n await store.init(projectDir);\n const codegraphConfig = getResolvedConfig({ projectRoot }).codegraph;\n await refreshProjectLite(store, {\n projectId,\n projectRoot,\n exclude: codegraphConfig.excludePatterns,\n maxFiles: codeGraphMaxFiles(job.payload),\n maxFileBytes: codegraphConfig.maxFileBytes,\n });\n const activeObservations = await getObservationStore().loadByProject(projectId, { status: 'active' });\n await backfillMissingObservationCodeRefs(store, activeObservations);\n const snapshot = store.latestSnapshot(projectId);\n enqueueClaimRequalification({\n projectId,\n dataDir: projectDir,\n source: 'codegraph-refresh',\n ...(snapshot?.id ? { snapshotId: snapshot.id } : {}),\n ...(options.maintenanceQueue ? { queue: options.maintenanceQueue } : {}),\n });\n enqueueObservationQualification({\n projectId,\n dataDir: projectDir,\n source: 'codegraph-refresh',\n ...(options.maintenanceQueue ? { queue: options.maintenanceQueue } : {}),\n });\n return { action: 'complete' };\n }\n\n if (job.kind === 'observation-qualify') {\n const [\n { CodeGraphStore },\n { bindObservationToCode },\n { getObservationStore },\n { qualifyCandidateFromCurrentCode },\n { updateObservationAdmission },\n ] = await Promise.all([\n import('../codegraph/store.js'),\n import('../codegraph/binder.js'),\n import('../store/obs-store.js'),\n import('../memory/admission.js'),\n import('../memory/observations.js'),\n ]);\n const codeStore = new CodeGraphStore();\n await codeStore.init(projectDir);\n const limit = observationQualificationBatchSize(job.payload);\n const page = await getObservationStore().loadByProject(projectId, {\n status: 'active',\n afterId: observationQualificationCursor(job.payload),\n limit: limit + 1,\n });\n const hasMore = page.length > limit;\n const observations = hasMore ? page.slice(0, limit) : page;\n const indexedAtMs = Date.parse(codeStore.status(projectId).indexedAt ?? '');\n\n for (const observation of observations) {\n if (observation.admissionState !== 'candidate') continue;\n // A candidate may only earn delivery after a Code Memory scan that\n // happened at or after it was captured. A stale snapshot is evidence\n // about an earlier project state, not a reason to inject this record.\n if (!Number.isFinite(indexedAtMs) || indexedAtMs < Date.parse(observation.createdAt)) continue;\n await bindObservationToCode(codeStore, observation);\n const currentCodeReferenceCount = codeStore\n .listObservationRefs(projectId, observation.id)\n .filter((reference) => reference.status === 'current')\n .length;\n const qualification = qualifyCandidateFromCurrentCode({\n observation,\n currentCodeReferenceCount,\n });\n if (!qualification) continue;\n await updateObservationAdmission({\n observationId: observation.id,\n projectId,\n expectedState: 'candidate',\n // Automatic capture earns project visibility only after a current\n // Code Memory link exists. Explicit/private records retain scope.\n ...(observation.sourceDetail === 'hook' ? { visibility: 'project' as const } : {}),\n ...qualification,\n });\n }\n\n if (hasMore && observations.length > 0) {\n return {\n action: 'reschedule',\n delayMs: 0,\n resetAttempts: true,\n payload: {\n ...job.payload,\n cursor: observations[observations.length - 1].id,\n limit,\n },\n };\n }\n return { action: 'complete' };\n }\n\n if (job.kind === 'claim-derive') {\n const id = observationId(job.payload);\n if (!id) throw new Error('Claim derivation requires a positive observationId');\n const [\n { CodeGraphStore },\n { ClaimStore },\n { bindObservationToCode },\n { deriveLowRiskClaimsFromObservation },\n { getObservationStore },\n ] = await Promise.all([\n import('../codegraph/store.js'),\n import('../knowledge/claim-store.js'),\n import('../codegraph/binder.js'),\n import('../knowledge/claims.js'),\n import('../store/obs-store.js'),\n ]);\n const observation = await getObservationStore().getById(id);\n if (!observation || observation.projectId !== projectId) return { action: 'complete' };\n const codeStore = new CodeGraphStore();\n const claimStore = new ClaimStore();\n await Promise.all([codeStore.init(projectDir), claimStore.init(projectDir)]);\n await bindObservationToCode(codeStore, observation);\n const derived = deriveLowRiskClaimsFromObservation(claimStore, observation, codeStore);\n if (derived.length > 0) {\n enqueueKnowledgeFollowups({\n projectId,\n dataDir: projectDir,\n source: 'claim-derive:' + id,\n includeCompile: true,\n ...(options.maintenanceQueue ? { queue: options.maintenanceQueue } : {}),\n });\n }\n return { action: 'complete' };\n }\n\n if (job.kind === 'claim-requalification') {\n const [\n { CodeGraphStore },\n { ClaimStore },\n { bindObservationToCode },\n { deriveLowRiskClaimsFromObservation, requalifyClaimsForCodeState },\n { getObservationStore },\n ] = await Promise.all([\n import('../codegraph/store.js'),\n import('../knowledge/claim-store.js'),\n import('../codegraph/binder.js'),\n import('../knowledge/claims.js'),\n import('../store/obs-store.js'),\n ]);\n const codeStore = new CodeGraphStore();\n const claimStore = new ClaimStore();\n await Promise.all([codeStore.init(projectDir), claimStore.init(projectDir)]);\n const limit = claimDerivationBatchSize(job.payload);\n const observations = await getObservationStore().loadByProject(projectId, {\n status: 'active',\n afterId: claimDerivationCursor(job.payload),\n limit,\n });\n let derivedCount = 0;\n for (const observation of observations) {\n await bindObservationToCode(codeStore, observation);\n derivedCount += deriveLowRiskClaimsFromObservation(claimStore, observation, codeStore).length;\n }\n requalifyClaimsForCodeState(claimStore, codeStore, projectId);\n if (observations.length === limit) {\n return {\n action: 'reschedule',\n delayMs: 0,\n resetAttempts: true,\n payload: {\n ...job.payload,\n cursor: observations[observations.length - 1].id,\n limit,\n },\n };\n }\n enqueueKnowledgeFollowups({\n projectId,\n dataDir: projectDir,\n source: 'claim-requalification',\n includeCompile: derivedCount > 0,\n ...(options.maintenanceQueue ? { queue: options.maintenanceQueue } : {}),\n });\n return { action: 'complete' };\n }\n\n if (job.kind === 'knowledge-compile') {\n const workspace = await loadWorkspaceForMaintenance(projectId, projectDir, workspaceMode(job.payload));\n if (!workspace) return { action: 'complete' };\n if (workspace.mode === 'versioned' && job.payload.allowVersionedWrite !== true) {\n return { action: 'complete' };\n }\n const [{ ClaimStore }, { compileKnowledgeWorkspace }] = await Promise.all([\n import('../knowledge/claim-store.js'),\n import('../knowledge/wiki.js'),\n ]);\n const claims = new ClaimStore();\n await claims.init(projectDir);\n await compileKnowledgeWorkspace({ workspace, claims });\n enqueueKnowledgeFollowups({\n projectId,\n dataDir: projectDir,\n source: 'knowledge-compile',\n ...(options.maintenanceQueue ? { queue: options.maintenanceQueue } : {}),\n });\n return { action: 'complete' };\n }\n\n if (job.kind === 'workflow-index') {\n const workspace = await loadWorkspaceForMaintenance(projectId, projectDir, workspaceMode(job.payload));\n if (!workspace) return { action: 'complete' };\n const { syncCanonicalWorkflows } = await import('../knowledge/workflows.js');\n await syncCanonicalWorkflows(workspace);\n return { action: 'complete' };\n }\n\n if (job.kind === 'knowledge-lint') {\n const workspace = await loadWorkspaceForMaintenance(projectId, projectDir, workspaceMode(job.payload));\n if (!workspace) return { action: 'complete' };\n const [\n { ClaimStore },\n { CodeGraphStore },\n { lintKnowledgeWorkspace },\n ] = await Promise.all([\n import('../knowledge/claim-store.js'),\n import('../codegraph/store.js'),\n import('../knowledge/wiki.js'),\n ]);\n const claims = new ClaimStore();\n const codeStore = new CodeGraphStore();\n await Promise.all([claims.init(projectDir), codeStore.init(projectDir)]);\n await lintKnowledgeWorkspace({ workspace, claims, codeStore });\n return { action: 'complete' };\n }\n\n if (job.kind !== 'vector-backfill') {\n throw new Error(`No runtime handler is registered for maintenance job: ${job.kind}`);\n }\n\n const { isEmbeddingExplicitlyDisabled } = await import('../embedding/provider.js');\n if (isEmbeddingExplicitlyDisabled()) return { action: 'complete' };\n\n const { backfillVectorEmbeddings, getVectorStatus } = await import('../memory/observations.js');\n const before = getVectorStatus(projectId);\n if (before.missing === 0) return { action: 'complete' };\n\n const result = await backfillVectorEmbeddings({\n projectId,\n limit: vectorBatchSize(job.payload),\n });\n const after = getVectorStatus(projectId);\n if (after.missing === 0) return { action: 'complete' };\n\n if (result.failed > 0 && result.succeeded === 0) {\n throw new Error(`vector backfill made no progress (${result.failed}/${result.attempted} failed)`);\n }\n\n return {\n action: 'reschedule',\n delayMs: result.attempted === 0 ? VECTOR_RETRY_DELAY_MS : 0,\n resetAttempts: result.succeeded > 0,\n };\n };\n}\n\n/**\n * Keep vector writes with the active in-memory search index. Everything that\n * can scan disk or consolidate a large corpus runs in a separate process so\n * an MCP request never shares its event loop with maintenance work.\n */\nexport function createProjectMaintenanceDispatcher(\n projectId: string,\n projectDir: string,\n projectRoot: string,\n isolatedRunner: typeof runMaintenanceInChildProcess = runMaintenanceInChildProcess,\n): MaintenanceJobHandler {\n const inProcessHandler = createProjectMaintenanceHandler(projectId, projectDir, projectRoot);\n return async (job): Promise<MaintenanceJobRunResult> => {\n if (job.kind === 'vector-backfill') {\n return (await inProcessHandler(job)) ?? { action: 'complete' };\n }\n return isolatedRunner({ job, projectRoot, dataDir: projectDir });\n };\n}\n"],"mappings":"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","names":["db","path","path","db","existsSync","readFileSync","homedir","createRequire","require","matter","existsSync","readFileSync","path","id","name","existsSync","readFileSync","homedir","existsSync","readFileSync","homedir","configCache","path","homedir","existsSync","provider","provider","path","fs","nextId","count","observations","result","SqliteBackend","store","fs","path","projectDir","path","fs","_store","join","homedir","hash","cache","MAX_CACHE_SIZE","createHash","readFile","writeFile","mkdir","join","homedir","textHash","loadDiskCache","CACHE_FILE","cache","CACHE_DIR","diskCacheDirty","hash","MAX_CACHE_SIZE","MAX_RETRIES","errorText","embedding","provider_exports","now","getEmbeddingMode","getEmbeddingApiKey","getEmbeddingBaseUrl","getEmbeddingModel","FastEmbedProvider","TransformersProvider","APIEmbeddingProvider","init_provider","fs","path","HIGH_VALUE_TYPES","getDb","insert","remove","observationId","COMMAND_LIKE_QUERY","provider","initPromise","observations","now","resolveAliases","rerankResults","withFreshIndex","getAllObservations","init_provider","randomUUID","now","updated","createHash","path","observationId","randomUUID","writeFile","observationId","path","path","observations","getObservationCount","now","MaintenanceJobStore","CodeGraphStore","bindObservationToCode","removeObservation","slug","provider","count","init_provider","randomUUID","now","workspaceId","remove","insert","createHash","fs","path","relative","observations","raw","now","projectDir","execFile","createHash","promisify","execFileAsync","count","path","normalizeCodePath","createHash","readdirSync","readFileSync","statSync","join","path","id","createHash","randomUUID","optionalText","createHash","randomUUID","now","createHash","fs","path","createHash","fs","path","hash","slug","relative","matter","randomUUID","optionalText","workspaceId","createHash","fs","path","matter","hash","now","optionalText","storeFor","markdownFiles","sourcePath","isWithin","relative","existsSync","path","fileURLToPath","projectDir","loadKnowledgeWorkspace","isLLMEnabled","executeConsolidation","getObservationStore","deduplicateMemory","archiveExpiredBatch","result","CodeGraphStore","refreshProjectLite","backfillMissingObservationCodeRefs","getResolvedConfig","bindObservationToCode","qualifyCandidateFromCurrentCode","updateObservationAdmission","observations","ClaimStore","deriveLowRiskClaimsFromObservation","requalifyClaimsForCodeState","compileKnowledgeWorkspace","syncCanonicalWorkflows","lintKnowledgeWorkspace","isEmbeddingExplicitlyDisabled","backfillVectorEmbeddings","getVectorStatus"]}
1
+ {"version":3,"sources":["../node_modules/tsup/assets/esm_shims.js","../src/store/bun-sqlite-compat.ts","../src/store/sqlite-db.ts","../src/config/config-paths.ts","../src/config/dotenv-loader.ts","../src/config/yaml-loader.ts","../src/project/detector.ts","../src/config/legacy-loader.ts","../src/config/toml-loader.ts","../src/config/resolved-config.ts","../src/config.ts","../src/llm/provider.ts","../src/store/sqlite-store.ts","../src/store/obs-store.ts","../src/types.ts","../src/store/file-lock.ts","../src/store/mini-skill-store.ts","../src/compact/token-budget.ts","../src/skills/mini-skills.ts","../src/memory/visibility.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/search/query-expansion.ts","../src/timeout.ts","../src/project/aliases.ts","../src/llm/quality.ts","../src/memory/freshness.ts","../src/store/orama-store.ts","../src/memory/entity-extractor.ts","../src/memory/secret-filter.ts","../src/runtime/maintenance-jobs.ts","../src/runtime/lifecycle.ts","../src/codegraph/ids.ts","../src/codegraph/store.ts","../src/codegraph/binder.ts","../src/memory/observations.ts","../src/knowledge/workspace-store.ts","../src/knowledge/workspace.ts","../src/memory/admission.ts","../src/memory/consolidation.ts","../src/llm/memory-manager.ts","../src/memory/retention.ts","../src/codegraph/code-state.ts","../src/codegraph/exclude.ts","../src/codegraph/lite-provider.ts","../src/knowledge/claim-store.ts","../src/knowledge/claims.ts","../src/knowledge/markdown.ts","../src/knowledge/wiki.ts","../src/workspace/workflow-sync.ts","../src/knowledge/workflow-store.ts","../src/codegraph/task-lens.ts","../src/knowledge/workflows.ts","../src/runtime/maintenance-runner.ts","../src/runtime/isolated-maintenance.ts","../src/runtime/project-maintenance.ts"],"sourcesContent":["// Shim globals in esm bundle\nimport path from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\nconst getFilename = () => fileURLToPath(import.meta.url)\nconst getDirname = () => path.dirname(getFilename())\n\nexport const __dirname = /* @__PURE__ */ getDirname()\nexport const __filename = /* @__PURE__ */ getFilename()\n","/**\n * Bun SQLite Compatibility Layer\n *\n * Provides a small better-sqlite3 compatibility layer for the available local\n * SQLite implementation. Node 22 ships node:sqlite, which keeps Memorix\n * usable when an optional better-sqlite3 native binary is unavailable.\n */\n\nimport { createRequire } from 'node:module';\n\nlet Database: any;\nlet driver: 'better-sqlite3' | 'node:sqlite' | 'bun:sqlite' | undefined;\nconst requireFromHere = createRequire(import.meta.url);\n\nfunction loadNodeSqlite(): any {\n const nodeSqlite = requireFromHere('node:sqlite');\n return nodeSqlite.DatabaseSync;\n}\n\nfunction isNativeBindingFailure(error: unknown): boolean {\n const message = error instanceof Error ? error.message : String(error);\n return /could not locate the bindings file|better_sqlite3\\.node|module did not self-register/i.test(message);\n}\n\nfunction addCompatibility(db: any): any {\n // Bun and node:sqlite do not expose better-sqlite3's pragma helper.\n if (!db.pragma) {\n db.pragma = function (pragma: string, options?: { simple?: boolean }) {\n const statement = db.prepare(`PRAGMA ${pragma}`);\n if (options?.simple) {\n const result = statement.get();\n return result ? Object.values(result)[0] : undefined;\n }\n return statement.all();\n };\n }\n\n // Stores use better-sqlite3's synchronous transaction factory. Keep nested\n // calls correct with savepoints instead of silently committing inner work.\n if (!db.transaction) {\n let depth = 0;\n let sequence = 0;\n db.transaction = function <T>(fn: (...args: any[]) => T) {\n return (...args: any[]): T => {\n const outermost = depth === 0;\n const savepoint = `memorix_tx_${++sequence}`;\n if (outermost) {\n db.exec('BEGIN IMMEDIATE');\n } else {\n db.exec(`SAVEPOINT ${savepoint}`);\n }\n depth += 1;\n try {\n const result = fn(...args);\n if (result && typeof (result as any).then === 'function') {\n throw new Error('[memorix] SQLite transactions must be synchronous');\n }\n depth -= 1;\n if (outermost) {\n db.exec('COMMIT');\n } else {\n db.exec(`RELEASE SAVEPOINT ${savepoint}`);\n }\n return result;\n } catch (error) {\n depth -= 1;\n try {\n if (outermost) {\n db.exec('ROLLBACK');\n } else {\n db.exec(`ROLLBACK TO SAVEPOINT ${savepoint}`);\n db.exec(`RELEASE SAVEPOINT ${savepoint}`);\n }\n } catch {\n // Preserve the original application failure when rollback itself fails.\n }\n throw error;\n }\n };\n };\n }\n\n return db;\n}\n\nfunction instantiateDatabase(Sqlite: any, filePath: string, options?: any): any {\n // DatabaseSync validates that an explicitly supplied second argument is an\n // object, unlike better-sqlite3 which accepts undefined.\n return driver === 'node:sqlite' && options === undefined\n ? new Sqlite(filePath)\n : new Sqlite(filePath, options);\n}\n\nexport function loadSqlite(): any {\n if (Database) return Database;\n\n // Kept as an operational escape hatch and a regression-test seam. Node 22\n // is the supported minimum runtime, so this does not expand the platform\n // contract beyond package.json's existing engine requirement.\n if (process.env.MEMORIX_SQLITE_DRIVER === 'node') {\n Database = loadNodeSqlite();\n driver = 'node:sqlite';\n return Database;\n }\n\n // Try better-sqlite3 first (Node.js)\n try {\n Database = requireFromHere('better-sqlite3');\n driver = 'better-sqlite3';\n return Database;\n } catch {\n // Fall through to node:sqlite, then Bun's runtime implementation.\n }\n\n try {\n Database = loadNodeSqlite();\n driver = 'node:sqlite';\n return Database;\n } catch {\n // Fall through to bun:sqlite\n }\n\n // Try bun:sqlite (Bun runtime)\n try {\n // bun:sqlite is a Bun built-in\n const bunSqlite = requireFromHere('bun:sqlite');\n Database = bunSqlite.Database;\n driver = 'bun:sqlite';\n return Database;\n } catch {\n throw new Error('[memorix] SQLite is unavailable (better-sqlite3, node:sqlite, and bun:sqlite failed)');\n }\n}\n\n/**\n * Create a SQLite database with better-sqlite3 compatible API.\n * Works under both Node.js (better-sqlite3) and Bun (bun:sqlite).\n */\nexport function createDatabase(path: string, options?: any): any {\n const Sqlite = loadSqlite();\n try {\n return addCompatibility(instantiateDatabase(Sqlite, path, options));\n } catch (error) {\n // require('better-sqlite3') can succeed even when npm had no prebuild and\n // no local compiler. Fall back to Node's built-in SQLite for that one\n // recoverable case; real open/corruption errors still surface unchanged.\n if (driver !== 'better-sqlite3' || !isNativeBindingFailure(error)) throw error;\n Database = loadNodeSqlite();\n driver = 'node:sqlite';\n return addCompatibility(instantiateDatabase(Database, path, options));\n }\n}\n\n/** Test-only reset for the driver cache used by the forced node:sqlite path. */\nexport function resetSqliteDriverForTests(): void {\n Database = undefined;\n driver = undefined;\n}\n","/**\n * Shared SQLite Database Handle\n *\n * Provides a singleton-per-dataDir better-sqlite3 connection shared across\n * all SQLite-backed stores (observations, mini-skills, sessions, team).\n *\n * Responsibilities:\n * - Dynamic require of better-sqlite3 (optionalDependencies)\n * - WAL mode and busy_timeout configuration\n * - Schema creation for ALL tables (observations, mini_skills, sessions, meta, team_*)\n * - Singleton caching per dataDir\n * - Graceful close\n */\n\nimport { createRequire } from 'node:module';\nimport path from 'node:path';\nimport fs from 'node:fs';\nimport { createDatabase, loadSqlite } from './bun-sqlite-compat.js';\n\n// Dynamic require for SQLite (better-sqlite3, node:sqlite, or bun:sqlite)\nlet BetterSqlite3: any;\n\nexport function loadBetterSqlite3(): any {\n if (BetterSqlite3) return BetterSqlite3;\n try {\n BetterSqlite3 = loadSqlite();\n return BetterSqlite3;\n } catch {\n throw new Error('[memorix] SQLite is not available (better-sqlite3, node:sqlite, and bun:sqlite all failed)');\n }\n}\n\n// ── Schema DDL ──────────────────────────────────────────────────────\n\nconst CREATE_OBSERVATIONS_TABLE = `\nCREATE TABLE IF NOT EXISTS observations (\n id INTEGER PRIMARY KEY,\n entityName TEXT NOT NULL,\n type TEXT NOT NULL,\n title TEXT NOT NULL,\n narrative TEXT NOT NULL DEFAULT '',\n facts TEXT NOT NULL DEFAULT '[]',\n filesModified TEXT NOT NULL DEFAULT '[]',\n concepts TEXT NOT NULL DEFAULT '[]',\n tokens INTEGER NOT NULL DEFAULT 0,\n createdAt TEXT NOT NULL,\n updatedAt TEXT,\n projectId TEXT NOT NULL,\n hasCausalLanguage INTEGER DEFAULT 0,\n topicKey TEXT,\n revisionCount INTEGER DEFAULT 1,\n sessionId TEXT,\n status TEXT NOT NULL DEFAULT 'active',\n progress TEXT,\n source TEXT DEFAULT 'agent',\n commitHash TEXT,\n relatedCommits TEXT,\n relatedEntities TEXT,\n sourceDetail TEXT,\n valueCategory TEXT,\n admissionState TEXT,\n admissionReason TEXT,\n visibility TEXT,\n sharedWithAgentIds TEXT\n);\n`;\n\nconst CREATE_MINI_SKILLS_TABLE = `\nCREATE TABLE IF NOT EXISTS mini_skills (\n id INTEGER PRIMARY KEY,\n sourceObservationIds TEXT NOT NULL DEFAULT '[]',\n sourceEntity TEXT NOT NULL DEFAULT 'unknown',\n title TEXT NOT NULL,\n instruction TEXT NOT NULL DEFAULT '',\n trigger_desc TEXT NOT NULL DEFAULT '',\n facts TEXT NOT NULL DEFAULT '[]',\n projectId TEXT NOT NULL,\n createdAt TEXT NOT NULL,\n usedCount INTEGER NOT NULL DEFAULT 0,\n tags TEXT NOT NULL DEFAULT '[]'\n);\n`;\n\nconst CREATE_SESSIONS_TABLE = `\nCREATE TABLE IF NOT EXISTS sessions (\n id TEXT PRIMARY KEY,\n projectId TEXT NOT NULL,\n startedAt TEXT NOT NULL,\n endedAt TEXT,\n status TEXT NOT NULL DEFAULT 'active',\n summary TEXT,\n agent TEXT\n);\n`;\n\nconst CREATE_META_TABLE = `\nCREATE TABLE IF NOT EXISTS meta (\n key TEXT PRIMARY KEY,\n value TEXT NOT NULL\n);\n`;\n\n// ── Phase 4a: Orchestration Coordination Tables ─────────────────────\n\nconst CREATE_TEAM_AGENTS_TABLE = `\nCREATE TABLE IF NOT EXISTS team_agents (\n agent_id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL,\n agent_type TEXT NOT NULL,\n instance_id TEXT NOT NULL,\n name TEXT NOT NULL DEFAULT '',\n role TEXT,\n capabilities TEXT,\n status TEXT NOT NULL DEFAULT 'active',\n joined_at INTEGER NOT NULL,\n last_heartbeat INTEGER NOT NULL,\n left_at INTEGER,\n last_seen_obs_generation INTEGER NOT NULL DEFAULT 0,\n UNIQUE(project_id, agent_type, instance_id)\n);\n`;\n\nconst CREATE_TEAM_MESSAGES_TABLE = `\nCREATE TABLE IF NOT EXISTS team_messages (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL,\n sender_agent_id TEXT NOT NULL,\n recipient_agent_id TEXT,\n type TEXT NOT NULL DEFAULT 'direct',\n content TEXT NOT NULL DEFAULT '',\n payload TEXT,\n task_id TEXT,\n read_at INTEGER,\n created_at INTEGER NOT NULL,\n to_role TEXT,\n handoff_status TEXT,\n FOREIGN KEY (sender_agent_id) REFERENCES team_agents(agent_id),\n FOREIGN KEY (task_id) REFERENCES team_tasks(task_id)\n);\n`;\n\nconst CREATE_TEAM_TASKS_TABLE = `\nCREATE TABLE IF NOT EXISTS team_tasks (\n task_id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL,\n description TEXT NOT NULL,\n status TEXT NOT NULL DEFAULT 'pending',\n assignee_agent_id TEXT,\n result TEXT,\n metadata TEXT,\n created_by TEXT,\n created_at INTEGER NOT NULL,\n updated_at INTEGER NOT NULL,\n required_role TEXT,\n preferred_role TEXT,\n FOREIGN KEY (assignee_agent_id) REFERENCES team_agents(agent_id),\n FOREIGN KEY (created_by) REFERENCES team_agents(agent_id)\n);\n`;\n\nconst CREATE_TEAM_TASK_DEPS_TABLE = `\nCREATE TABLE IF NOT EXISTS team_task_deps (\n task_id TEXT NOT NULL,\n dep_task_id TEXT NOT NULL,\n PRIMARY KEY (task_id, dep_task_id),\n FOREIGN KEY (task_id) REFERENCES team_tasks(task_id),\n FOREIGN KEY (dep_task_id) REFERENCES team_tasks(task_id)\n);\n`;\n\nconst CREATE_TEAM_LOCKS_TABLE = `\nCREATE TABLE IF NOT EXISTS team_locks (\n file TEXT NOT NULL,\n project_id TEXT NOT NULL,\n locked_by TEXT NOT NULL,\n locked_at INTEGER NOT NULL,\n expires_at INTEGER NOT NULL,\n PRIMARY KEY (file, project_id),\n FOREIGN KEY (locked_by) REFERENCES team_agents(agent_id)\n);\n`;\n\n// ── Phase 4d: Role-based Coordination Tables ─────────────────────────\n\nconst CREATE_TEAM_ROLES_TABLE = `\nCREATE TABLE IF NOT EXISTS team_roles (\n role_id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL,\n label TEXT NOT NULL,\n description TEXT,\n preferred_agent_types TEXT NOT NULL DEFAULT '[]',\n max_concurrent INTEGER NOT NULL DEFAULT 1,\n created_at INTEGER NOT NULL\n);\n`;\n\n// ── Chat Transcript Table ──────────────────────────────────────────────\n\nconst CREATE_CHAT_TRANSCRIPT_TABLE = `\nCREATE TABLE IF NOT EXISTS chat_transcript (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n project_id TEXT NOT NULL,\n thread_id TEXT NOT NULL DEFAULT 'default',\n role TEXT NOT NULL,\n content TEXT NOT NULL DEFAULT '',\n sources_json TEXT NOT NULL DEFAULT '[]',\n meta_json TEXT NOT NULL DEFAULT '{}',\n error INTEGER NOT NULL DEFAULT 0,\n created_at TEXT NOT NULL\n);\n`;\n\n// ── Knowledge Graph Tables ────────────────────────────────────────────\n\nconst CREATE_GRAPH_ENTITIES_TABLE = `\nCREATE TABLE IF NOT EXISTS graph_entities (\n name TEXT PRIMARY KEY,\n entityType TEXT NOT NULL DEFAULT '',\n observations TEXT NOT NULL DEFAULT '[]'\n);\n`;\n\nconst CREATE_GRAPH_RELATIONS_TABLE = `\nCREATE TABLE IF NOT EXISTS graph_relations (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n from_entity TEXT NOT NULL,\n to_entity TEXT NOT NULL,\n relationType TEXT NOT NULL DEFAULT '',\n UNIQUE(from_entity, to_entity, relationType)\n);\n`;\n\n// ── CodeGraph Memory Tables ─────────────────────────────────────────\n\nconst CREATE_CODE_FILES_TABLE = `\nCREATE TABLE IF NOT EXISTS code_files (\n id TEXT PRIMARY KEY,\n projectId TEXT NOT NULL,\n path TEXT NOT NULL,\n language TEXT,\n contentHash TEXT NOT NULL,\n mtimeMs INTEGER,\n sizeBytes INTEGER,\n indexedAt TEXT NOT NULL,\n gitCommit TEXT,\n UNIQUE(projectId, path)\n);\n`;\n\nconst CREATE_CODE_SYMBOLS_TABLE = `\nCREATE TABLE IF NOT EXISTS code_symbols (\n id TEXT PRIMARY KEY,\n projectId TEXT NOT NULL,\n fileId TEXT NOT NULL,\n path TEXT NOT NULL,\n name TEXT NOT NULL,\n qualifiedName TEXT NOT NULL,\n kind TEXT NOT NULL,\n startLine INTEGER,\n endLine INTEGER,\n signature TEXT,\n contentHash TEXT,\n indexedAt TEXT NOT NULL,\n stale INTEGER NOT NULL DEFAULT 0,\n UNIQUE(projectId, fileId, qualifiedName, kind)\n);\n`;\n\nconst CREATE_CODE_EDGES_TABLE = `\nCREATE TABLE IF NOT EXISTS code_edges (\n id TEXT PRIMARY KEY,\n projectId TEXT NOT NULL,\n fromSymbolId TEXT,\n toSymbolId TEXT,\n fromFileId TEXT,\n toFileId TEXT,\n type TEXT NOT NULL,\n confidence REAL NOT NULL DEFAULT 1.0,\n evidence TEXT,\n indexedAt TEXT NOT NULL\n);\n`;\n\nconst CREATE_OBSERVATION_CODE_REFS_TABLE = `\nCREATE TABLE IF NOT EXISTS observation_code_refs (\n id TEXT PRIMARY KEY,\n projectId TEXT NOT NULL,\n observationId INTEGER NOT NULL,\n fileId TEXT,\n symbolId TEXT,\n capturedFileHash TEXT,\n capturedSymbolHash TEXT,\n status TEXT NOT NULL,\n reason TEXT,\n createdAt TEXT NOT NULL,\n updatedAt TEXT\n);\n`;\n\nconst CREATE_SCHEMA_MIGRATIONS_TABLE = [\n 'CREATE TABLE IF NOT EXISTS schema_migrations (',\n ' id TEXT PRIMARY KEY,',\n ' applied_at TEXT NOT NULL',\n ');',\n].join('\\n');\n\nconst CREATE_CODE_STATE_SNAPSHOTS_TABLE = [\n 'CREATE TABLE IF NOT EXISTS code_state_snapshots (',\n ' id TEXT PRIMARY KEY,',\n ' projectId TEXT NOT NULL,',\n ' provider TEXT NOT NULL,',\n ' baseRevision TEXT,',\n ' worktreeFingerprint TEXT NOT NULL,',\n ' worktreeState TEXT NOT NULL,',\n ' changedPathCount INTEGER NOT NULL DEFAULT 0,',\n ' indexedAt TEXT NOT NULL,',\n ' sourceEpoch INTEGER NOT NULL,',\n \" completenessJson TEXT NOT NULL DEFAULT '{}',\",\n ' previousSnapshotId TEXT,',\n ' UNIQUE(projectId, sourceEpoch)',\n ');',\n].join('\\n');\n\n// ── 1.2 Knowledge Claim Ledger ──────────────────────────────────────\n\nconst CREATE_KNOWLEDGE_CLAIMS_TABLE = `\nCREATE TABLE IF NOT EXISTS knowledge_claims (\n id TEXT PRIMARY KEY,\n projectId TEXT NOT NULL,\n subject TEXT NOT NULL,\n predicate TEXT NOT NULL,\n objectValue TEXT NOT NULL,\n scope TEXT NOT NULL,\n claimKey TEXT NOT NULL,\n conflictKey TEXT NOT NULL,\n status TEXT NOT NULL,\n confidence REAL NOT NULL,\n observedAt TEXT NOT NULL,\n validFrom TEXT,\n validTo TEXT,\n supersededBy TEXT,\n reviewState TEXT NOT NULL,\n origin TEXT NOT NULL,\n createdAt TEXT NOT NULL,\n updatedAt TEXT NOT NULL\n);\n`;\n\nconst CREATE_KNOWLEDGE_CLAIM_EVIDENCE_TABLE = `\nCREATE TABLE IF NOT EXISTS knowledge_claim_evidence (\n id TEXT PRIMARY KEY,\n claimId TEXT NOT NULL,\n evidenceKind TEXT NOT NULL,\n evidenceId TEXT NOT NULL,\n relation TEXT NOT NULL,\n snapshotId TEXT,\n locator TEXT,\n capturedHash TEXT,\n evidenceKey TEXT NOT NULL,\n createdAt TEXT NOT NULL,\n UNIQUE(claimId, evidenceKey),\n FOREIGN KEY (claimId) REFERENCES knowledge_claims(id) ON DELETE CASCADE\n);\n`;\n\nconst CREATE_KNOWLEDGE_CLAIM_EVENTS_TABLE = `\nCREATE TABLE IF NOT EXISTS knowledge_claim_events (\n id TEXT PRIMARY KEY,\n projectId TEXT NOT NULL,\n claimId TEXT NOT NULL,\n kind TEXT NOT NULL,\n fromStatus TEXT,\n toStatus TEXT,\n relatedClaimId TEXT,\n detail TEXT,\n createdAt TEXT NOT NULL,\n FOREIGN KEY (claimId) REFERENCES knowledge_claims(id) ON DELETE CASCADE\n);\n`;\n\n// ── 1.2 Knowledge Workspace ─────────────────────────────────────────\n\nconst CREATE_KNOWLEDGE_WORKSPACES_TABLE = [\n 'CREATE TABLE IF NOT EXISTS knowledge_workspaces (',\n ' id TEXT PRIMARY KEY,',\n ' projectId TEXT NOT NULL,',\n ' mode TEXT NOT NULL,',\n ' rootPath TEXT NOT NULL,',\n ' projectRoot TEXT,',\n ' status TEXT NOT NULL,',\n ' createdAt TEXT NOT NULL,',\n ' updatedAt TEXT NOT NULL,',\n ' lastCompiledAt TEXT,',\n ' lastLintedAt TEXT,',\n ' UNIQUE(projectId, mode)',\n ');',\n].join('\\n');\n\nconst CREATE_KNOWLEDGE_PAGES_TABLE = [\n 'CREATE TABLE IF NOT EXISTS knowledge_pages (',\n ' id TEXT PRIMARY KEY,',\n ' workspaceId TEXT NOT NULL,',\n ' relativePath TEXT NOT NULL,',\n ' title TEXT NOT NULL,',\n ' kind TEXT NOT NULL,',\n ' status TEXT NOT NULL,',\n ' reviewState TEXT NOT NULL,',\n ' contentHash TEXT NOT NULL,',\n ' sourceHash TEXT NOT NULL,',\n \" claimIdsJson TEXT NOT NULL DEFAULT '[]',\",\n ' snapshotId TEXT,',\n \" tagsJson TEXT NOT NULL DEFAULT '[]',\",\n ' generatedAt TEXT NOT NULL,',\n ' updatedAt TEXT NOT NULL,',\n ' lastLintedAt TEXT,',\n ' manualContentHash TEXT,',\n ' UNIQUE(workspaceId, relativePath),',\n ' FOREIGN KEY (workspaceId) REFERENCES knowledge_workspaces(id) ON DELETE CASCADE',\n ');',\n].join('\\n');\n\nconst CREATE_KNOWLEDGE_PAGE_CLAIMS_TABLE = [\n 'CREATE TABLE IF NOT EXISTS knowledge_page_claims (',\n ' pageId TEXT NOT NULL,',\n ' claimId TEXT NOT NULL,',\n ' role TEXT NOT NULL,',\n ' PRIMARY KEY (pageId, claimId),',\n ' FOREIGN KEY (pageId) REFERENCES knowledge_pages(id) ON DELETE CASCADE,',\n ' FOREIGN KEY (claimId) REFERENCES knowledge_claims(id) ON DELETE RESTRICT',\n ');',\n].join('\\n');\n\nconst CREATE_KNOWLEDGE_PAGE_LINKS_TABLE = [\n 'CREATE TABLE IF NOT EXISTS knowledge_page_links (',\n ' sourcePageId TEXT NOT NULL,',\n ' targetPath TEXT NOT NULL,',\n ' PRIMARY KEY (sourcePageId, targetPath),',\n ' FOREIGN KEY (sourcePageId) REFERENCES knowledge_pages(id) ON DELETE CASCADE',\n ');',\n].join('\\n');\n\nconst CREATE_KNOWLEDGE_PROPOSALS_TABLE = [\n 'CREATE TABLE IF NOT EXISTS knowledge_proposals (',\n ' id TEXT PRIMARY KEY,',\n ' workspaceId TEXT NOT NULL,',\n ' pageId TEXT NOT NULL,',\n ' targetPath TEXT NOT NULL,',\n ' proposalPath TEXT NOT NULL,',\n ' baseContentHash TEXT,',\n ' sourceHash TEXT NOT NULL,',\n ' reason TEXT NOT NULL,',\n ' status TEXT NOT NULL,',\n ' createdAt TEXT NOT NULL,',\n ' appliedAt TEXT,',\n ' UNIQUE(workspaceId, proposalPath),',\n ' FOREIGN KEY (workspaceId) REFERENCES knowledge_workspaces(id) ON DELETE CASCADE,',\n ' FOREIGN KEY (pageId) REFERENCES knowledge_pages(id) ON DELETE CASCADE',\n ');',\n].join('\\n');\n\n// ── 1.2 Workflow inheritance ────────────────────────────────────────\n\nconst CREATE_KNOWLEDGE_WORKFLOWS_TABLE = [\n 'CREATE TABLE IF NOT EXISTS knowledge_workflows (',\n ' id TEXT PRIMARY KEY,',\n ' workspaceId TEXT NOT NULL,',\n ' sourcePath TEXT NOT NULL,',\n ' title TEXT NOT NULL,',\n ' status TEXT NOT NULL,',\n ' version INTEGER NOT NULL,',\n ' sourceHash TEXT NOT NULL,',\n ' contentHash TEXT NOT NULL,',\n ' specJson TEXT NOT NULL,',\n ' importedFrom TEXT,',\n ' createdAt TEXT NOT NULL,',\n ' updatedAt TEXT NOT NULL,',\n ' UNIQUE(workspaceId, sourcePath),',\n ' FOREIGN KEY (workspaceId) REFERENCES knowledge_workspaces(id) ON DELETE CASCADE',\n ');',\n].join('\\n');\n\nconst CREATE_KNOWLEDGE_WORKFLOW_RUNS_TABLE = [\n 'CREATE TABLE IF NOT EXISTS knowledge_workflow_runs (',\n ' id TEXT PRIMARY KEY,',\n ' workflowId TEXT NOT NULL,',\n ' projectId TEXT NOT NULL,',\n ' task TEXT NOT NULL,',\n ' startingSnapshotId TEXT,',\n \" selectedEvidenceJson TEXT NOT NULL DEFAULT '[]',\",\n \" phaseStateJson TEXT NOT NULL DEFAULT '{}',\",\n ' outcome TEXT NOT NULL,',\n ' verificationVerdict TEXT NOT NULL,',\n ' failureReason TEXT,',\n ' startedAt TEXT NOT NULL,',\n ' completedAt TEXT,',\n ' FOREIGN KEY (workflowId) REFERENCES knowledge_workflows(id) ON DELETE CASCADE',\n ');',\n].join('\\n');\n\n// ── Runtime maintenance jobs ───────────────────────────────────────\n\nconst CREATE_MAINTENANCE_JOBS_TABLE = `\nCREATE TABLE IF NOT EXISTS maintenance_jobs (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL,\n kind TEXT NOT NULL,\n dedupe_key TEXT NOT NULL,\n payload_json TEXT NOT NULL DEFAULT '{}',\n status TEXT NOT NULL DEFAULT 'pending',\n attempts INTEGER NOT NULL DEFAULT 0,\n max_attempts INTEGER NOT NULL DEFAULT 8,\n run_after INTEGER NOT NULL,\n lease_owner TEXT,\n lease_expires_at INTEGER,\n last_error TEXT,\n created_at INTEGER NOT NULL,\n updated_at INTEGER NOT NULL,\n completed_at INTEGER\n);\n`;\n\nconst CREATE_MAINTENANCE_TARGETS_TABLE = `\nCREATE TABLE IF NOT EXISTS maintenance_targets (\n project_id TEXT PRIMARY KEY,\n project_root TEXT NOT NULL,\n data_dir TEXT NOT NULL,\n updated_at INTEGER NOT NULL\n);\n`;\n\nconst CREATE_INDEXES = `\nCREATE INDEX IF NOT EXISTS idx_observations_projectId ON observations(projectId);\nCREATE INDEX IF NOT EXISTS idx_observations_topicKey ON observations(projectId, topicKey);\nCREATE INDEX IF NOT EXISTS idx_observations_status ON observations(status);\nCREATE INDEX IF NOT EXISTS idx_observations_project_status_id ON observations(projectId, status, id);\nCREATE INDEX IF NOT EXISTS idx_observations_project_admission ON observations(projectId, status, admissionState, id);\nCREATE INDEX IF NOT EXISTS idx_observations_project_visibility ON observations(projectId, status, visibility, id);\nCREATE INDEX IF NOT EXISTS idx_mini_skills_projectId ON mini_skills(projectId);\nCREATE INDEX IF NOT EXISTS idx_sessions_projectId ON sessions(projectId);\nCREATE INDEX IF NOT EXISTS idx_sessions_status ON sessions(projectId, status);\nCREATE INDEX IF NOT EXISTS idx_team_agents_project ON team_agents(project_id, status);\nCREATE INDEX IF NOT EXISTS idx_team_messages_recipient ON team_messages(recipient_agent_id, read_at);\nCREATE INDEX IF NOT EXISTS idx_team_messages_project ON team_messages(project_id, created_at);\nCREATE INDEX IF NOT EXISTS idx_team_tasks_project ON team_tasks(project_id, status);\nCREATE INDEX IF NOT EXISTS idx_team_tasks_assignee ON team_tasks(assignee_agent_id, status);\nCREATE INDEX IF NOT EXISTS idx_team_locks_project ON team_locks(project_id);\nCREATE INDEX IF NOT EXISTS idx_team_roles_project ON team_roles(project_id);\nCREATE INDEX IF NOT EXISTS idx_team_tasks_role ON team_tasks(required_role);\nCREATE INDEX IF NOT EXISTS idx_team_messages_role ON team_messages(to_role);\nCREATE INDEX IF NOT EXISTS idx_graph_relations_from ON graph_relations(from_entity);\nCREATE INDEX IF NOT EXISTS idx_graph_relations_to ON graph_relations(to_entity);\nCREATE INDEX IF NOT EXISTS idx_chat_transcript_project ON chat_transcript(project_id, thread_id);\nCREATE INDEX IF NOT EXISTS idx_code_files_project ON code_files(projectId);\nCREATE INDEX IF NOT EXISTS idx_code_symbols_project_name ON code_symbols(projectId, name);\nCREATE INDEX IF NOT EXISTS idx_code_symbols_file ON code_symbols(fileId);\nCREATE INDEX IF NOT EXISTS idx_code_edges_project ON code_edges(projectId, type);\nCREATE INDEX IF NOT EXISTS idx_code_snapshots_project_epoch ON code_state_snapshots(projectId, sourceEpoch DESC);\nCREATE INDEX IF NOT EXISTS idx_code_files_snapshot ON code_files(projectId, snapshotId);\nCREATE INDEX IF NOT EXISTS idx_code_symbols_snapshot ON code_symbols(projectId, snapshotId);\nCREATE INDEX IF NOT EXISTS idx_code_edges_snapshot ON code_edges(projectId, snapshotId);\nCREATE INDEX IF NOT EXISTS idx_observation_code_refs_obs ON observation_code_refs(projectId, observationId);\nCREATE INDEX IF NOT EXISTS idx_observation_code_refs_status ON observation_code_refs(projectId, status);\nCREATE INDEX IF NOT EXISTS idx_knowledge_claims_project_status ON knowledge_claims(projectId, status, updatedAt DESC);\nCREATE INDEX IF NOT EXISTS idx_knowledge_claims_project_conflict ON knowledge_claims(projectId, conflictKey, status);\nCREATE INDEX IF NOT EXISTS idx_knowledge_claims_project_key ON knowledge_claims(projectId, claimKey, status);\nCREATE INDEX IF NOT EXISTS idx_knowledge_claim_evidence_claim ON knowledge_claim_evidence(claimId, createdAt);\nCREATE INDEX IF NOT EXISTS idx_knowledge_claim_events_claim ON knowledge_claim_events(claimId, createdAt);\nCREATE INDEX IF NOT EXISTS idx_knowledge_workspaces_project ON knowledge_workspaces(projectId, mode);\nCREATE INDEX IF NOT EXISTS idx_knowledge_pages_workspace_status ON knowledge_pages(workspaceId, status, updatedAt DESC);\nCREATE INDEX IF NOT EXISTS idx_knowledge_page_claims_claim ON knowledge_page_claims(claimId);\nCREATE INDEX IF NOT EXISTS idx_knowledge_proposals_workspace_status ON knowledge_proposals(workspaceId, status, createdAt DESC);\nCREATE INDEX IF NOT EXISTS idx_knowledge_workflows_workspace_status ON knowledge_workflows(workspaceId, status, updatedAt DESC);\nCREATE INDEX IF NOT EXISTS idx_knowledge_workflow_runs_project_workflow ON knowledge_workflow_runs(projectId, workflowId, startedAt DESC);\nCREATE INDEX IF NOT EXISTS idx_maintenance_jobs_ready ON maintenance_jobs(status, run_after);\nCREATE INDEX IF NOT EXISTS idx_maintenance_jobs_project ON maintenance_jobs(project_id, status, run_after);\nCREATE INDEX IF NOT EXISTS idx_maintenance_targets_updated ON maintenance_targets(updated_at);\nCREATE UNIQUE INDEX IF NOT EXISTS idx_maintenance_jobs_active_dedupe\n ON maintenance_jobs(project_id, kind, dedupe_key)\n WHERE status IN ('pending', 'running', 'retry');\n`;\n\ninterface SchemaMigration {\n id: string;\n apply: (db: any) => void;\n}\n\nfunction hasColumn(db: any, table: string, column: string): boolean {\n return db.prepare('PRAGMA table_info(' + table + ')')\n .all()\n .some((row: { name?: string }) => row.name === column);\n}\n\nfunction addColumnIfMissing(db: any, table: string, column: string, definition: string): void {\n if (hasColumn(db, table, column)) return;\n db.exec('ALTER TABLE ' + table + ' ADD COLUMN ' + definition);\n}\n\nconst SCHEMA_MIGRATIONS: SchemaMigration[] = [\n {\n id: '1.2.2-observation-admission',\n apply: (db) => {\n addColumnIfMissing(db, 'observations', 'admissionState', 'admissionState TEXT');\n addColumnIfMissing(db, 'observations', 'admissionReason', 'admissionReason TEXT');\n db.exec('CREATE INDEX IF NOT EXISTS idx_observations_project_admission ON observations(projectId, status, admissionState, id)');\n },\n },\n {\n id: '1.2.2-observation-visibility',\n apply: (db) => {\n addColumnIfMissing(db, 'observations', 'visibility', 'visibility TEXT');\n addColumnIfMissing(db, 'observations', 'sharedWithAgentIds', 'sharedWithAgentIds TEXT');\n db.exec('CREATE INDEX IF NOT EXISTS idx_observations_project_visibility ON observations(projectId, status, visibility, id)');\n },\n },\n {\n id: '1.2-code-state-snapshots',\n apply: (db) => {\n db.exec(CREATE_CODE_STATE_SNAPSHOTS_TABLE);\n addColumnIfMissing(db, 'code_files', 'snapshotId', 'snapshotId TEXT');\n addColumnIfMissing(db, 'code_files', 'sourceEpoch', 'sourceEpoch INTEGER');\n addColumnIfMissing(db, 'code_symbols', 'snapshotId', 'snapshotId TEXT');\n addColumnIfMissing(db, 'code_symbols', 'sourceEpoch', 'sourceEpoch INTEGER');\n addColumnIfMissing(db, 'code_edges', 'snapshotId', 'snapshotId TEXT');\n addColumnIfMissing(db, 'code_edges', 'sourceEpoch', 'sourceEpoch INTEGER');\n addColumnIfMissing(db, 'observation_code_refs', 'snapshotId', 'snapshotId TEXT');\n db.exec('CREATE INDEX IF NOT EXISTS idx_code_snapshots_project_epoch ON code_state_snapshots(projectId, sourceEpoch DESC)');\n db.exec('CREATE INDEX IF NOT EXISTS idx_code_files_snapshot ON code_files(projectId, snapshotId)');\n db.exec('CREATE INDEX IF NOT EXISTS idx_code_symbols_snapshot ON code_symbols(projectId, snapshotId)');\n db.exec('CREATE INDEX IF NOT EXISTS idx_code_edges_snapshot ON code_edges(projectId, snapshotId)');\n },\n },\n {\n id: '1.2-knowledge-claim-ledger',\n apply: (db) => {\n db.exec(CREATE_KNOWLEDGE_CLAIMS_TABLE);\n db.exec(CREATE_KNOWLEDGE_CLAIM_EVIDENCE_TABLE);\n db.exec(CREATE_KNOWLEDGE_CLAIM_EVENTS_TABLE);\n db.exec('CREATE INDEX IF NOT EXISTS idx_knowledge_claims_project_status ON knowledge_claims(projectId, status, updatedAt DESC)');\n db.exec('CREATE INDEX IF NOT EXISTS idx_knowledge_claims_project_conflict ON knowledge_claims(projectId, conflictKey, status)');\n db.exec('CREATE INDEX IF NOT EXISTS idx_knowledge_claims_project_key ON knowledge_claims(projectId, claimKey, status)');\n db.exec('CREATE INDEX IF NOT EXISTS idx_knowledge_claim_evidence_claim ON knowledge_claim_evidence(claimId, createdAt)');\n db.exec('CREATE INDEX IF NOT EXISTS idx_knowledge_claim_events_claim ON knowledge_claim_events(claimId, createdAt)');\n },\n },\n {\n id: '1.2-knowledge-workspace',\n apply: (db) => {\n db.exec(CREATE_KNOWLEDGE_WORKSPACES_TABLE);\n db.exec(CREATE_KNOWLEDGE_PAGES_TABLE);\n db.exec(CREATE_KNOWLEDGE_PAGE_CLAIMS_TABLE);\n db.exec(CREATE_KNOWLEDGE_PAGE_LINKS_TABLE);\n db.exec(CREATE_KNOWLEDGE_PROPOSALS_TABLE);\n db.exec('CREATE INDEX IF NOT EXISTS idx_knowledge_workspaces_project ON knowledge_workspaces(projectId, mode)');\n db.exec('CREATE INDEX IF NOT EXISTS idx_knowledge_pages_workspace_status ON knowledge_pages(workspaceId, status, updatedAt DESC)');\n db.exec('CREATE INDEX IF NOT EXISTS idx_knowledge_page_claims_claim ON knowledge_page_claims(claimId)');\n db.exec('CREATE INDEX IF NOT EXISTS idx_knowledge_proposals_workspace_status ON knowledge_proposals(workspaceId, status, createdAt DESC)');\n },\n },\n {\n id: '1.2-workflow-inheritance',\n apply: (db) => {\n db.exec(CREATE_KNOWLEDGE_WORKFLOWS_TABLE);\n db.exec(CREATE_KNOWLEDGE_WORKFLOW_RUNS_TABLE);\n db.exec('CREATE INDEX IF NOT EXISTS idx_knowledge_workflows_workspace_status ON knowledge_workflows(workspaceId, status, updatedAt DESC)');\n db.exec('CREATE INDEX IF NOT EXISTS idx_knowledge_workflow_runs_project_workflow ON knowledge_workflow_runs(projectId, workflowId, startedAt DESC)');\n },\n },\n];\n\nfunction applySchemaMigrations(db: any): void {\n db.exec(CREATE_SCHEMA_MIGRATIONS_TABLE);\n for (const migration of SCHEMA_MIGRATIONS) {\n const applied = db.prepare('SELECT 1 FROM schema_migrations WHERE id = ?').get(migration.id);\n if (applied) continue;\n const apply = db.transaction(() => {\n migration.apply(db);\n db.prepare('INSERT INTO schema_migrations (id, applied_at) VALUES (?, ?)').run(\n migration.id,\n new Date().toISOString(),\n );\n });\n apply();\n }\n}\n\n// ── Singleton cache ─────────────────────────────────────────────────\n\nconst _dbCache = new Map<string, any>();\n\n/**\n * Get or create a shared SQLite database handle for the given data directory.\n *\n * The handle is cached per normalized dataDir path. All stores (observations,\n * mini-skills, sessions) share the same connection and the same DB file.\n *\n * Callers must NOT close the returned handle directly — use closeDatabase().\n */\nexport function getDatabase(dataDir: string): any {\n const normalized = path.resolve(dataDir);\n const existing = _dbCache.get(normalized);\n if (existing) return existing;\n\n loadBetterSqlite3();\n fs.mkdirSync(dataDir, { recursive: true });\n\n const dbPath = path.join(dataDir, 'memorix.db');\n const db = createDatabase(dbPath);\n\n // WAL mode for concurrent read performance\n db.pragma('journal_mode = WAL');\n db.pragma('busy_timeout = 5000');\n db.pragma('foreign_keys = ON');\n\n // Create all tables\n db.exec(CREATE_OBSERVATIONS_TABLE);\n db.exec(CREATE_MINI_SKILLS_TABLE);\n db.exec(CREATE_SESSIONS_TABLE);\n db.exec(CREATE_META_TABLE);\n // Phase 4a: coordination tables (order matters for FK references)\n db.exec(CREATE_TEAM_AGENTS_TABLE);\n db.exec(CREATE_TEAM_TASKS_TABLE);\n db.exec(CREATE_TEAM_TASK_DEPS_TABLE);\n db.exec(CREATE_TEAM_MESSAGES_TABLE);\n db.exec(CREATE_TEAM_LOCKS_TABLE);\n db.exec(CREATE_TEAM_ROLES_TABLE);\n db.exec(CREATE_GRAPH_ENTITIES_TABLE);\n db.exec(CREATE_GRAPH_RELATIONS_TABLE);\n db.exec(CREATE_CHAT_TRANSCRIPT_TABLE);\n db.exec(CREATE_CODE_FILES_TABLE);\n db.exec(CREATE_CODE_SYMBOLS_TABLE);\n db.exec(CREATE_CODE_EDGES_TABLE);\n db.exec(CREATE_OBSERVATION_CODE_REFS_TABLE);\n db.exec(CREATE_MAINTENANCE_JOBS_TABLE);\n db.exec(CREATE_MAINTENANCE_TARGETS_TABLE);\n\n // Phase 3a migration: add sourceSnapshot + updatedAt to mini_skills\n // Idempotent — ALTER TABLE ADD COLUMN throws if column already exists\n // IMPORTANT: These must run BEFORE CREATE_INDEXES so columns exist when indexes reference them\n try { db.exec(`ALTER TABLE mini_skills ADD COLUMN sourceSnapshot TEXT NOT NULL DEFAULT ''`); } catch { /* already exists */ }\n try { db.exec(`ALTER TABLE mini_skills ADD COLUMN updatedAt TEXT`); } catch { /* already exists */ }\n\n // Phase 4a: observation attribution columns\n try { db.exec(`ALTER TABLE observations ADD COLUMN createdByAgentId TEXT`); } catch { /* already exists */ }\n try { db.exec(`ALTER TABLE observations ADD COLUMN writeGeneration INTEGER DEFAULT 0`); } catch { /* already exists */ }\n\n // Phase 4d: role-based coordination columns\n try { db.exec(`ALTER TABLE team_tasks ADD COLUMN required_role TEXT`); } catch { /* already exists */ }\n try { db.exec(`ALTER TABLE team_tasks ADD COLUMN preferred_role TEXT`); } catch { /* already exists */ }\n try { db.exec(`ALTER TABLE team_messages ADD COLUMN to_role TEXT`); } catch { /* already exists */ }\n try { db.exec(`ALTER TABLE team_messages ADD COLUMN handoff_status TEXT`); } catch { /* already exists */ }\n\n // New migrations are transactional and tracked. Older idempotent migrations\n // remain untouched for backwards compatibility with existing local stores.\n applySchemaMigrations(db);\n\n // Create indexes AFTER all ALTER TABLE migrations so referenced columns exist\n db.exec(CREATE_INDEXES);\n\n // Seed meta defaults\n db.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('storage_generation', '0')`).run();\n db.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('next_id', '1')`).run();\n db.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('mini_skills_generation', '0')`).run();\n\n _dbCache.set(normalized, db);\n return db;\n}\n\n/**\n * Close and remove a cached database handle for the given data directory.\n * Safe to call even if no handle exists.\n */\nexport function closeDatabase(dataDir: string): void {\n const normalized = path.resolve(dataDir);\n const db = _dbCache.get(normalized);\n if (db) {\n try { db.close(); } catch { /* best-effort */ }\n _dbCache.delete(normalized);\n }\n}\n\n/**\n * Close all cached database handles. Used during shutdown or tests.\n */\nexport function closeAllDatabases(): void {\n for (const [key, db] of _dbCache) {\n try { db.close(); } catch { /* best-effort */ }\n _dbCache.delete(key);\n }\n}\n\n/**\n * Check if better-sqlite3 is available without throwing.\n */\nexport function isSqliteAvailable(): boolean {\n try {\n loadBetterSqlite3();\n return true;\n } catch {\n return false;\n }\n}\n","import { join } from 'node:path';\n\nexport function getGlobalConfigTomlPath(homeDir: string): string {\n return join(homeDir, '.memorix', 'config.toml');\n}\n\nexport function getProjectConfigTomlPath(projectRoot: string): string {\n return join(projectRoot, 'memorix.toml');\n}\n\nexport function getGlobalYamlPath(homeDir: string): string {\n return join(homeDir, '.memorix', 'memorix.yml');\n}\n\nexport function getProjectYamlPath(projectRoot: string): string {\n return join(projectRoot, 'memorix.yml');\n}\n\nexport function getGlobalDotenvPath(homeDir: string): string {\n return join(homeDir, '.memorix', '.env');\n}\n\nexport function getProjectDotenvPath(projectRoot: string): string {\n return join(projectRoot, '.env');\n}\n\nexport function getLegacyConfigJsonPath(homeDir: string): string {\n return join(homeDir, '.memorix', 'config.json');\n}\n","/**\n * .env Loader for Memorix\n *\n * Loads compatibility environment overrides from project/user .env files.\n * The primary product configuration is TOML:\n * - ~/.memorix/config.toml\n * - <git-root>/memorix.toml\n *\n * Design principle:\n * TOML = normal user setup and structured behavior\n * .env = compatibility, CI, launchers, and temporary overrides\n *\n * Priority (highest wins):\n * 1. System environment variables (from MCP host `env` field or shell)\n * 2. Project .env file (./ .env in project root)\n * 3. User .env file (~/.memorix/.env) — advanced, not promoted\n *\n * Do not promote .env as the default product surface. Keep it as an override\n * layer for users who need launcher-specific behavior.\n */\n\nimport { existsSync, readFileSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { parse } from 'dotenv';\nimport { getGlobalDotenvPath, getProjectDotenvPath } from './config-paths.js';\n\n// ─── State ───\n\nlet dotenvLoaded = false;\nlet dotenvProjectRoot: string | null = null;\n\n/** Track which .env files were loaded (for diagnostics) */\nconst loadedEnvFiles: string[] = [];\n/** Track keys injected by .env so project switches can cleanly restore process.env */\nconst injectedKeys = new Set<string>();\n\nfunction loadEnvFile(filePath: string): void {\n if (!existsSync(filePath)) return;\n\n const parsed = parse(readFileSync(filePath, 'utf-8'));\n for (const [key, value] of Object.entries(parsed)) {\n if (!(key in process.env)) {\n process.env[key] = value;\n injectedKeys.add(key);\n }\n }\n\n loadedEnvFiles.push(filePath);\n}\n\ninterface DotenvLoadOptions {\n userHomeDir?: string;\n}\n\n// ─── Public API ───\n\n/**\n * Load .env files into process.env.\n * Called once during startup. Does NOT override existing env vars.\n *\n * @param projectRoot - Project root directory (for project-level .env)\n */\nexport function loadDotenv(projectRoot?: string, options: DotenvLoadOptions = {}): void {\n if (dotenvLoaded && dotenvProjectRoot === (projectRoot ?? null)) return;\n\n if (dotenvLoaded && dotenvProjectRoot !== (projectRoot ?? null)) {\n resetDotenv();\n }\n\n loadedEnvFiles.length = 0;\n\n // Loading order = priority order (with override: false, first value wins).\n // System env vars already exist in process.env, so they always win.\n\n // 1. Project-level .env — highest .env priority, load first\n if (projectRoot) {\n loadEnvFile(getProjectDotenvPath(projectRoot));\n }\n\n // 2. User-level .env (~/.memorix/.env) — lowest .env priority, load second\n // (override: false means it only fills in keys not already set)\n loadEnvFile(getGlobalDotenvPath(options.userHomeDir ?? homedir()));\n\n dotenvLoaded = true;\n dotenvProjectRoot = projectRoot ?? null;\n}\n\n/**\n * Reset dotenv state (for testing or project switch).\n */\nexport function resetDotenv(): void {\n for (const key of injectedKeys) {\n delete process.env[key];\n }\n injectedKeys.clear();\n dotenvLoaded = false;\n dotenvProjectRoot = null;\n loadedEnvFiles.length = 0;\n}\n\n/**\n * Get list of .env files that were loaded (for diagnostics).\n */\nexport function getLoadedEnvFiles(): readonly string[] {\n return loadedEnvFiles;\n}\n\n// ─── Supported .env variables ───\n// These are the ONLY variables Memorix reads from .env.\n// All are secrets or endpoint URLs — no behavior config.\n//\n// MEMORIX_LLM_API_KEY — Background memory LLM API key\n// MEMORIX_LLM_BASE_URL — Background memory LLM endpoint\n// MEMORIX_AGENT_API_KEY — TUI/chat coding agent API key\n// MEMORIX_AGENT_BASE_URL — TUI/chat coding agent endpoint\n// MEMORIX_AGENT_LLM_API_KEY — Legacy alias for MEMORIX_AGENT_API_KEY\n// MEMORIX_AGENT_LLM_BASE_URL — Legacy alias for MEMORIX_AGENT_BASE_URL\n// MEMORIX_EMBEDDING_API_KEY — Embedding/vector API key\n// MEMORIX_EMBEDDING_BASE_URL — Custom embedding endpoint\n// MEMORIX_API_KEY — Memory LLM simple key (not used for embedding or agent)\n// OPENAI_API_KEY — OpenAI compatibility fallback\n// ANTHROPIC_API_KEY — Anthropic compatibility fallback\n// OPENROUTER_API_KEY — OpenRouter compatibility fallback\n","/**\n * memorix.yml Configuration Loader\n *\n * Loads YAML configuration from project-level and user-level paths.\n * This is the platform-grade config format — Memorix as a central hub,\n * not just an MCP plugin.\n *\n * Priority chain (highest wins):\n * 1. Environment variables\n * 2. ./memorix.yml (project-level, in project root)\n * 3. ~/.memorix/memorix.yml (user-level, global defaults)\n * 4. ~/.memorix/config.json (legacy, backward compat)\n * 5. Hardcoded defaults\n *\n * Inspired by: Cipher's cipher.yml, Docker's docker-compose.yml\n */\n\nimport { existsSync, readFileSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { createRequire } from 'node:module';\nimport { getGlobalYamlPath, getProjectYamlPath } from './config-paths.js';\n\n// ─── Types ───────────────────────────────────────────────────────────\n\nexport interface MemorixYamlConfig {\n /** LLM provider configuration */\n llm?: {\n provider?: 'openai' | 'anthropic' | 'openrouter' | string;\n model?: string;\n apiKey?: string;\n baseUrl?: string;\n };\n\n /** TUI / chat agent LLM provider configuration */\n agent?: {\n provider?: 'openai' | 'anthropic' | 'openrouter' | string;\n model?: string;\n apiKey?: string;\n baseUrl?: string;\n };\n\n /** Embedding / vector search configuration */\n embedding?: {\n provider?: 'off' | 'api' | 'fastembed' | 'transformers' | 'auto';\n model?: string;\n apiKey?: string;\n baseUrl?: string;\n dimensions?: number;\n };\n\n /** Git-Memory pipeline configuration */\n git?: {\n /** Auto-install post-commit hook on first run (default: false) */\n autoHook?: boolean;\n /** Ingest commits as memories on post-commit (default: true when hook installed) */\n ingestOnCommit?: boolean;\n /** Maximum diff size (chars) to include in memory (default: 500) */\n maxDiffSize?: number;\n /** Skip merge commits (default: true) */\n skipMergeCommits?: boolean;\n /** File patterns to exclude from git memory (glob) */\n excludePatterns?: string[];\n /** Additional commit message phrases to treat as noise (literal, case-insensitive) */\n noiseKeywords?: string[];\n };\n\n /** CodeGraph / Project Context configuration */\n codegraph?: {\n /** File patterns to exclude from CodeGraph indexing and context suggestions */\n excludePatterns?: string[];\n /** Maximum source file size to parse into CodeGraph Memory */\n maxFileBytes?: number;\n /** Use a healthy pre-existing local CodeGraph index when present (default: auto). */\n externalContext?: 'auto' | 'off';\n /** Optional CodeGraph executable path when it is not available on PATH. */\n externalCommand?: string;\n /** Bound for one local semantic context request. */\n externalTimeoutMs?: number;\n };\n\n /** Behavior settings */\n behavior?: {\n /** Session start injection mode */\n sessionInject?: 'full' | 'minimal' | 'silent';\n /** Show sync advisory on first search */\n syncAdvisory?: boolean;\n /** Auto-archive expired memories on startup */\n autoCleanup?: boolean;\n /** Formation Pipeline mode */\n formationMode?: 'active' | 'shadow' | 'fallback';\n };\n\n /** MCP server mode configuration (when Memorix runs as hub) */\n server?: {\n /** Transport: stdio (default) or http */\n transport?: 'stdio' | 'http';\n /** HTTP port (only for http transport) */\n port?: number;\n /** Enable Web Dashboard */\n dashboard?: boolean;\n /** Dashboard port (default: 3210) */\n dashboardPort?: number;\n };\n\n /** Orchestration coordination settings */\n team?: {\n /** Enable orchestration coordination features */\n enabled?: boolean;\n /** Shared workspace memory collection */\n workspaceCollection?: string;\n };\n\n /** Additional MCP servers to aggregate (Memorix as hub) */\n mcpServers?: Record<string, {\n type?: 'stdio' | 'sse';\n command?: string;\n args?: string[];\n env?: Record<string, string>;\n url?: string;\n }>;\n}\n\n// ─── Loader ──────────────────────────────────────────────────────────\n\n// Per-project config cache — keyed by resolved projectRoot string.\n// null key = user-level-only config (no project root).\nconst configCache = new Map<string | null, MemorixYamlConfig>();\nconst require = createRequire(import.meta.url);\n\n/** Stored project root — set once by server init, used by all no-arg loadYamlConfig() calls */\nlet globalProjectRoot: string | null = null;\n\n/**\n * Set the project root for YAML config resolution.\n * Call this once during server init so all config getters\n * (which call loadYamlConfig() without args) pick up project-level memorix.yml.\n *\n * In HTTP mode, this is called per-session/switchProject — the Map cache\n * preserves configs for all projects simultaneously.\n */\nexport function initProjectRoot(root: string): void {\n globalProjectRoot = root;\n // Invalidate this project's cache entry so file changes are picked up\n configCache.delete(root);\n}\n\n/**\n * Clear the global project root used by no-arg loadYamlConfig().\n * Useful when a long-lived process switches to a project whose root is unknown.\n */\nexport function clearProjectRoot(): void {\n globalProjectRoot = null;\n}\n\n/**\n * Load memorix.yml from project root and/or user home.\n * Project-level overrides user-level (shallow merge per top-level key).\n */\nexport function loadYamlConfig(projectRoot?: string | null): MemorixYamlConfig {\n // When null is explicitly passed, skip global fallback (user-level config only).\n // When undefined (no arg), fall back to globally-initialized project root.\n const resolvedRoot = projectRoot === null ? null : (projectRoot ?? globalProjectRoot ?? null);\n\n // Per-project cache hit\n const cached = configCache.get(resolvedRoot ?? null);\n if (cached) return cached;\n\n const userYaml = getGlobalYamlPath(homedir());\n const projectYaml = resolvedRoot ? getProjectYamlPath(resolvedRoot) : null;\n\n let userConfig: MemorixYamlConfig = {};\n let projectConfig: MemorixYamlConfig = {};\n\n // Load user-level config\n if (existsSync(userYaml)) {\n try {\n userConfig = parseYaml(readFileSync(userYaml, 'utf-8'));\n } catch (err) {\n console.error(`[memorix] Warning: Failed to parse ${userYaml}: ${err}`);\n }\n }\n\n // Load project-level config (overrides user-level)\n if (projectYaml && existsSync(projectYaml)) {\n try {\n projectConfig = parseYaml(readFileSync(projectYaml, 'utf-8'));\n } catch (err) {\n console.error(`[memorix] Warning: Failed to parse ${projectYaml}: ${err}`);\n }\n }\n\n // Shallow merge: project-level top keys override user-level\n const merged: MemorixYamlConfig = {\n ...userConfig,\n ...projectConfig,\n // Deep merge for nested objects where both exist\n llm: { ...userConfig.llm, ...projectConfig.llm },\n agent: { ...userConfig.agent, ...projectConfig.agent },\n embedding: { ...userConfig.embedding, ...projectConfig.embedding },\n git: { ...userConfig.git, ...projectConfig.git },\n codegraph: { ...userConfig.codegraph, ...projectConfig.codegraph },\n behavior: { ...userConfig.behavior, ...projectConfig.behavior },\n server: { ...userConfig.server, ...projectConfig.server },\n team: { ...userConfig.team, ...projectConfig.team },\n };\n configCache.set(resolvedRoot ?? null, merged);\n\n return merged;\n}\n\n/**\n * Reset cached YAML config (for testing or project switching).\n * Invalidates all cached entries, or a specific projectRoot if provided.\n */\nexport function resetYamlConfigCache(projectRoot?: string | null): void {\n if (projectRoot !== undefined) {\n configCache.delete(projectRoot ?? null);\n } else {\n configCache.clear();\n }\n}\n\n/**\n * Parse YAML string using gray-matter's internal js-yaml.\n * gray-matter is already a dependency — no new deps needed.\n */\nfunction parseYaml(content: string): MemorixYamlConfig {\n // gray-matter uses js-yaml internally; we import it from there\n // But for simplicity and reliability, use a basic YAML parser\n // that handles the flat config structure we need.\n try {\n const yaml = require('js-yaml');\n return yaml.load(content) as MemorixYamlConfig ?? {};\n } catch {\n // Fallback: try gray-matter which wraps js-yaml\n try {\n const matter = require('gray-matter');\n const parsed = matter(`---\\n${content}\\n---`);\n return (parsed.data as MemorixYamlConfig) ?? {};\n } catch {\n console.error('[memorix] YAML parse failed — check memorix.yml syntax');\n return {};\n }\n }\n}\n","/**\n * Project Detector\n *\n * Strict .git-based project detection.\n * No .git = not a project. No fallbacks, no accommodations.\n *\n * ID strategy:\n * - .git + remote → normalizeGitRemote(remote) (globally unique, e.g. \"user/repo\")\n * - .git + no remote → \"local/<dirname>\" (local git repo, no remote yet)\n * - no .git → null (not a project)\n */\n\nimport { execSync } from 'node:child_process';\nimport { existsSync, readFileSync, readdirSync, statSync } from 'node:fs';\nimport path from 'node:path';\nimport type { ProjectInfo, DetectionResult, DetectionFailure } from '../types.js';\n\n/**\n * Detect the current project identity from Git.\n * Returns null if no .git directory is found — caller must handle this.\n * @param cwd - Working directory to detect from (defaults to process.cwd())\n */\nexport function detectProject(cwd?: string): ProjectInfo | null {\n return detectProjectWithDiagnostics(cwd).project;\n}\n\n/**\n * Detect project with full diagnostic info.\n * Returns both the project (if found) and a failure descriptor (if not).\n * Callers can use failure.reason to produce actionable error messages.\n */\nexport function detectProjectWithDiagnostics(cwd?: string): DetectionResult {\n const basePath = cwd ?? process.cwd();\n\n // Check: does the path exist?\n if (!existsSync(basePath)) {\n return {\n project: null,\n failure: { reason: 'path_not_found', path: basePath, detail: `Path does not exist: \"${basePath}\"` },\n };\n }\n\n // Check: is it a directory?\n try {\n if (!statSync(basePath).isDirectory()) {\n return {\n project: null,\n failure: { reason: 'not_a_directory', path: basePath, detail: `Path is not a directory: \"${basePath}\"` },\n };\n }\n } catch {\n return {\n project: null,\n failure: { reason: 'path_not_found', path: basePath, detail: `Cannot stat path: \"${basePath}\"` },\n };\n }\n\n // Check: git root\n const gitRootResult = getGitRootWithDiagnostics(basePath);\n if (!gitRootResult.root) {\n return {\n project: null,\n failure: gitRootResult.failure ?? {\n reason: 'no_git',\n path: basePath,\n detail: `No .git directory found in \"${basePath}\" or any parent directory.`,\n },\n };\n }\n\n const gitRoot = gitRootResult.root;\n const gitRemote = getGitRemote(gitRoot);\n\n if (gitRemote) {\n const id = normalizeGitRemote(gitRemote);\n const name = id.split('/').pop() ?? path.basename(gitRoot);\n return { project: { id, name, gitRemote, rootPath: gitRoot }, failure: null };\n }\n\n // Git repo without remote — local-only project\n const name = path.basename(gitRoot);\n const id = `local/${name}`;\n return { project: { id, name, rootPath: gitRoot }, failure: null };\n}\n\n/**\n * Get the Git repository root directory.\n * Returns null if not inside a git repository.\n */\nfunction getGitRoot(cwd: string): string | null {\n return getGitRootWithDiagnostics(cwd).root;\n}\n\n/**\n * Get git root with diagnostic failure info.\n * Distinguishes: no_git, git_worktree_error, git_safe_directory.\n */\nfunction getGitRootWithDiagnostics(cwd: string): { root: string | null; failure: DetectionFailure | null } {\n // Fast path: walk up to find .git directory (instant, no subprocess)\n let dir = path.resolve(cwd);\n const fsRoot = path.parse(dir).root;\n while (dir !== fsRoot) {\n const gitPath = path.join(dir, '.git');\n if (existsSync(gitPath)) {\n // .git may be a file (worktree) or directory (normal repo)\n try {\n const st = statSync(gitPath);\n if (st.isDirectory() || st.isFile()) return { root: dir, failure: null };\n } catch {\n return {\n root: null,\n failure: {\n reason: 'git_worktree_error',\n path: cwd,\n detail: `Found .git at \"${gitPath}\" but cannot stat it (permission denied or broken worktree link).`,\n },\n };\n }\n }\n dir = path.dirname(dir);\n }\n\n // Slow path: git CLI for edge cases (submodules, worktrees, bare repos)\n try {\n const root = execSync('git -c safe.directory=* rev-parse --show-toplevel', {\n cwd,\n encoding: 'utf-8',\n stdio: ['pipe', 'pipe', 'pipe'],\n timeout: 5000,\n }).trim();\n return root ? { root, failure: null } : { root: null, failure: null };\n } catch (err) {\n // Inspect stderr for known git error patterns\n const msg = err instanceof Error ? err.message : String(err);\n if (msg.includes('safe.directory') || msg.includes('dubious ownership')) {\n return {\n root: null,\n failure: {\n reason: 'git_safe_directory',\n path: cwd,\n detail: `Git refuses to operate in \"${cwd}\" due to ownership/safe.directory restrictions. ` +\n 'Run: git config --global --add safe.directory \"' + cwd + '\"',\n },\n };\n }\n return {\n root: null,\n failure: { reason: 'no_git', path: cwd, detail: `No git repository found at \"${cwd}\" or any parent directory.` },\n };\n }\n}\n\n/**\n * Get the Git remote URL for the given directory.\n * Returns null if not a git repository or no remote configured.\n */\nfunction getGitRemote(cwd: string): string | null {\n // Fast path: read .git/config directly (instant, no subprocess)\n const fsRemote = readGitConfigRemote(cwd);\n if (fsRemote) return fsRemote;\n\n // Slow path: git CLI for edge cases (submodules, worktrees, non-standard layouts)\n try {\n const remote = execSync('git -c safe.directory=* remote get-url origin', {\n cwd,\n encoding: 'utf-8',\n stdio: ['pipe', 'pipe', 'pipe'],\n timeout: 5000,\n }).trim();\n return remote || null;\n } catch {\n return null;\n }\n}\n\n/**\n * Fallback: parse remote.origin.url from .git/config when git CLI fails.\n * Handles Windows \"dubious ownership\" and other permission issues.\n */\nfunction readGitConfigRemote(cwd: string): string | null {\n try {\n const configPath = path.join(cwd, '.git', 'config');\n if (!existsSync(configPath)) return null;\n const content = readFileSync(configPath, 'utf-8');\n // Parse INI-style: [remote \"origin\"] section, url = ...\n const remoteMatch = content.match(/\\[remote\\s+\"origin\"\\]([\\s\\S]*?)(?=\\n\\[|$)/);\n if (!remoteMatch) return null;\n const urlMatch = remoteMatch[1].match(/^\\s*url\\s*=\\s*(.+)$/m);\n return urlMatch ? urlMatch[1].trim() : null;\n } catch {\n return null;\n }\n}\n\n/**\n * Detect if a directory is a \"system directory\" that's clearly not a user workspace.\n * These include Windows system dirs, IDE installation dirs, and temp dirs.\n */\nexport function isSystemDirectory(dir: string): boolean {\n const lower = dir.toLowerCase().replace(/\\\\/g, '/');\n return (\n lower.includes('/windows/') || lower.endsWith('/windows') ||\n lower.includes('/program files') ||\n lower.includes('/appdata/') ||\n // IDE installation directories\n /\\/(windsurf|cursor|code|vscode)\\/\\1/i.test(lower) ||\n /\\/windsurf\\b/i.test(lower) && !lower.includes('.windsurf') ||\n // Node / npm internal paths\n lower.includes('/node_modules/') ||\n lower.includes('/nvm') ||\n // System root\n /^[a-z]:\\/$/i.test(lower)\n );\n}\n\n/**\n * Scan immediate subdirectories for a .git directory.\n * Used when the workspace root itself isn't a git repo (multi-project workspace).\n * Returns the first subdirectory containing .git, or null.\n */\nexport function findGitInSubdirs(dir: string): string | null {\n try {\n const resolved = path.resolve(dir);\n const entries = readdirSync(resolved);\n for (const entry of entries) {\n if (entry.startsWith('.')) continue; // skip hidden dirs\n const fullPath = path.join(resolved, entry);\n try {\n if (statSync(fullPath).isDirectory() && existsSync(path.join(fullPath, '.git'))) {\n return fullPath;\n }\n } catch { /* permission error, skip */ }\n }\n } catch { /* readdir failed */ }\n return null;\n}\n\n/**\n * Normalize a Git remote URL to a consistent project ID.\n *\n * Examples:\n * https://github.com/user/repo.git → user/repo\n * git@github.com:user/repo.git → user/repo\n * ssh://git@github.com/user/repo → user/repo\n */\nfunction normalizeGitRemote(remote: string): string {\n let normalized = remote;\n\n // Remove trailing .git\n normalized = normalized.replace(/\\.git$/, '');\n\n // Handle SSH format: git@github.com:user/repo\n const sshMatch = normalized.match(/^[\\w-]+@[\\w.-]+:(.+)$/);\n if (sshMatch) {\n return sshMatch[1];\n }\n\n // Handle HTTPS/SSH URL format\n try {\n const url = new URL(normalized);\n // Remove leading slash\n return url.pathname.replace(/^\\//, '');\n } catch {\n // If URL parsing fails, take last two segments\n const segments = normalized.split('/').filter(Boolean);\n return segments.slice(-2).join('/');\n }\n}\n","import { existsSync, readFileSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { getLegacyConfigJsonPath } from './config-paths.js';\n\nexport interface MemorixConfig {\n llm?: {\n provider?: string;\n apiKey?: string;\n model?: string;\n baseUrl?: string;\n };\n agent?: {\n provider?: string;\n apiKey?: string;\n model?: string;\n baseUrl?: string;\n };\n embedding?: string;\n embeddingApi?: {\n apiKey?: string;\n baseUrl?: string;\n model?: string;\n dimensions?: number;\n };\n}\n\nlet cachedConfig: MemorixConfig | null = null;\n\nexport function loadFileConfig(): MemorixConfig {\n if (cachedConfig !== null) return cachedConfig;\n\n const configPath = getLegacyConfigJsonPath(homedir());\n try {\n if (existsSync(configPath)) {\n cachedConfig = JSON.parse(readFileSync(configPath, 'utf-8'));\n return cachedConfig!;\n }\n } catch {\n // Corrupt or unreadable legacy config should not block startup.\n }\n cachedConfig = {};\n return cachedConfig;\n}\n\nexport function resetConfigCache(): void {\n cachedConfig = null;\n}\n","import { existsSync, readFileSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { getGlobalConfigTomlPath, getProjectConfigTomlPath } from './config-paths.js';\n\nexport interface MemorixTomlConfig {\n agent?: {\n provider?: string;\n model?: string;\n base_url?: string;\n api_key?: string;\n };\n memory?: {\n inject?: 'full' | 'minimal' | 'silent';\n formation?: 'active' | 'shadow' | 'fallback';\n auto_cleanup?: boolean;\n sync_advisory?: boolean;\n llm?: {\n provider?: string;\n model?: string;\n base_url?: string;\n api_key?: string;\n };\n };\n embedding?: {\n provider?: 'off' | 'api' | 'fastembed' | 'transformers' | 'auto' | string;\n model?: string;\n base_url?: string;\n api_key?: string;\n dimensions?: number;\n };\n hooks?: {\n native_memcode?: boolean;\n external_agents?: boolean;\n };\n git?: {\n auto_hook?: boolean;\n ingest_on_commit?: boolean;\n max_diff_size?: number;\n skip_merge_commits?: boolean;\n exclude_patterns?: string[];\n noise_keywords?: string[];\n };\n codegraph?: {\n exclude_patterns?: string[];\n max_file_bytes?: number;\n external_context?: 'auto' | 'off';\n external_command?: string;\n external_timeout_ms?: number;\n };\n server?: {\n transport?: 'stdio' | 'http';\n dashboard?: boolean;\n dashboard_port?: number;\n port?: number;\n };\n}\n\ninterface LoadTomlOptions {\n projectRoot?: string | null;\n homeDir?: string;\n}\n\nconst configCache = new Map<string, MemorixTomlConfig>();\n\nexport function loadTomlConfig(options: LoadTomlOptions = {}): MemorixTomlConfig {\n const homeDir = options.homeDir ?? homedir();\n const projectRoot = options.projectRoot ?? null;\n const cacheKey = `${homeDir}\\0${projectRoot ?? ''}`;\n const cached = configCache.get(cacheKey);\n if (cached) return cached;\n\n const userToml = getGlobalConfigTomlPath(homeDir);\n const projectToml = projectRoot ? getProjectConfigTomlPath(projectRoot) : null;\n\n const userConfig = existsSync(userToml) ? parseTomlConfig(readFileSync(userToml, 'utf8'), userToml) : {};\n const projectConfig = projectToml && existsSync(projectToml)\n ? parseTomlConfig(readFileSync(projectToml, 'utf8'), projectToml)\n : {};\n\n const merged = mergeTomlConfig(userConfig, projectConfig);\n configCache.set(cacheKey, merged);\n return merged;\n}\n\nexport function resetTomlConfigCache(): void {\n configCache.clear();\n}\n\nfunction mergeTomlConfig(base: MemorixTomlConfig, override: MemorixTomlConfig): MemorixTomlConfig {\n return {\n ...base,\n ...override,\n agent: { ...base.agent, ...override.agent },\n memory: {\n ...base.memory,\n ...override.memory,\n llm: { ...base.memory?.llm, ...override.memory?.llm },\n },\n embedding: { ...base.embedding, ...override.embedding },\n hooks: { ...base.hooks, ...override.hooks },\n git: { ...base.git, ...override.git },\n codegraph: { ...base.codegraph, ...override.codegraph },\n server: { ...base.server, ...override.server },\n };\n}\n\nfunction parseTomlConfig(content: string, filePath: string): MemorixTomlConfig {\n const root: Record<string, unknown> = {};\n let current: Record<string, unknown> = root;\n\n for (const [index, rawLine] of content.split(/\\r?\\n/).entries()) {\n const line = stripComment(rawLine).trim();\n if (!line) continue;\n\n const tableMatch = line.match(/^\\[([A-Za-z0-9_.-]+)\\]$/);\n if (tableMatch) {\n current = ensureTable(root, tableMatch[1].split('.'));\n continue;\n }\n\n const assignment = line.match(/^([A-Za-z0-9_-]+)\\s*=\\s*(.+)$/);\n if (!assignment) {\n throw new Error(`Invalid TOML syntax in ${filePath}:${index + 1}`);\n }\n current[assignment[1]] = parseTomlValue(assignment[2].trim(), filePath, index + 1);\n }\n\n return root as MemorixTomlConfig;\n}\n\nfunction ensureTable(root: Record<string, unknown>, path: string[]): Record<string, unknown> {\n let cursor = root;\n for (const part of path) {\n const value = cursor[part];\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n cursor[part] = {};\n }\n cursor = cursor[part] as Record<string, unknown>;\n }\n return cursor;\n}\n\nfunction parseTomlValue(raw: string, filePath: string, line: number): unknown {\n if (raw.startsWith('\"') && raw.endsWith('\"')) {\n return raw.slice(1, -1).replace(/\\\\\"/g, '\"').replace(/\\\\\\\\/g, '\\\\');\n }\n if (raw.startsWith(\"'\") && raw.endsWith(\"'\")) {\n return raw.slice(1, -1);\n }\n if (raw === 'true') return true;\n if (raw === 'false') return false;\n if (/^-?\\d+$/.test(raw)) return Number.parseInt(raw, 10);\n if (/^-?\\d+\\.\\d+$/.test(raw)) return Number.parseFloat(raw);\n if (raw.startsWith('[') && raw.endsWith(']')) {\n const body = raw.slice(1, -1).trim();\n if (!body) return [];\n return body.split(',').map((entry) => parseTomlValue(entry.trim(), filePath, line));\n }\n throw new Error(`Unsupported TOML value in ${filePath}:${line}`);\n}\n\nfunction stripComment(line: string): string {\n let quote: '\"' | \"'\" | null = null;\n let escaped = false;\n for (let i = 0; i < line.length; i++) {\n const char = line[i];\n if (escaped) {\n escaped = false;\n continue;\n }\n if (char === '\\\\' && quote === '\"') {\n escaped = true;\n continue;\n }\n if (char === '\"' || char === \"'\") {\n if (quote === char) quote = null;\n else if (quote === null) quote = char;\n continue;\n }\n if (char === '#' && quote === null) {\n return line.slice(0, i);\n }\n }\n return line;\n}\n","import { homedir } from 'node:os';\nimport { existsSync } from 'node:fs';\nimport { detectProject } from '../project/detector.js';\nimport {\n getGlobalConfigTomlPath,\n getGlobalYamlPath,\n getLegacyConfigJsonPath,\n getProjectConfigTomlPath,\n getProjectYamlPath,\n} from './config-paths.js';\nimport { loadFileConfig } from './legacy-loader.js';\nimport { loadTomlConfig } from './toml-loader.js';\nimport { loadYamlConfig } from './yaml-loader.js';\nimport { loadDotenv } from './dotenv-loader.js';\n\nexport interface ResolvedLaneOptions {\n projectRoot?: string | null;\n homeDir?: string;\n}\n\nexport interface ResolvedMemorixConfig {\n agent: {\n provider?: string;\n model?: string;\n baseUrl?: string;\n apiKey?: string;\n };\n memory: {\n inject?: 'full' | 'minimal' | 'silent';\n formation?: 'active' | 'shadow' | 'fallback';\n autoCleanup?: boolean;\n syncAdvisory?: boolean;\n llm: {\n provider?: string;\n model?: string;\n baseUrl?: string;\n apiKey?: string;\n };\n };\n embedding: {\n provider?: 'off' | 'fastembed' | 'transformers' | 'api' | 'auto' | string;\n model?: string;\n baseUrl?: string;\n apiKey?: string;\n dimensions?: number;\n };\n git: {\n autoHook?: boolean;\n ingestOnCommit?: boolean;\n maxDiffSize?: number;\n skipMergeCommits?: boolean;\n excludePatterns?: string[];\n noiseKeywords?: string[];\n };\n codegraph: {\n excludePatterns?: string[];\n maxFileBytes?: number;\n externalContext: 'auto' | 'off';\n externalCommand?: string;\n externalTimeoutMs?: number;\n };\n server: {\n transport?: 'stdio' | 'http';\n dashboard?: boolean;\n dashboardPort?: number;\n port?: number;\n };\n sources: {\n toml: string[];\n legacy: string[];\n env: string[];\n };\n}\n\nexport function getResolvedConfig(options: ResolvedLaneOptions = {}): ResolvedMemorixConfig {\n const homeDir = options.homeDir ?? homedir();\n const projectRoot = options.projectRoot === undefined ? detectProject()?.rootPath ?? null : options.projectRoot;\n\n // Make .env a first-class config source so every consumer of this resolved\n // config (embedding API key, LLM base URL, etc.) sees values from\n // ~/.memorix/.env / <project>/.env. loadDotenv() is idempotent — guarded by\n // a module-level `dotenvLoaded` flag — so repeat calls within one process\n // are essentially free, and it never overrides an already-set process env.\n loadDotenv(projectRoot === null ? undefined : projectRoot ?? undefined, { userHomeDir: homeDir });\n\n const toml = loadTomlConfig({ projectRoot: projectRoot ?? null, homeDir });\n const yaml = loadYamlConfig(projectRoot ?? null);\n const legacy = loadFileConfig();\n const embeddingBaseUrl = first(process.env.MEMORIX_EMBEDDING_BASE_URL, toml.embedding?.base_url, yaml.embedding?.baseUrl, legacy.embeddingApi?.baseUrl);\n const openRouterEmbeddingApiKey = isOpenRouterUrl(embeddingBaseUrl) ? process.env.OPENROUTER_API_KEY : undefined;\n const memoryLlmProvider = first(\n process.env.MEMORIX_LLM_PROVIDER,\n toml.memory?.llm?.provider,\n yaml.llm?.provider,\n legacy.llm?.provider,\n );\n const memoryLlmModel = first(\n process.env.MEMORIX_LLM_MODEL,\n toml.memory?.llm?.model,\n yaml.llm?.model,\n legacy.llm?.model,\n );\n const memoryLlmBaseUrl = first(\n process.env.MEMORIX_LLM_BASE_URL,\n toml.memory?.llm?.base_url,\n yaml.llm?.baseUrl,\n legacy.llm?.baseUrl,\n );\n const openRouterMemoryLlmApiKey = isOpenRouterMemoryLane(memoryLlmProvider, memoryLlmBaseUrl)\n ? process.env.OPENROUTER_API_KEY\n : undefined;\n\n const resolved: ResolvedMemorixConfig = {\n agent: {\n provider: first(\n process.env.MEMORIX_AGENT_PROVIDER,\n process.env.MEMORIX_AGENT_LLM_PROVIDER,\n toml.agent?.provider,\n yaml.agent?.provider,\n legacy.agent?.provider,\n ),\n model: first(\n process.env.MEMORIX_AGENT_MODEL,\n process.env.MEMORIX_AGENT_LLM_MODEL,\n toml.agent?.model,\n yaml.agent?.model,\n legacy.agent?.model,\n ),\n baseUrl: first(\n process.env.MEMORIX_AGENT_BASE_URL,\n process.env.MEMORIX_AGENT_LLM_BASE_URL,\n toml.agent?.base_url,\n yaml.agent?.baseUrl,\n legacy.agent?.baseUrl,\n ),\n apiKey: first(\n process.env.MEMORIX_AGENT_API_KEY,\n process.env.MEMORIX_AGENT_LLM_API_KEY,\n toml.agent?.api_key,\n yaml.agent?.apiKey,\n legacy.agent?.apiKey,\n ),\n },\n memory: {\n inject: first(toml.memory?.inject, yaml.behavior?.sessionInject),\n formation: first(toml.memory?.formation, yaml.behavior?.formationMode),\n autoCleanup: firstBool(toml.memory?.auto_cleanup, yaml.behavior?.autoCleanup),\n syncAdvisory: firstBool(toml.memory?.sync_advisory, yaml.behavior?.syncAdvisory),\n llm: {\n provider: memoryLlmProvider,\n model: memoryLlmModel,\n baseUrl: memoryLlmBaseUrl,\n apiKey: first(\n process.env.MEMORIX_LLM_API_KEY,\n process.env.MEMORIX_API_KEY,\n toml.memory?.llm?.api_key,\n yaml.llm?.apiKey,\n legacy.llm?.apiKey,\n process.env.OPENAI_API_KEY,\n process.env.ANTHROPIC_API_KEY,\n openRouterMemoryLlmApiKey,\n ),\n },\n },\n embedding: {\n provider: first(process.env.MEMORIX_EMBEDDING, toml.embedding?.provider, yaml.embedding?.provider, legacy.embedding, 'off'),\n model: first(process.env.MEMORIX_EMBEDDING_MODEL, toml.embedding?.model, yaml.embedding?.model, legacy.embeddingApi?.model),\n baseUrl: embeddingBaseUrl,\n apiKey: first(process.env.MEMORIX_EMBEDDING_API_KEY, toml.embedding?.api_key, yaml.embedding?.apiKey, legacy.embeddingApi?.apiKey, openRouterEmbeddingApiKey),\n dimensions: firstNumber(parseNumber(process.env.MEMORIX_EMBEDDING_DIMENSIONS), toml.embedding?.dimensions, yaml.embedding?.dimensions, legacy.embeddingApi?.dimensions),\n },\n git: {\n autoHook: firstBool(toml.git?.auto_hook, yaml.git?.autoHook),\n ingestOnCommit: firstBool(toml.git?.ingest_on_commit, yaml.git?.ingestOnCommit),\n maxDiffSize: firstNumber(toml.git?.max_diff_size, yaml.git?.maxDiffSize),\n skipMergeCommits: firstBool(toml.git?.skip_merge_commits, yaml.git?.skipMergeCommits),\n excludePatterns: firstArray(toml.git?.exclude_patterns, yaml.git?.excludePatterns),\n noiseKeywords: firstArray(toml.git?.noise_keywords, yaml.git?.noiseKeywords),\n },\n codegraph: {\n excludePatterns: firstArray(toml.codegraph?.exclude_patterns, yaml.codegraph?.excludePatterns),\n maxFileBytes: firstNumber(toml.codegraph?.max_file_bytes, yaml.codegraph?.maxFileBytes),\n externalContext: first(\n normalizeExternalContext(process.env.MEMORIX_CODEGRAPH_EXTERNAL_CONTEXT),\n toml.codegraph?.external_context,\n yaml.codegraph?.externalContext,\n 'auto',\n )!,\n externalCommand: first(\n process.env.MEMORIX_CODEGRAPH_EXTERNAL_COMMAND,\n toml.codegraph?.external_command,\n yaml.codegraph?.externalCommand,\n ),\n externalTimeoutMs: firstNumber(\n parseNumber(process.env.MEMORIX_CODEGRAPH_EXTERNAL_TIMEOUT_MS),\n toml.codegraph?.external_timeout_ms,\n yaml.codegraph?.externalTimeoutMs,\n ),\n },\n server: {\n transport: first(toml.server?.transport, yaml.server?.transport),\n dashboard: firstBool(toml.server?.dashboard, yaml.server?.dashboard),\n dashboardPort: firstNumber(toml.server?.dashboard_port, yaml.server?.dashboardPort),\n port: firstNumber(toml.server?.port, yaml.server?.port),\n },\n sources: {\n toml: getExistingConfigSources([\n getGlobalConfigTomlPath(homeDir),\n ...(projectRoot ? [getProjectConfigTomlPath(projectRoot)] : []),\n ]),\n legacy: getExistingConfigSources([\n getGlobalYamlPath(homeDir),\n ...(projectRoot ? [getProjectYamlPath(projectRoot)] : []),\n getLegacyConfigJsonPath(homeDir),\n ]),\n env: getEnvSourceNames(),\n },\n };\n\n return resolved;\n}\n\nexport function getResolvedConfigForCwd(cwd = process.cwd()): ResolvedMemorixConfig {\n const project = detectProject(cwd);\n return getResolvedConfig({ projectRoot: project?.rootPath ?? null });\n}\n\nexport function getResolvedAgentLane(options: ResolvedLaneOptions = {}): ResolvedMemorixConfig['agent'] {\n const resolved = getResolvedConfig(options);\n return {\n ...resolved.agent,\n provider: resolved.agent.provider ?? resolved.memory.llm.provider,\n model: resolved.agent.model ?? resolved.memory.llm.model,\n baseUrl: resolved.agent.baseUrl ?? resolved.memory.llm.baseUrl,\n apiKey: resolved.agent.apiKey ?? resolved.memory.llm.apiKey,\n };\n}\n\nexport function getResolvedMemoryLane(options: ResolvedLaneOptions = {}): ResolvedMemorixConfig['memory'] {\n return getResolvedConfig(options).memory;\n}\n\nexport function getResolvedEmbeddingLane(options: ResolvedLaneOptions = {}): ResolvedMemorixConfig['embedding'] {\n return getResolvedConfig(options).embedding;\n}\n\nexport function resetResolvedConfigCache(): void {\n // Kept as a public test helper. File-level caches live in individual loaders.\n}\n\nfunction first<T>(...values: Array<T | null | undefined | ''>): T | undefined {\n return values.find((value): value is T => value !== undefined && value !== null && value !== '');\n}\n\nfunction firstBool(...values: Array<boolean | undefined>): boolean | undefined {\n return values.find((value): value is boolean => value !== undefined);\n}\n\nfunction firstNumber(...values: Array<number | undefined | null>): number | undefined {\n return values.find((value): value is number => value !== undefined && value !== null && Number.isFinite(value));\n}\n\nfunction firstArray<T>(...values: Array<T[] | undefined>): T[] | undefined {\n return values.find((value): value is T[] => Array.isArray(value));\n}\n\nfunction parseNumber(value: string | undefined): number | undefined {\n if (!value) return undefined;\n const parsed = Number.parseInt(value, 10);\n return Number.isFinite(parsed) ? parsed : undefined;\n}\n\nfunction getExistingConfigSources(paths: string[]): string[] {\n return paths.filter((filePath) => existsSync(filePath));\n}\n\nfunction getEnvSourceNames(): string[] {\n return [\n 'MEMORIX_AGENT_PROVIDER',\n 'MEMORIX_AGENT_MODEL',\n 'MEMORIX_AGENT_API_KEY',\n 'MEMORIX_AGENT_BASE_URL',\n 'MEMORIX_AGENT_LLM_PROVIDER',\n 'MEMORIX_AGENT_LLM_MODEL',\n 'MEMORIX_AGENT_LLM_API_KEY',\n 'MEMORIX_AGENT_LLM_BASE_URL',\n 'MEMORIX_LLM_PROVIDER',\n 'MEMORIX_LLM_MODEL',\n 'MEMORIX_LLM_API_KEY',\n 'MEMORIX_LLM_BASE_URL',\n 'MEMORIX_API_KEY',\n 'MEMORIX_EMBEDDING',\n 'MEMORIX_EMBEDDING_API_KEY',\n 'MEMORIX_EMBEDDING_BASE_URL',\n 'MEMORIX_EMBEDDING_MODEL',\n 'MEMORIX_EMBEDDING_DIMENSIONS',\n 'MEMORIX_CODEGRAPH_EXTERNAL_CONTEXT',\n 'MEMORIX_CODEGRAPH_EXTERNAL_COMMAND',\n 'MEMORIX_CODEGRAPH_EXTERNAL_TIMEOUT_MS',\n 'OPENROUTER_API_KEY',\n ].filter((name) => process.env[name]);\n}\n\nfunction isOpenRouterUrl(value: string | undefined): boolean {\n if (!value) return false;\n try {\n const url = new URL(value);\n return url.hostname.toLowerCase() === 'openrouter.ai' || url.hostname.toLowerCase().endsWith('.openrouter.ai');\n } catch {\n return /(^|\\.)openrouter\\.ai(?::|\\/|$)/i.test(value);\n }\n}\n\nfunction isOpenRouterMemoryLane(provider: string | undefined, baseUrl: string | undefined): boolean {\n return provider?.trim().toLowerCase() === 'openrouter' || isOpenRouterUrl(baseUrl);\n}\n\nfunction normalizeExternalContext(value: string | undefined): 'auto' | 'off' | undefined {\n const normalized = value?.trim().toLowerCase();\n if (normalized === 'auto' || normalized === 'off') return normalized;\n return undefined;\n}\n","/**\n * Unified Configuration Reader\n *\n * Priority chain (highest wins):\n * 1. Environment variables (from MCP JSON `env` field or system env)\n * 2. memorix.toml / ~/.memorix/config.toml\n * 3. memorix.yml / ~/.memorix/memorix.yml compatibility files\n * 4. ~/.memorix/config.json legacy file\n * 5. Hardcoded defaults\n */\n\nimport { loadYamlConfig, type MemorixYamlConfig } from './config/yaml-loader.js';\nimport {\n getResolvedAgentLane,\n getResolvedConfig,\n getResolvedEmbeddingLane,\n getResolvedMemoryLane,\n type ResolvedLaneOptions,\n} from './config/resolved-config.js';\nexport { loadDotenv, resetDotenv, getLoadedEnvFiles } from './config/dotenv-loader.js';\nexport { loadFileConfig, resetConfigCache, type MemorixConfig } from './config/legacy-loader.js';\n\n// ─── Resolved Getters ────────────────────────────────────────────────\n\n/** Memory/background LLM API key: env > memorix.yml > config.json > provider env fallbacks */\nexport function getLLMApiKey(): string | undefined {\n return getResolvedMemoryLane().llm.apiKey;\n}\n\n/** LLM provider: env > memorix.yml > config.json > auto-detect */\nexport function getLLMProvider(): string {\n const provider = getResolvedMemoryLane().llm.provider;\n if (provider) return provider;\n // Auto-detect from env var names\n if (process.env.ANTHROPIC_API_KEY && !process.env.OPENAI_API_KEY) return 'anthropic';\n if (process.env.OPENROUTER_API_KEY && !process.env.OPENAI_API_KEY) return 'openrouter';\n return 'openai';\n}\n\n/** LLM model: env > memorix.yml > config.json > provider default */\nexport function getLLMModel(providerDefault: string): string {\n return getResolvedMemoryLane().llm.model || providerDefault;\n}\n\n/** LLM base URL: env > memorix.yml > config.json > provider default */\nexport function getLLMBaseUrl(providerDefault: string): string {\n return getResolvedMemoryLane().llm.baseUrl || providerDefault;\n}\n\n/** TUI/chat agent API key: agent env > agent config > memory LLM fallback */\nexport function getAgentLLMApiKey(): string | undefined {\n return getResolvedAgentLane().apiKey;\n}\n\n/** TUI/chat agent provider: agent env > agent config > memory LLM fallback */\nexport function getAgentLLMProvider(): string {\n return getResolvedAgentLane().provider || getLLMProvider();\n}\n\n/** TUI/chat agent model: agent env > agent config > memory LLM fallback */\nexport function getAgentLLMModel(providerDefault: string): string {\n return getResolvedAgentLane().model || getLLMModel(providerDefault);\n}\n\n/** TUI/chat agent base URL: agent env > agent config > memory LLM fallback */\nexport function getAgentLLMBaseUrl(providerDefault: string): string {\n return getResolvedAgentLane().baseUrl || getLLMBaseUrl(providerDefault);\n}\n\n/** Embedding mode: env > memorix.yml > config.json > 'off' */\nexport function getEmbeddingMode(): 'off' | 'fastembed' | 'transformers' | 'api' | 'auto' {\n const provider = getResolvedEmbeddingLane().provider?.toLowerCase()?.trim();\n if (provider === 'fastembed' || provider === 'transformers' || provider === 'api' || provider === 'auto') return provider;\n return 'off';\n}\n\n/** Embedding API key: embedding lane only. Do not borrow memory LLM or agent keys. */\nexport function getEmbeddingApiKey(): string | undefined {\n return getResolvedEmbeddingLane().apiKey;\n}\n\n/** Embedding base URL: env > memorix.yml > config.json > provider default */\nexport function getEmbeddingBaseUrl(): string {\n return getResolvedEmbeddingLane().baseUrl || 'https://api.openai.com/v1';\n}\n\n/** Embedding model: env > memorix.yml > config.json > default */\nexport function getEmbeddingModel(): string {\n return getResolvedEmbeddingLane().model || 'text-embedding-3-small';\n}\n\n/** Embedding dimensions override: env > memorix.yml > config.json > null (auto-detect) */\nexport function getEmbeddingDimensions(): number | null {\n return getResolvedEmbeddingLane().dimensions ?? null;\n}\n\n// ─── YAML-specific getters (new config sections) ────────────────────\n\n/** Git-Memory pipeline config */\nexport function getGitConfig(options: ResolvedLaneOptions = {}): NonNullable<MemorixYamlConfig['git']> {\n const git = getResolvedConfig(options).git;\n return {\n autoHook: git.autoHook,\n ingestOnCommit: git.ingestOnCommit,\n maxDiffSize: git.maxDiffSize,\n skipMergeCommits: git.skipMergeCommits,\n excludePatterns: git.excludePatterns,\n noiseKeywords: git.noiseKeywords,\n };\n}\n\n/** Server config */\nexport function getServerConfig(): NonNullable<MemorixYamlConfig['server']> {\n const server = getResolvedConfig().server;\n return {\n transport: server.transport,\n dashboard: server.dashboard,\n dashboardPort: server.dashboardPort,\n port: server.port,\n };\n}\n\n/** Team config */\nexport function getTeamConfig(): NonNullable<MemorixYamlConfig['team']> {\n return loadYamlConfig().team ?? {};\n}\n\n/** Get the full resolved YAML config (for status display) */\nexport { loadYamlConfig } from './config/yaml-loader.js';\n","/**\n * LLM Provider\n *\n * Abstraction layer for LLM-enhanced memory management.\n * Supports OpenAI-compatible APIs (OpenAI, Anthropic via proxy, local models).\n *\n * This is the optional \"premium\" path — Memorix works without it,\n * but with an LLM configured, memory quality approaches Mem0/Cipher level.\n */\n\nimport {\n getAgentLLMApiKey,\n getAgentLLMBaseUrl,\n getAgentLLMModel,\n getAgentLLMProvider,\n getLLMApiKey,\n getLLMBaseUrl,\n getLLMModel,\n getLLMProvider,\n} from '../config.js';\n\nexport interface LLMConfig {\n provider: 'openai' | 'anthropic' | 'openrouter' | 'custom';\n apiKey: string;\n model?: string;\n baseUrl?: string;\n}\n\nconst LLM_TIMEOUT_DEFAULT_MS = 30_000;\nconst LLM_TIMEOUT_MIN_MS = 1_000;\nconst LLM_TIMEOUT_MAX_MS = 300_000;\nconst MAX_LLM_RESPONSE_BYTES = 2 * 1024 * 1024;\n\n/**\n * Parse and validate MEMORIX_LLM_TIMEOUT_MS environment variable.\n * - Must be a valid integer in the range 1000–300000ms.\n * - Non-integer or out-of-range values log a warning and fall back to the default.\n * Default: 30000ms (30s) — allows for proxy routing and cold starts.\n */\nexport function parseLLMTimeoutMs(raw: string | undefined): number {\n if (raw === undefined || raw.trim() === '') return LLM_TIMEOUT_DEFAULT_MS;\n const parsed = Number(raw);\n if (!Number.isInteger(parsed) || Number.isNaN(parsed)) {\n console.warn(\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.`,\n );\n return LLM_TIMEOUT_DEFAULT_MS;\n }\n if (parsed < LLM_TIMEOUT_MIN_MS) return LLM_TIMEOUT_MIN_MS;\n if (parsed > LLM_TIMEOUT_MAX_MS) return LLM_TIMEOUT_MAX_MS;\n return parsed;\n}\n\nconst LLM_CALL_TIMEOUT_MS = parseLLMTimeoutMs(process.env.MEMORIX_LLM_TIMEOUT_MS);\n\nexport interface LLMResponse {\n content: string;\n usage?: { promptTokens: number; completionTokens: number };\n}\n\n/** A single tool call requested by the LLM */\nexport interface ToolCall {\n id: string;\n name: string;\n arguments: string; // JSON string\n}\n\n/** Response from callLLMWithTools — may contain text, tool calls, or both */\nexport interface LLMToolResponse {\n content: string;\n toolCalls: ToolCall[];\n stopReason: 'end_turn' | 'tool_use' | 'stop' | 'unknown';\n usage?: { promptTokens: number; completionTokens: number };\n}\n\n/** Streaming event from callLLMWithToolsStream */\nexport type LLMStreamEvent =\n | { type: 'text'; content: string }\n | { type: 'tool_call'; toolCall: ToolCall }\n | { type: 'done'; response: LLMToolResponse };\n\nasync function readResponseText(response: Response, signal?: AbortSignal, maxBytes = MAX_LLM_RESPONSE_BYTES): Promise<string> {\n const contentLength = response.headers.get('content-length');\n if (contentLength && Number(contentLength) > maxBytes) {\n throw new Error(`LLM response too large (${contentLength} bytes)`);\n }\n\n const reader = response.body?.getReader();\n if (!reader) {\n signal?.throwIfAborted();\n return response.text();\n }\n\n const decoder = new TextDecoder();\n const chunks: string[] = [];\n let bytesRead = 0;\n const abortReader = () => {\n void reader.cancel(signal?.reason).catch(() => undefined);\n };\n\n signal?.addEventListener('abort', abortReader, { once: true });\n\n try {\n while (true) {\n signal?.throwIfAborted();\n const { value, done } = await reader.read();\n if (done) break;\n signal?.throwIfAborted();\n if (!value) continue;\n bytesRead += value.byteLength;\n if (bytesRead > maxBytes) {\n await reader.cancel('response too large').catch(() => undefined);\n throw new Error(`LLM response exceeded ${maxBytes} bytes`);\n }\n chunks.push(decoder.decode(value, { stream: true }));\n }\n\n chunks.push(decoder.decode());\n signal?.throwIfAborted();\n return chunks.join('');\n } finally {\n signal?.removeEventListener('abort', abortReader);\n reader.releaseLock();\n }\n}\n\nasync function readResponseJson<T>(response: Response, signal?: AbortSignal, maxBytes = MAX_LLM_RESPONSE_BYTES): Promise<T> {\n const text = await readResponseText(response, signal, maxBytes);\n return JSON.parse(text) as T;\n}\n\n/**\n * Call the LLM with tools in streaming mode.\n * Yields text chunks as they arrive, then a final 'done' event with the complete response.\n * Tool calls are accumulated and yielded at the end.\n */\nexport async function* callLLMWithToolsStream(\n messages: ChatMessage[],\n tools: ToolDefinition[],\n): AsyncGenerator<LLMStreamEvent, void, undefined> {\n if (!currentConfig) {\n throw new Error('LLM not configured. Set MEMORIX_LLM_API_KEY or OPENAI_API_KEY.');\n }\n\n if (currentConfig.provider === 'anthropic') {\n yield* callAnthropicWithToolsStream(messages, tools);\n return;\n }\n\n yield* callOpenAIWithToolsStream(messages, tools);\n}\n\n/** Tool definition for LLM function calling */\nexport interface ToolDefinition {\n name: string;\n description: string;\n parameters: Record<string, unknown>; // JSON Schema object\n}\n\n/** Chat message for multi-turn tool-use conversations */\nexport interface ChatMessage {\n role: 'system' | 'user' | 'assistant' | 'tool';\n content: string;\n toolCallId?: string; // for role='tool': which call this result is for\n toolCalls?: ToolCall[]; // for role='assistant': tool calls made\n name?: string; // for role='tool': function name\n}\n\n/** Provider defaults per provider type */\nconst PROVIDER_DEFAULTS: Record<string, { baseUrl: string; model: string }> = {\n openai: { baseUrl: 'https://api.openai.com/v1', model: 'gpt-4.1-nano' },\n anthropic: { baseUrl: 'https://api.anthropic.com/v1', model: 'claude-3-5-haiku-latest' },\n openrouter: { baseUrl: 'https://openrouter.ai/api/v1', model: 'openai/gpt-4.1-nano' },\n custom: { baseUrl: 'http://localhost:11434/v1', model: 'llama3' },\n};\n\nlet currentConfig: LLMConfig | null = null;\n\nexport type LLMConfigScope = 'memory' | 'agent';\n\nexport interface InitLLMOptions {\n scope?: LLMConfigScope;\n}\n\n/**\n * Initialize the LLM provider from environment variables.\n * Returns null if no API key is configured — Memorix gracefully degrades.\n */\nexport function initLLM(options: InitLLMOptions = {}): LLMConfig | null {\n const scope = options.scope ?? 'memory';\n const apiKey = scope === 'agent' ? getAgentLLMApiKey() : getLLMApiKey();\n if (!apiKey) {\n currentConfig = null;\n return null;\n }\n\n const provider = (scope === 'agent' ? getAgentLLMProvider() : getLLMProvider()) as LLMConfig['provider'];\n const defaults = PROVIDER_DEFAULTS[provider] ?? PROVIDER_DEFAULTS.openai;\n\n currentConfig = {\n provider,\n apiKey,\n model: scope === 'agent' ? getAgentLLMModel(defaults.model) : getLLMModel(defaults.model),\n baseUrl: scope === 'agent' ? getAgentLLMBaseUrl(defaults.baseUrl) : getLLMBaseUrl(defaults.baseUrl),\n };\n\n return currentConfig;\n}\n\n/**\n * Check if LLM is available.\n */\nexport function isLLMEnabled(): boolean {\n return currentConfig !== null;\n}\n\n/**\n * Get current LLM config (for display/debug).\n */\nexport function getLLMConfig(): LLMConfig | null {\n return currentConfig;\n}\n\n/**\n * Set LLM config directly (for testing or programmatic use).\n */\nexport function setLLMConfig(config: LLMConfig | null): void {\n currentConfig = config;\n}\n\n/**\n * Call the LLM with a prompt.\n * Uses OpenAI-compatible chat completions API (works with OpenRouter, Ollama, etc.)\n *\n * For Anthropic, we use their Messages API directly.\n */\nexport async function callLLM(\n systemPrompt: string,\n userMessage: string,\n): Promise<LLMResponse> {\n if (!currentConfig) {\n throw new Error('LLM not configured. Set MEMORIX_LLM_API_KEY or OPENAI_API_KEY.');\n }\n\n if (currentConfig.provider === 'anthropic') {\n return callAnthropic(systemPrompt, userMessage);\n }\n\n return callOpenAICompatible(systemPrompt, userMessage);\n}\n\n/**\n * OpenAI-compatible API call (works with OpenAI, OpenRouter, Ollama, etc.)\n */\nasync function callOpenAICompatible(\n systemPrompt: string,\n userMessage: string,\n): Promise<LLMResponse> {\n const config = currentConfig!;\n // Auto-fix: append /v1 if baseUrl doesn't end with it (common user mistake)\n let base = config.baseUrl!.replace(/\\/+$/, '');\n if (!base.endsWith('/v1')) base += '/v1';\n const url = `${base}/chat/completions`;\n\n const response = await fetch(url, {\n signal: AbortSignal.timeout(LLM_CALL_TIMEOUT_MS),\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${config.apiKey}`,\n },\n body: JSON.stringify({\n model: config.model,\n messages: [\n { role: 'system', content: systemPrompt },\n { role: 'user', content: userMessage },\n ],\n temperature: 0.1,\n max_tokens: 1024,\n }),\n });\n\n if (!response.ok) {\n const error = await readResponseText(response, undefined, 64 * 1024).catch(() => 'unknown error');\n throw new Error(`LLM API error (${response.status}): ${error}`);\n }\n\n const data = await readResponseJson<{\n choices: Array<{ message: { content: string } }>;\n usage?: { prompt_tokens: number; completion_tokens: number };\n }>(response);\n\n return {\n content: data.choices[0]?.message?.content ?? '',\n usage: data.usage ? {\n promptTokens: data.usage.prompt_tokens,\n completionTokens: data.usage.completion_tokens,\n } : undefined,\n };\n}\n\n/**\n * Anthropic Messages API call.\n */\nasync function callAnthropic(\n systemPrompt: string,\n userMessage: string,\n): Promise<LLMResponse> {\n const config = currentConfig!;\n const url = `${config.baseUrl}/messages`;\n\n const response = await fetch(url, {\n signal: AbortSignal.timeout(LLM_CALL_TIMEOUT_MS),\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': config.apiKey,\n 'anthropic-version': '2023-06-01',\n },\n body: JSON.stringify({\n model: config.model,\n system: systemPrompt,\n messages: [\n { role: 'user', content: userMessage },\n ],\n temperature: 0.1,\n max_tokens: 1024,\n }),\n });\n\n if (!response.ok) {\n const error = await readResponseText(response, undefined, 64 * 1024).catch(() => 'unknown error');\n throw new Error(`Anthropic API error (${response.status}): ${error}`);\n }\n\n const data = await readResponseJson<{\n content: Array<{ text: string }>;\n usage?: { input_tokens: number; output_tokens: number };\n }>(response);\n\n return {\n content: data.content[0]?.text ?? '',\n usage: data.usage ? {\n promptTokens: data.usage.input_tokens,\n completionTokens: data.usage.output_tokens,\n } : undefined,\n };\n}\n\n/**\n * Call the LLM with tool definitions (agentic harness pattern).\n *\n * The LLM can decide to call tools or respond directly.\n * Returns structured response with tool_calls for the agentic loop.\n */\nexport async function callLLMWithTools(\n messages: ChatMessage[],\n tools: ToolDefinition[],\n signal?: AbortSignal,\n): Promise<LLMToolResponse> {\n if (!currentConfig) {\n throw new Error('LLM not configured. Set MEMORIX_LLM_API_KEY or OPENAI_API_KEY.');\n }\n\n if (currentConfig.provider === 'anthropic') {\n return callAnthropicWithTools(messages, tools, signal);\n }\n\n return callOpenAIWithTools(messages, tools, signal);\n}\n\n/**\n * OpenAI-compatible tool calling (works with OpenAI, OpenRouter, Ollama, etc.)\n */\nasync function callOpenAIWithTools(\n messages: ChatMessage[],\n tools: ToolDefinition[],\n signal?: AbortSignal,\n): Promise<LLMToolResponse> {\n const config = currentConfig!;\n let base = config.baseUrl!.replace(/\\/+$/, '');\n if (!base.endsWith('/v1')) base += '/v1';\n const url = `${base}/chat/completions`;\n\n // Convert ChatMessage[] to OpenAI format\n const openaiMessages: Array<Record<string, unknown>> = messages.map((msg) => {\n if (msg.role === 'tool') {\n return { role: 'tool', content: msg.content, tool_call_id: msg.toolCallId };\n }\n if (msg.role === 'assistant' && msg.toolCalls && msg.toolCalls.length > 0) {\n return {\n role: 'assistant',\n content: msg.content || null,\n tool_calls: msg.toolCalls.map((tc) => ({\n id: tc.id,\n type: 'function',\n function: { name: tc.name, arguments: tc.arguments },\n })),\n };\n }\n return { role: msg.role, content: msg.content };\n });\n\n const openaiTools = tools.map((t) => ({\n type: 'function' as const,\n function: { name: t.name, description: t.description, parameters: t.parameters },\n }));\n\n const fetchSignal = signal\n ? AbortSignal.any([signal, AbortSignal.timeout(LLM_CALL_TIMEOUT_MS)])\n : AbortSignal.timeout(LLM_CALL_TIMEOUT_MS);\n\n const response = await fetch(url, {\n signal: fetchSignal,\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${config.apiKey}`,\n },\n body: JSON.stringify({\n model: config.model,\n messages: openaiMessages,\n tools: openaiTools.length > 0 ? openaiTools : undefined,\n temperature: 0.3,\n max_tokens: 2048,\n }),\n });\n\n if (!response.ok) {\n const error = await readResponseText(response, signal, 64 * 1024).catch(() => 'unknown error');\n throw new Error(`LLM tool-call API error (${response.status}): ${error}`);\n }\n\n const data = await readResponseJson<{\n choices: Array<{\n message: {\n content: string | null;\n tool_calls?: Array<{\n id: string;\n type: string;\n function: { name: string; arguments: string };\n }>;\n };\n finish_reason: string;\n }>;\n usage?: { prompt_tokens: number; completion_tokens: number };\n }>(response, signal);\n\n const choice = data.choices[0];\n const content = choice?.message?.content ?? '';\n const toolCalls: ToolCall[] = (choice?.message?.tool_calls ?? []).map((tc: { id: string; function: { name: string; arguments: string } }) => ({\n id: tc.id,\n name: tc.function.name,\n arguments: tc.function.arguments,\n }));\n\n const stopReason = choice?.finish_reason === 'tool_calls' ? 'tool_use'\n : choice?.finish_reason === 'stop' ? 'stop'\n : 'unknown';\n\n return {\n content,\n toolCalls,\n stopReason,\n usage: data.usage ? {\n promptTokens: data.usage.prompt_tokens,\n completionTokens: data.usage.completion_tokens,\n } : undefined,\n };\n}\n\n/**\n * Anthropic tool calling (Messages API with tool_use).\n */\nasync function callAnthropicWithTools(\n messages: ChatMessage[],\n tools: ToolDefinition[],\n signal?: AbortSignal,\n): Promise<LLMToolResponse> {\n const config = currentConfig!;\n const url = `${config.baseUrl}/messages`;\n\n // Separate system message from the rest\n const systemContent = messages.find((m) => m.role === 'system')?.content ?? '';\n const nonSystemMessages = messages.filter((m) => m.role !== 'system');\n\n // Convert to Anthropic message format\n const anthropicMessages: Array<Record<string, unknown>> = [];\n for (const msg of nonSystemMessages) {\n if (msg.role === 'user') {\n anthropicMessages.push({ role: 'user', content: msg.content });\n } else if (msg.role === 'assistant') {\n const contentBlocks: Array<Record<string, unknown>> = [];\n if (msg.content) contentBlocks.push({ type: 'text', text: msg.content });\n if (msg.toolCalls) {\n for (const tc of msg.toolCalls) {\n contentBlocks.push({\n type: 'tool_use',\n id: tc.id,\n name: tc.name,\n input: JSON.parse(tc.arguments),\n });\n }\n }\n anthropicMessages.push({ role: 'assistant', content: contentBlocks });\n } else if (msg.role === 'tool') {\n anthropicMessages.push({\n role: 'user',\n content: [{\n type: 'tool_result',\n tool_use_id: msg.toolCallId,\n content: msg.content,\n }],\n });\n }\n }\n\n const anthropicTools = tools.map((t) => ({\n name: t.name,\n description: t.description,\n input_schema: t.parameters,\n }));\n\n const fetchSignal = signal\n ? AbortSignal.any([signal, AbortSignal.timeout(LLM_CALL_TIMEOUT_MS)])\n : AbortSignal.timeout(LLM_CALL_TIMEOUT_MS);\n\n const response = await fetch(url, {\n signal: fetchSignal,\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': config.apiKey,\n 'anthropic-version': '2023-06-01',\n },\n body: JSON.stringify({\n model: config.model,\n system: systemContent,\n messages: anthropicMessages,\n tools: anthropicTools.length > 0 ? anthropicTools : undefined,\n temperature: 0.3,\n max_tokens: 2048,\n }),\n });\n\n if (!response.ok) {\n const error = await readResponseText(response, signal, 64 * 1024).catch(() => 'unknown error');\n throw new Error(`Anthropic tool-call API error (${response.status}): ${error}`);\n }\n\n const data = await readResponseJson<{\n content: Array<{ type: string; text?: string; id?: string; name?: string; input?: unknown }>;\n stop_reason: string;\n usage?: { input_tokens: number; output_tokens: number };\n }>(response, signal);\n\n let content = '';\n const toolCalls: ToolCall[] = [];\n for (const block of data.content) {\n if (block.type === 'text' && block.text) {\n content += block.text;\n } else if (block.type === 'tool_use' && block.id && block.name) {\n toolCalls.push({\n id: block.id,\n name: block.name,\n arguments: JSON.stringify(block.input ?? {}),\n });\n }\n }\n\n const stopReason = data.stop_reason === 'tool_use' ? 'tool_use'\n : data.stop_reason === 'end_turn' ? 'end_turn'\n : 'unknown';\n\n return {\n content,\n toolCalls,\n stopReason,\n usage: data.usage ? {\n promptTokens: data.usage.input_tokens,\n completionTokens: data.usage.output_tokens,\n } : undefined,\n };\n}\n\n// ── Streaming implementations ────────────────────────────────────\n\n/**\n * OpenAI-compatible streaming with tool support.\n * Parses SSE chunks, yields text deltas, accumulates tool calls.\n */\nasync function* callOpenAIWithToolsStream(\n messages: ChatMessage[],\n tools: ToolDefinition[],\n): AsyncGenerator<LLMStreamEvent, void, undefined> {\n const config = currentConfig!;\n let base = config.baseUrl!.replace(/\\/+$/, '');\n if (!base.endsWith('/v1')) base += '/v1';\n const url = `${base}/chat/completions`;\n\n const openaiMessages: Array<Record<string, unknown>> = messages.map((msg) => {\n if (msg.role === 'tool') {\n return { role: 'tool', content: msg.content, tool_call_id: msg.toolCallId };\n }\n if (msg.role === 'assistant' && msg.toolCalls && msg.toolCalls.length > 0) {\n return {\n role: 'assistant',\n content: msg.content || null,\n tool_calls: msg.toolCalls.map((tc) => ({\n id: tc.id,\n type: 'function',\n function: { name: tc.name, arguments: tc.arguments },\n })),\n };\n }\n return { role: msg.role, content: msg.content };\n });\n\n const openaiTools = tools.map((t) => ({\n type: 'function' as const,\n function: { name: t.name, description: t.description, parameters: t.parameters },\n }));\n\n const response = await fetch(url, {\n signal: AbortSignal.timeout(LLM_CALL_TIMEOUT_MS * 2), // longer timeout for streaming\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${config.apiKey}`,\n },\n body: JSON.stringify({\n model: config.model,\n messages: openaiMessages,\n tools: openaiTools.length > 0 ? openaiTools : undefined,\n temperature: 0.3,\n max_tokens: 2048,\n stream: true,\n }),\n });\n\n if (!response.ok) {\n const error = await response.text().catch(() => 'unknown error');\n throw new Error(`LLM streaming API error (${response.status}): ${error}`);\n }\n\n // Parse SSE stream\n const reader = response.body?.getReader();\n if (!reader) throw new Error('No response body for streaming');\n\n const decoder = new TextDecoder();\n let fullContent = '';\n const toolCallMap = new Map<number, { id: string; name: string; arguments: string }>();\n let finishReason = 'unknown';\n let buffer = '';\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() ?? ''; // keep incomplete line in buffer\n\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed || trimmed === 'data: [DONE]') continue;\n if (!trimmed.startsWith('data: ')) continue;\n\n try {\n const chunk = JSON.parse(trimmed.slice(6));\n const delta = chunk.choices?.[0]?.delta;\n if (!delta) continue;\n\n // Text content\n if (delta.content) {\n fullContent += delta.content;\n yield { type: 'text' as const, content: delta.content };\n }\n\n // Tool call deltas — accumulate\n if (delta.tool_calls) {\n for (const tc of delta.tool_calls) {\n const idx = tc.index ?? 0;\n if (!toolCallMap.has(idx)) {\n toolCallMap.set(idx, {\n id: tc.id ?? '',\n name: tc.function?.name ?? '',\n arguments: tc.function?.arguments ?? '',\n });\n } else {\n const existing = toolCallMap.get(idx)!;\n if (tc.id) existing.id = tc.id;\n if (tc.function?.name) existing.name = tc.function.name;\n if (tc.function?.arguments) existing.arguments += tc.function.arguments;\n }\n }\n }\n\n // Finish reason\n if (chunk.choices?.[0]?.finish_reason) {\n finishReason = chunk.choices[0].finish_reason;\n }\n } catch {\n // Skip malformed JSON chunks\n }\n }\n }\n } finally {\n reader.releaseLock();\n }\n\n const toolCalls = [...toolCallMap.values()].map((tc) => ({\n id: tc.id,\n name: tc.name,\n arguments: tc.arguments,\n }));\n\n // Yield tool_call events\n for (const tc of toolCalls) {\n yield { type: 'tool_call' as const, toolCall: tc };\n }\n\n const stopReason = finishReason === 'tool_calls' ? 'tool_use'\n : finishReason === 'stop' ? 'stop'\n : 'unknown';\n\n yield {\n type: 'done' as const,\n response: {\n content: fullContent,\n toolCalls,\n stopReason,\n },\n };\n}\n\n/**\n * Anthropic streaming with tool support.\n * Parses SSE events, yields text deltas, accumulates tool_use blocks.\n */\nasync function* callAnthropicWithToolsStream(\n messages: ChatMessage[],\n tools: ToolDefinition[],\n): AsyncGenerator<LLMStreamEvent, void, undefined> {\n const config = currentConfig!;\n const url = `${config.baseUrl}/messages`;\n\n const systemContent = messages.find((m) => m.role === 'system')?.content ?? '';\n const nonSystemMessages = messages.filter((m) => m.role !== 'system');\n\n const anthropicMessages: Array<Record<string, unknown>> = [];\n for (const msg of nonSystemMessages) {\n if (msg.role === 'user') {\n anthropicMessages.push({ role: 'user', content: msg.content });\n } else if (msg.role === 'assistant') {\n const contentBlocks: Array<Record<string, unknown>> = [];\n if (msg.content) contentBlocks.push({ type: 'text', text: msg.content });\n if (msg.toolCalls) {\n for (const tc of msg.toolCalls) {\n contentBlocks.push({\n type: 'tool_use',\n id: tc.id,\n name: tc.name,\n input: JSON.parse(tc.arguments),\n });\n }\n }\n anthropicMessages.push({ role: 'assistant', content: contentBlocks });\n } else if (msg.role === 'tool') {\n anthropicMessages.push({\n role: 'user',\n content: [{\n type: 'tool_result',\n tool_use_id: msg.toolCallId,\n content: msg.content,\n }],\n });\n }\n }\n\n const anthropicTools = tools.map((t) => ({\n name: t.name,\n description: t.description,\n input_schema: t.parameters,\n }));\n\n const response = await fetch(url, {\n signal: AbortSignal.timeout(LLM_CALL_TIMEOUT_MS * 2),\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': config.apiKey,\n 'anthropic-version': '2023-06-01',\n },\n body: JSON.stringify({\n model: config.model,\n system: systemContent,\n messages: anthropicMessages,\n tools: anthropicTools.length > 0 ? anthropicTools : undefined,\n temperature: 0.3,\n max_tokens: 2048,\n stream: true,\n }),\n });\n\n if (!response.ok) {\n const error = await response.text().catch(() => 'unknown error');\n throw new Error(`Anthropic streaming API error (${response.status}): ${error}`);\n }\n\n const reader = response.body?.getReader();\n if (!reader) throw new Error('No response body for streaming');\n\n const decoder = new TextDecoder();\n let fullContent = '';\n const toolCalls: ToolCall[] = [];\n let currentToolId = '';\n let currentToolName = '';\n let currentToolInput = '';\n let stopReason = 'unknown';\n let buffer = '';\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() ?? '';\n\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed.startsWith('data: ')) continue;\n\n try {\n const event = JSON.parse(trimmed.slice(6));\n\n if (event.type === 'content_block_delta') {\n const delta = event.delta;\n if (delta?.type === 'text_delta' && delta.text) {\n fullContent += delta.text;\n yield { type: 'text' as const, content: delta.text };\n } else if (delta?.type === 'input_json_delta' && delta.partial_json) {\n currentToolInput += delta.partial_json;\n }\n } else if (event.type === 'content_block_start') {\n const block = event.content_block;\n if (block?.type === 'tool_use') {\n currentToolId = block.id ?? '';\n currentToolName = block.name ?? '';\n currentToolInput = '';\n }\n } else if (event.type === 'content_block_stop') {\n // Finalize current tool call\n if (currentToolId && currentToolName) {\n const tc: ToolCall = {\n id: currentToolId,\n name: currentToolName,\n arguments: currentToolInput || '{}',\n };\n toolCalls.push(tc);\n yield { type: 'tool_call' as const, toolCall: tc };\n currentToolId = '';\n currentToolName = '';\n currentToolInput = '';\n }\n } else if (event.type === 'message_delta') {\n if (event.delta?.stop_reason) {\n stopReason = event.delta.stop_reason;\n }\n }\n } catch {\n // Skip malformed JSON\n }\n }\n }\n } finally {\n reader.releaseLock();\n }\n\n const mappedStopReason = stopReason === 'tool_use' ? 'tool_use'\n : stopReason === 'end_turn' ? 'end_turn'\n : 'unknown';\n\n yield {\n type: 'done' as const,\n response: {\n content: fullContent,\n toolCalls,\n stopReason: mappedStopReason,\n },\n };\n}\n","/**\n * SqliteBackend — ObservationStore implementation backed by better-sqlite3.\n *\n * Features:\n * - WAL mode for concurrent read performance\n * - storage_generation counter for cross-process freshness detection\n * - next_id counter in meta table (replaces counter.json)\n * - One-time migration from observations.json on first init\n * - Dynamic require of better-sqlite3 (optionalDependencies)\n *\n * Array fields (facts, filesModified, concepts, relatedCommits, relatedEntities)\n * are stored as JSON strings in SQLite columns.\n *\n * Uses the shared database handle from sqlite-db.ts so that observations,\n * mini-skills, and sessions all share one connection and one DB file.\n */\n\nimport type { Observation } from '../types.js';\nimport type { ObservationStore, StoreTransaction } from './obs-store.js';\nimport { getDatabase, closeDatabase } from './sqlite-db.js';\nimport path from 'node:path';\nimport fs from 'node:fs';\n\n// ── Row ↔ Observation serialization ────────────────────────────────\n\nfunction obsToRow(obs: Observation): Record<string, unknown> {\n return {\n id: obs.id,\n entityName: obs.entityName,\n type: obs.type,\n title: obs.title,\n narrative: obs.narrative,\n facts: JSON.stringify(obs.facts ?? []),\n filesModified: JSON.stringify(obs.filesModified ?? []),\n concepts: JSON.stringify(obs.concepts ?? []),\n tokens: obs.tokens ?? 0,\n createdAt: obs.createdAt,\n updatedAt: obs.updatedAt ?? null,\n projectId: obs.projectId,\n hasCausalLanguage: obs.hasCausalLanguage ? 1 : 0,\n topicKey: obs.topicKey ?? null,\n revisionCount: obs.revisionCount ?? 1,\n sessionId: obs.sessionId ?? null,\n status: obs.status ?? 'active',\n progress: obs.progress ? JSON.stringify(obs.progress) : null,\n source: obs.source ?? 'agent',\n commitHash: obs.commitHash ?? null,\n relatedCommits: obs.relatedCommits ? JSON.stringify(obs.relatedCommits) : null,\n relatedEntities: obs.relatedEntities ? JSON.stringify(obs.relatedEntities) : null,\n sourceDetail: obs.sourceDetail ?? null,\n valueCategory: obs.valueCategory ?? null,\n admissionState: obs.admissionState ?? null,\n admissionReason: obs.admissionReason ?? null,\n visibility: obs.visibility ?? null,\n sharedWithAgentIds: obs.sharedWithAgentIds ? JSON.stringify(obs.sharedWithAgentIds) : null,\n createdByAgentId: obs.createdByAgentId ?? null,\n writeGeneration: obs.writeGeneration ?? 0,\n };\n}\n\nfunction rowToObs(row: any): Observation {\n return {\n id: row.id,\n entityName: row.entityName,\n type: row.type,\n title: row.title,\n narrative: row.narrative,\n facts: safeJsonParse(row.facts, []),\n filesModified: safeJsonParse(row.filesModified, []),\n concepts: safeJsonParse(row.concepts, []),\n tokens: row.tokens,\n createdAt: row.createdAt,\n ...(row.updatedAt ? { updatedAt: row.updatedAt } : {}),\n projectId: row.projectId,\n hasCausalLanguage: !!row.hasCausalLanguage,\n ...(row.topicKey ? { topicKey: row.topicKey } : {}),\n revisionCount: row.revisionCount ?? 1,\n ...(row.sessionId ? { sessionId: row.sessionId } : {}),\n status: row.status ?? 'active',\n ...(row.progress ? { progress: safeJsonParse(row.progress, undefined) } : {}),\n ...(row.source ? { source: row.source } : {}),\n ...(row.commitHash ? { commitHash: row.commitHash } : {}),\n ...(row.relatedCommits ? { relatedCommits: safeJsonParse(row.relatedCommits, []) } : {}),\n ...(row.relatedEntities ? { relatedEntities: safeJsonParse(row.relatedEntities, []) } : {}),\n ...(row.sourceDetail ? { sourceDetail: row.sourceDetail } : {}),\n ...(row.valueCategory ? { valueCategory: row.valueCategory } : {}),\n ...(row.admissionState ? { admissionState: row.admissionState } : {}),\n ...(row.admissionReason ? { admissionReason: row.admissionReason } : {}),\n ...(row.visibility ? { visibility: row.visibility } : {}),\n ...(row.sharedWithAgentIds ? { sharedWithAgentIds: safeJsonParse(row.sharedWithAgentIds, []) } : {}),\n ...(row.createdByAgentId ? { createdByAgentId: row.createdByAgentId } : {}),\n ...(row.writeGeneration ? { writeGeneration: row.writeGeneration } : {}),\n } as Observation;\n}\n\nfunction safeJsonParse(val: string | null | undefined, fallback: any): any {\n if (val == null || val === '') return fallback;\n try { return JSON.parse(val); } catch { return fallback; }\n}\n\n// ── SqliteBackend ──────────────────────────────────────────────────\n\nexport class SqliteBackend implements ObservationStore {\n private db: any = null;\n private dataDir: string = '';\n private knownGeneration: number = 0;\n\n // Async mutex for serializing atomic() calls on the single connection\n private _atomicQueue: Promise<unknown> = Promise.resolve();\n\n // Prepared statements (lazy-initialized after db open)\n private stmtInsert: any = null;\n private stmtUpdate: any = null;\n private stmtSetStatus: any = null;\n private stmtSetStatusIfCurrent: any = null;\n private stmtDelete: any = null;\n private stmtSelectAll: any = null;\n private stmtSelectById: any = null;\n private stmtSelectByProject: any = null;\n private stmtSelectByProjectStatus: any = null;\n private stmtSelectByProjectAfterId: any = null;\n private stmtSelectByProjectStatusAfterId: any = null;\n private stmtCountByProject: any = null;\n private stmtCountByProjectStatus: any = null;\n private stmtSelectByTopicKey: any = null;\n private stmtSelectGeneration: any = null;\n private stmtBumpGeneration: any = null;\n private stmtGetMeta: any = null;\n private stmtSetMeta: any = null;\n\n async init(dataDir: string): Promise<void> {\n this.dataDir = dataDir;\n\n // Use shared database handle (opens DB, creates all tables, sets pragmas)\n this.db = getDatabase(dataDir);\n\n // Prepare statements\n this.stmtInsert = this.db.prepare(`\n INSERT OR REPLACE INTO observations\n (id, entityName, type, title, narrative, facts, filesModified, concepts, tokens,\n createdAt, updatedAt, projectId, hasCausalLanguage, topicKey, revisionCount,\n sessionId, status, progress, source, commitHash, relatedCommits, relatedEntities,\n sourceDetail, valueCategory, admissionState, admissionReason, visibility, sharedWithAgentIds,\n createdByAgentId, writeGeneration)\n VALUES\n (@id, @entityName, @type, @title, @narrative, @facts, @filesModified, @concepts, @tokens,\n @createdAt, @updatedAt, @projectId, @hasCausalLanguage, @topicKey, @revisionCount,\n @sessionId, @status, @progress, @source, @commitHash, @relatedCommits, @relatedEntities,\n @sourceDetail, @valueCategory, @admissionState, @admissionReason, @visibility, @sharedWithAgentIds,\n @createdByAgentId, @writeGeneration)\n `);\n this.stmtUpdate = this.stmtInsert; // INSERT OR REPLACE works for both\n this.stmtSetStatus = this.db.prepare(`UPDATE observations SET status = ? WHERE id = ?`);\n this.stmtSetStatusIfCurrent = this.db.prepare(\n `UPDATE observations SET status = ? WHERE id = ? AND status = ?`,\n );\n this.stmtDelete = this.db.prepare(`DELETE FROM observations WHERE id = ?`);\n this.stmtSelectAll = this.db.prepare(`SELECT * FROM observations`);\n this.stmtSelectById = this.db.prepare(`SELECT * FROM observations WHERE id = ?`);\n this.stmtSelectByProject = this.db.prepare(`\n SELECT * FROM observations WHERE projectId = ?\n ORDER BY id ASC LIMIT ? OFFSET ?\n `);\n this.stmtSelectByProjectStatus = this.db.prepare(`\n SELECT * FROM observations WHERE projectId = ? AND status = ?\n ORDER BY id ASC LIMIT ? OFFSET ?\n `);\n this.stmtSelectByProjectAfterId = this.db.prepare(`\n SELECT * FROM observations WHERE projectId = ? AND id > ?\n ORDER BY id ASC LIMIT ?\n `);\n this.stmtSelectByProjectStatusAfterId = this.db.prepare(`\n SELECT * FROM observations WHERE projectId = ? AND status = ? AND id > ?\n ORDER BY id ASC LIMIT ?\n `);\n this.stmtCountByProject = this.db.prepare(\n `SELECT COUNT(*) AS count FROM observations WHERE projectId = ?`,\n );\n this.stmtCountByProjectStatus = this.db.prepare(\n `SELECT COUNT(*) AS count FROM observations WHERE projectId = ? AND status = ?`,\n );\n this.stmtSelectByTopicKey = this.db.prepare(\n `SELECT * FROM observations WHERE projectId = ? AND topicKey = ? ORDER BY id ASC LIMIT 1`,\n );\n this.stmtSelectGeneration = this.db.prepare(`SELECT value FROM meta WHERE key = 'storage_generation'`);\n this.stmtBumpGeneration = this.db.prepare(`UPDATE meta SET value = CAST(CAST(value AS INTEGER) + 1 AS TEXT) WHERE key = 'storage_generation'`);\n this.stmtGetMeta = this.db.prepare(`SELECT value FROM meta WHERE key = ?`);\n this.stmtSetMeta = this.db.prepare(`INSERT OR REPLACE INTO meta (key, value) VALUES (?, ?)`);\n\n // Read initial generation\n this.knownGeneration = this.readGeneration();\n\n // Migration: if observations table is empty but observations.json exists, import\n await this.migrateFromJsonIfNeeded();\n }\n\n // ── Internal helpers ─────────────────────────────────────────────\n\n private readGeneration(): number {\n const row = this.stmtSelectGeneration.get();\n return row ? parseInt(row.value, 10) : 0;\n }\n\n private bumpGeneration(): void {\n this.stmtBumpGeneration.run();\n this.knownGeneration = this.readGeneration();\n }\n\n private rawLoadAll(): Observation[] {\n const rows = this.stmtSelectAll.all();\n return rows.map(rowToObs);\n }\n\n private rawGetById(id: number): Observation | undefined {\n const row = this.stmtSelectById.get(id);\n return row ? rowToObs(row) : undefined;\n }\n\n private rawFindByTopicKey(projectId: string, topicKey: string): Observation | undefined {\n const row = this.stmtSelectByTopicKey.get(projectId, topicKey);\n return row ? rowToObs(row) : undefined;\n }\n\n private rawLoadIdCounter(): number {\n const row = this.stmtGetMeta.get('next_id');\n return row ? parseInt(row.value, 10) : 1;\n }\n\n private rawSaveIdCounter(nextId: number): void {\n this.stmtSetMeta.run('next_id', String(nextId));\n }\n\n // ── Migration ────────────────────────────────────────────────────\n\n private async migrateFromJsonIfNeeded(): Promise<void> {\n // Only migrate if table is empty\n const count = this.db.prepare(`SELECT COUNT(*) AS cnt FROM observations`).get();\n if (count.cnt > 0) return;\n\n const jsonPath = path.join(this.dataDir, 'observations.json');\n if (!fs.existsSync(jsonPath)) return;\n\n try {\n const raw = fs.readFileSync(jsonPath, 'utf-8');\n const observations: Observation[] = JSON.parse(raw);\n\n if (observations.length === 0) return;\n\n console.error(`[memorix] Migrating ${observations.length} observations from JSON to SQLite...`);\n\n const insertMany = this.db.transaction((obsList: Observation[]) => {\n for (const obs of obsList) {\n this.stmtInsert.run(obsToRow(obs));\n }\n });\n insertMany(observations);\n\n // Migrate counter\n const counterPath = path.join(this.dataDir, 'counter.json');\n if (fs.existsSync(counterPath)) {\n try {\n const counterData = JSON.parse(fs.readFileSync(counterPath, 'utf-8'));\n const nextId = counterData.nextId ?? counterData.next_id ?? (Math.max(...observations.map(o => o.id)) + 1);\n this.rawSaveIdCounter(nextId);\n } catch {\n // Fallback: derive from max observation ID\n this.rawSaveIdCounter(Math.max(...observations.map(o => o.id)) + 1);\n }\n } else {\n this.rawSaveIdCounter(Math.max(...observations.map(o => o.id)) + 1);\n }\n\n this.bumpGeneration();\n\n console.error(`[memorix] Migration complete. ${observations.length} observations now in SQLite.`);\n } catch (err) {\n console.error(`[memorix] JSON→SQLite migration failed (non-fatal, data preserved in JSON): ${err}`);\n }\n }\n\n // ── Public read ──────────────────────────────────────────────────\n\n async loadAll(): Promise<Observation[]> {\n return this.rawLoadAll();\n }\n\n async loadByProject(\n projectId: string,\n options: { status?: string; limit?: number; offset?: number; afterId?: number } = {},\n ): Promise<Observation[]> {\n const limit = options.limit == null ? -1 : Math.max(1, Math.floor(options.limit));\n const offset = options.offset == null ? 0 : Math.max(0, Math.floor(options.offset));\n const afterId = options.afterId == null ? null : Math.max(0, Math.floor(options.afterId));\n const rows = afterId === null\n ? (options.status\n ? this.stmtSelectByProjectStatus.all(projectId, options.status, limit, offset)\n : this.stmtSelectByProject.all(projectId, limit, offset))\n : (options.status\n ? this.stmtSelectByProjectStatusAfterId.all(projectId, options.status, afterId, limit)\n : this.stmtSelectByProjectAfterId.all(projectId, afterId, limit));\n return rows.map(rowToObs);\n }\n\n async getById(id: number): Promise<Observation | undefined> {\n return this.rawGetById(id);\n }\n\n async countByProject(projectId: string, options: { status?: string } = {}): Promise<number> {\n const row = options.status\n ? this.stmtCountByProjectStatus.get(projectId, options.status)\n : this.stmtCountByProject.get(projectId);\n return Number(row?.count ?? 0);\n }\n\n async loadIdCounter(): Promise<number> {\n return this.rawLoadIdCounter();\n }\n\n // ── Public write (each bumps generation) ─────────────────────────\n\n async insert(obs: Observation): Promise<void> {\n this.stmtInsert.run(obsToRow(obs));\n this.bumpGeneration();\n }\n\n async update(obs: Observation): Promise<void> {\n this.stmtUpdate.run(obsToRow(obs));\n this.bumpGeneration();\n }\n\n async remove(id: number): Promise<void> {\n this.stmtDelete.run(id);\n this.bumpGeneration();\n }\n\n async bulkReplace(obs: Observation[]): Promise<void> {\n const run = this.db.transaction((obsList: Observation[]) => {\n this.db.prepare(`DELETE FROM observations`).run();\n for (const o of obsList) {\n this.stmtInsert.run(obsToRow(o));\n }\n });\n run(obs);\n this.bumpGeneration();\n }\n\n async bulkRemoveByIds(ids: number[]): Promise<void> {\n if (ids.length === 0) return;\n const run = this.db.transaction((idList: number[]) => {\n const stmt = this.db.prepare(`DELETE FROM observations WHERE id = ?`);\n for (const id of idList) {\n stmt.run(id);\n }\n });\n run(ids);\n this.bumpGeneration();\n }\n\n async saveIdCounter(nextId: number): Promise<void> {\n this.rawSaveIdCounter(nextId);\n }\n\n // ── Compound atomic operation ────────────────────────────────────\n\n async atomic<T>(fn: (tx: StoreTransaction) => Promise<T>): Promise<T> {\n // Serialize concurrent atomic() calls via an async queue.\n // better-sqlite3 is single-connection; nested BEGIN is illegal.\n const run = this._atomicQueue\n .catch(() => undefined)\n .then(async () => {\n this.db.prepare('BEGIN IMMEDIATE').run();\n try {\n const tx: StoreTransaction = {\n loadAll: async () => this.rawLoadAll(),\n getById: async (id) => this.rawGetById(id),\n findByTopicKey: async (projectId, topicKey) => this.rawFindByTopicKey(projectId, topicKey),\n loadIdCounter: async () => this.rawLoadIdCounter(),\n insert: async (obs) => { this.stmtInsert.run(obsToRow(obs)); },\n update: async (obs) => { this.stmtUpdate.run(obsToRow(obs)); },\n setStatus: async (id, status, expectedStatus) => {\n const result = expectedStatus === undefined\n ? this.stmtSetStatus.run(status, id)\n : this.stmtSetStatusIfCurrent.run(status, id, expectedStatus);\n return Number(result.changes) > 0;\n },\n remove: async (id) => { this.stmtDelete.run(id); },\n saveAll: async (obs) => {\n this.db.prepare(`DELETE FROM observations`).run();\n for (const o of obs) {\n this.stmtInsert.run(obsToRow(o));\n }\n },\n saveIdCounter: async (nextId) => this.rawSaveIdCounter(nextId),\n getGeneration: async () => this.readGeneration(),\n };\n const result = await fn(tx);\n this.bumpGeneration();\n this.db.prepare('COMMIT').run();\n return result;\n } catch (err) {\n try { this.db.prepare('ROLLBACK').run(); } catch { /* already rolled back */ }\n throw err;\n }\n });\n\n // Keep the queue alive after failures so one bad transaction does not poison\n // all future atomic() calls.\n this._atomicQueue = run.catch(() => undefined);\n return run;\n }\n\n // ── Freshness ────────────────────────────────────────────────────\n\n async ensureFresh(): Promise<boolean> {\n const remoteGen = this.readGeneration();\n if (remoteGen > this.knownGeneration) {\n this.knownGeneration = remoteGen;\n return true; // caller should reload observations[] + rebuild Orama\n }\n return false;\n }\n\n getGeneration(): number {\n return this.knownGeneration;\n }\n\n // ── Diagnostics ──────────────────────────────────────────────────\n\n close(): void {\n // Detach from the shared handle without closing it — other stores\n // (MiniSkillSqliteStore, SessionSqliteStore) may still be using it.\n // Use closeDatabase(dataDir) or closeAllDatabases() for full shutdown.\n this.db = null;\n }\n\n getBackendName(): 'sqlite' | 'degraded' {\n return 'sqlite';\n }\n}\n","/**\n * ObservationStore — unified persistence abstraction for observations.\n *\n * Backends:\n * - SqliteBackend (sqlite-store.ts) — WAL-mode SQLite with generation tracking\n * - DegradedBackend — read-only empty store when SQLite is unavailable\n *\n * JSON is no longer a runtime writable backend.\n * observations.json is only used as a one-time migration source into SQLite.\n *\n * All observation persistence flows through this interface.\n */\n\nimport type { Observation } from '../types.js';\n\n/**\n * Raw transaction handle for compound atomic operations.\n *\n * Inside an `atomic()` block the caller gets a StoreTransaction whose methods\n * operate directly on the underlying storage WITHOUT acquiring their own lock.\n * The outer `atomic()` already holds the lock / transaction.\n */\nexport interface StoreTransaction {\n /** Load all observations (raw, no lock). */\n loadAll(): Promise<Observation[]>;\n /** Load one observation by its globally unique ID (raw, no lock). */\n getById(id: number): Promise<Observation | undefined>;\n /** Find one observation by its project-scoped topic key (raw, no lock). */\n findByTopicKey(projectId: string, topicKey: string): Promise<Observation | undefined>;\n /** Load the ID counter (raw, no lock). */\n loadIdCounter(): Promise<number>;\n /** Insert one observation without independently acquiring a lock. */\n insert(obs: Observation): Promise<void>;\n /** Update one observation without independently acquiring a lock. */\n update(obs: Observation): Promise<void>;\n /** Change only an observation's lifecycle status without replacing its other fields. */\n setStatus(id: number, status: string, expectedStatus?: string): Promise<boolean>;\n /** Remove one observation without independently acquiring a lock. */\n remove(id: number): Promise<void>;\n /** Save all observations (raw, no lock). */\n saveAll(obs: Observation[]): Promise<void>;\n /** Save the ID counter (raw, no lock). */\n saveIdCounter(nextId: number): Promise<void>;\n /** Read the storage generation visible to this transaction. */\n getGeneration(): Promise<number>;\n}\n\nexport interface ObservationStore {\n // ── Lifecycle ──────────────────────────────────────────────────────\n\n /** One-time init: open DB/files, run migration if needed */\n init(dataDir: string): Promise<void>;\n\n // ── Read ───────────────────────────────────────────────────────────\n\n /** Load all observations into memory. Called at startup after init(). */\n loadAll(): Promise<Observation[]>;\n\n /** Load one project's observations without scanning the shared flat store. */\n loadByProject(\n projectId: string,\n options?: { status?: string; limit?: number; offset?: number; afterId?: number },\n ): Promise<Observation[]>;\n\n /** Count one project's observations without materializing the rows. */\n countByProject(projectId: string, options?: { status?: string }): Promise<number>;\n\n /** Load one observation by its globally unique ID. */\n getById(id: number): Promise<Observation | undefined>;\n\n /** Load the current next-ID counter value. */\n loadIdCounter(): Promise<number>;\n\n // ── Write — single mutations ───────────────────────────────────────\n\n /** Insert a new observation. Bumps generation (if applicable). */\n insert(obs: Observation): Promise<void>;\n\n /** Update an existing observation in-place (matched by obs.id). */\n update(obs: Observation): Promise<void>;\n\n /** Remove a single observation by ID. */\n remove(id: number): Promise<void>;\n\n // ── Write — batch ──────────────────────────────────────────────────\n\n /**\n * Replace the entire observation set atomically.\n * Reserved for explicit full-state imports or recovery operations.\n */\n bulkReplace(obs: Observation[]): Promise<void>;\n\n /** Remove multiple observations by ID in one operation. */\n bulkRemoveByIds(ids: number[]): Promise<void>;\n\n /** Persist the next-ID counter. */\n saveIdCounter(nextId: number): Promise<void>;\n\n // ── Compound atomic operations ─────────────────────────────────────\n\n /**\n * Execute fn while holding an exclusive lock (file lock for JSON,\n * transaction for SQLite). The StoreTransaction provides raw load/save\n * methods that operate within the lock scope.\n *\n * Used by storeObservation for compound topicKey-TOCTOU + ID-assignment.\n */\n atomic<T>(fn: (tx: StoreTransaction) => Promise<T>): Promise<T>;\n\n // ── Freshness (cross-process coherence) ────────────────────────────\n\n /**\n * Check if another process has mutated the store since our last read.\n * If yes, the caller should reload observations[] and rebuild the Orama index.\n *\n * - SqliteBackend: compares storage_generation in meta table vs local knownGeneration\n * - DegradedBackend: no-op, returns false (no data to refresh)\n *\n * @returns true if the local cache is stale and was refreshed\n */\n ensureFresh(): Promise<boolean>;\n\n /** Current known generation counter (local). */\n getGeneration(): number;\n\n // ── Lifecycle ─────────────────────────────────────────────────────\n\n /** Close the backend (release DB handles, file locks, etc.). */\n close(): void;\n\n // ── Diagnostics ────────────────────────────────────────────────────\n\n /** Which backend is active: 'sqlite' or 'degraded' (read-only). */\n getBackendName(): 'sqlite' | 'degraded';\n}\n\n// ── Singleton store access ─────────────────────────────────────────\n\nlet _store: ObservationStore | null = null;\nlet _storeDataDir: string | null = null;\n\n/** Get the active ObservationStore singleton. Throws if not yet initialized. */\nexport function getObservationStore(): ObservationStore {\n if (!_store) {\n throw new Error('[memorix] ObservationStore not initialized — call initObservationStore() first');\n }\n return _store;\n}\n\n/** Set the active ObservationStore singleton (called once during startup). */\nexport function setObservationStore(store: ObservationStore): void {\n _store = store;\n}\n\n/** Reset the singleton (for tests only). Detaches from the backend.\n * Call closeAllDatabases() separately if you need to release the shared DB handle. */\nexport function resetObservationStore(): void {\n if (_store) {\n try { _store.close(); } catch { /* best-effort */ }\n }\n _store = null;\n _storeDataDir = null;\n}\n\n/**\n * Create a fresh ObservationStore instance for a specific data directory\n * without touching the process-wide singleton. This is useful for long-lived\n * multi-project hosts (for example serve-http embedded dashboard APIs) where\n * requests may need to read different project data dirs concurrently.\n */\nexport async function createObservationStore(dataDir: string): Promise<ObservationStore> {\n // Try SQLite first (optionalDependencies — may not be installed)\n try {\n const { SqliteBackend } = await import('./sqlite-store.js');\n const store = new SqliteBackend();\n await store.init(dataDir);\n return store;\n } catch (err) {\n console.error(`[memorix] SQLite backend unavailable — degraded mode (read-only): ${err instanceof Error ? err.message : err}`);\n }\n\n // No writable JSON fallback — degraded read-only mode instead\n // observations.json is only used as migration source, not runtime backend\n const store = new DegradedBackend();\n await store.init(dataDir);\n return store;\n}\n\n/**\n * Initialize the ObservationStore singleton for the given data directory.\n *\n * Tries SQLite first. If unavailable, falls back to DegradedBackend (read-only).\n *\n * Idempotent: if already initialized for the same dataDir, returns the existing store.\n */\nexport async function initObservationStore(dataDir: string): Promise<ObservationStore> {\n if (_store && _storeDataDir === dataDir) {\n return _store;\n }\n\n // Close previous store if switching directories\n if (_store) {\n try { _store.close(); } catch { /* best-effort */ }\n _store = null;\n _storeDataDir = null;\n }\n\n const store = await createObservationStore(dataDir);\n _store = store;\n _storeDataDir = dataDir;\n return store;\n}\n\n// ── DegradedBackend (read-only when SQLite unavailable) ──────────\n\n/**\n * DegradedBackend — ObservationStore that is read-only and empty.\n *\n * Used when better-sqlite3 is unavailable. All write operations throw.\n * This ensures the system does not silently fall back to writing observations.json\n * as a runtime canonical store.\n */\nexport class DegradedBackend implements ObservationStore {\n private dataDir: string = '';\n\n async init(dataDir: string): Promise<void> {\n this.dataDir = dataDir;\n }\n\n async loadAll(): Promise<Observation[]> {\n return [];\n }\n\n async loadByProject(_projectId: string, _options?: { status?: string; limit?: number; offset?: number; afterId?: number }): Promise<Observation[]> {\n return [];\n }\n\n async countByProject(_projectId: string, _options?: { status?: string }): Promise<number> {\n return 0;\n }\n\n async getById(_id: number): Promise<Observation | undefined> {\n return undefined;\n }\n\n async loadIdCounter(): Promise<number> {\n return 1;\n }\n\n async insert(_obs: Observation): Promise<void> {\n throw new Error('[memorix] Cannot write observations: SQLite backend unavailable (degraded mode)');\n }\n\n async update(_obs: Observation): Promise<void> {\n throw new Error('[memorix] Cannot write observations: SQLite backend unavailable (degraded mode)');\n }\n\n async remove(_id: number): Promise<void> {\n throw new Error('[memorix] Cannot write observations: SQLite backend unavailable (degraded mode)');\n }\n\n async bulkReplace(_obs: Observation[]): Promise<void> {\n throw new Error('[memorix] Cannot write observations: SQLite backend unavailable (degraded mode)');\n }\n\n async bulkRemoveByIds(_ids: number[]): Promise<void> {\n throw new Error('[memorix] Cannot write observations: SQLite backend unavailable (degraded mode)');\n }\n\n async saveIdCounter(_nextId: number): Promise<void> {\n throw new Error('[memorix] Cannot write observations: SQLite backend unavailable (degraded mode)');\n }\n\n async atomic<T>(_fn: (tx: StoreTransaction) => Promise<T>): Promise<T> {\n throw new Error('[memorix] Cannot write observations: SQLite backend unavailable (degraded mode)');\n }\n\n async ensureFresh(): Promise<boolean> {\n return false;\n }\n\n getGeneration(): number {\n return 0;\n }\n\n close(): void {\n // No resources to release\n }\n\n getBackendName(): 'sqlite' | 'degraded' {\n return 'degraded';\n }\n}\n","/**\n * Memorix Core Types\n *\n * Data model sources:\n * - Entity/Relation/KnowledgeGraph: MCP Official Memory Server (v0.6.3)\n * - Observation/ObservationType: claude-mem Progressive Disclosure\n * - UnifiedRule/RuleSource: Memorix original (rules sync)\n *\n * Designed for extensibility: new agent formats (Kiro, Copilot, Antigravity)\n * can be added by extending RuleSource and adding format adapters.\n */\n\n// ============================================================\n// Knowledge Graph (adopted from MCP Official Memory Server)\n// ============================================================\n\n/** A node in the knowledge graph representing a concept, component, or config */\nexport interface Entity {\n name: string;\n entityType: string;\n observations: string[];\n}\n\n/** A directed edge between two entities */\nexport interface Relation {\n from: string;\n to: string;\n relationType: string;\n}\n\n/** The complete knowledge graph */\nexport interface KnowledgeGraph {\n entities: Entity[];\n relations: Relation[];\n}\n\n// ============================================================\n// Observation (adopted from claude-mem Progressive Disclosure)\n// ============================================================\n\n/**\n * Observation type classification using claude-mem's icon-based legend system.\n *\n * Icon mapping:\n * [SESSION] session-request — User's original goal\n * [GOTCHA] gotcha — Critical pitfall / trap\n * [FIX] problem-solution — Bug fix or workaround\n * [INFO] how-it-works — Technical explanation\n * [CHANGE] what-changed — Code/architecture change\n * [DISCOVERY] discovery — New learning or insight\n * [WHY] why-it-exists — Design rationale\n * [DECISION] decision — Architecture decision\n * [TRADEOFF] trade-off — Deliberate compromise\n * [REASONING] reasoning — Why this approach was chosen (System 2 reasoning trace)\n * [PROBE] probe — Operational heartbeat / connectivity check (short-lived, excluded from default search)\n */\nexport type ObservationType =\n | 'session-request'\n | 'gotcha'\n | 'problem-solution'\n | 'how-it-works'\n | 'what-changed'\n | 'discovery'\n | 'why-it-exists'\n | 'decision'\n | 'trade-off'\n | 'reasoning'\n | 'probe';\n\n/** Map from ObservationType to display icon */\nexport const OBSERVATION_ICONS: Record<ObservationType, string> = {\n 'session-request': '[SESSION]',\n 'gotcha': '[GOTCHA]',\n 'problem-solution': '[FIX]',\n 'how-it-works': '[INFO]',\n 'what-changed': '[CHANGE]',\n 'discovery': '[DISCOVERY]',\n 'why-it-exists': '[WHY]',\n 'decision': '[DECISION]',\n 'trade-off': '[TRADEOFF]',\n 'reasoning': '[REASONING]',\n 'probe': '[PROBE]',\n};\n\n/** Observation lifecycle status */\nexport type ObservationStatus = 'active' | 'resolved' | 'archived';\n\n/**\n * Control-plane admission state for automatically captured observations.\n * Candidate and ephemeral records remain inspectable, but only qualified\n * records are eligible for automatic context delivery. Missing state preserves\n * legacy behavior for observations written before this policy existed.\n */\nexport type ObservationAdmissionState = 'ephemeral' | 'candidate' | 'qualified';\n\n/**\n * Who may retrieve an observation through agent-facing memory surfaces.\n * Missing visibility is a legacy record and resolves to `project`.\n */\nexport type ObservationVisibility = 'personal' | 'project' | 'team';\n\n/**\n * Identity available to an agent-facing retrieval call. Internal maintenance\n * deliberately omits this and may inspect all project records for lifecycle work.\n */\nexport interface ObservationReader {\n /** Bound project for a normal project-scoped call. Omit only for explicit global search. */\n projectId?: string;\n /** Stable coordination identity, available after an explicit team join. */\n agentId?: string;\n /** True only when agentId is an active member of the bound project team. */\n isTeamMember?: boolean;\n}\n\n/** Progress tracking for task/feature observations */\nexport interface ProgressInfo {\n feature: string;\n status: 'in-progress' | 'completed' | 'blocked';\n completion?: number;\n}\n\n/** A rich observation record attached to an entity */\nexport interface Observation {\n id: number;\n entityName: string;\n type: ObservationType;\n title: string;\n narrative: string;\n facts: string[];\n filesModified: string[];\n concepts: string[];\n tokens: number;\n createdAt: string;\n updatedAt?: string;\n projectId: string;\n /** Whether the observation contains causal language (because, due to, etc.) */\n hasCausalLanguage?: boolean;\n /** Optional topic key for upsert — same project+topicKey updates existing observation */\n topicKey?: string;\n /** How many times this observation was revised via topic key upsert (starts at 1) */\n revisionCount?: number;\n /** Session ID this observation belongs to */\n sessionId?: string;\n /** Lifecycle status: active (default) → resolved → archived */\n status?: ObservationStatus;\n /** ID of the observation that superseded this one (set when auto-resolved by topicKey upsert) */\n supersededBy?: number;\n /** Progress tracking for task/feature observations */\n progress?: ProgressInfo;\n /** Origin of this observation: agent (IDE hooks/MCP), git (commit ingest), manual (CLI) */\n source?: 'agent' | 'git' | 'manual';\n /** Git commit hash if source is 'git' */\n commitHash?: string;\n /** Related commit hashes — links reasoning memories to the commits they explain */\n relatedCommits?: string[];\n /** Related entity names — explicit cross-references to other memory entities */\n relatedEntities?: string[];\n /** Provenance detail: how this observation entered the system */\n sourceDetail?: 'explicit' | 'hook' | 'git-ingest';\n /** Value category from formation pipeline evaluation */\n valueCategory?: 'core' | 'contextual' | 'ephemeral';\n /** Control-plane admission state for automatic capture and delivery. */\n admissionState?: ObservationAdmissionState;\n /** Short, sanitized explanation for the latest admission decision. */\n admissionReason?: string;\n /** Retrieval scope. Legacy records without a value remain project-visible. */\n visibility?: ObservationVisibility;\n /** Explicit additional readers for a personal record, used by targeted handoffs. */\n sharedWithAgentIds?: string[];\n /** Phase 4a: Agent ID that created this observation (team attribution) */\n createdByAgentId?: string;\n /** Phase 4a: Monotonic write generation — snapshot of storage_generation at write time (watermark coherence) */\n writeGeneration?: number;\n}\n\n// ============================================================\n// Session Lifecycle (inspired by Engram's session management)\n// ============================================================\n\n/** A coding session tracked by Memorix */\nexport interface Session {\n id: string;\n projectId: string;\n startedAt: string;\n endedAt?: string;\n summary?: string;\n status: 'active' | 'completed';\n /** Agent/IDE that started this session */\n agent?: string;\n}\n\n// ============================================================\n// Compact Engine (adopted from claude-mem 3-layer workflow)\n// ============================================================\n\n/** L1 index entry — lightweight, ~50-100 tokens per result */\nexport interface IndexEntry {\n id: number;\n time: string;\n type: ObservationType;\n icon: string;\n title: string;\n tokens: number;\n /** Relevance score from search (time-decayed). Used by compact engine. */\n score?: number;\n /** Project that owns this observation. Needed to disambiguate global results. */\n projectId?: string;\n /** Origin of the memory for source-aware retrieval and display. */\n source?: 'agent' | 'git' | 'manual';\n /** Provenance detail for source-aware display */\n sourceDetail?: 'explicit' | 'hook' | 'git-ingest';\n /** Value category for source-aware ranking */\n valueCategory?: 'core' | 'contextual' | 'ephemeral';\n /** Control-plane admission state when known. */\n admissionState?: ObservationAdmissionState;\n /** Retrieval scope when known. */\n visibility?: ObservationVisibility;\n /** Explainable recall: why this result matched. */\n matchedFields?: string[];\n /** Entity name — used for entity-affinity scoring and workstream deduplication. */\n entityName?: string;\n /** Document type: observation or mini-skill (Phase 3a) */\n documentType?: DocumentType;\n /** Knowledge layer for layer-aware ranking (Phase 3a) */\n knowledgeLayer?: KnowledgeLayer;\n}\n\n/** Explicit reference to an observation, optionally scoped to a project. */\nexport interface ObservationRef {\n id: number;\n projectId?: string;\n}\n\n/** L2 timeline context — observations around an anchor */\nexport interface TimelineContext {\n anchorId: number;\n anchorEntry: IndexEntry | null;\n before: IndexEntry[];\n after: IndexEntry[];\n}\n\n/** Retrieval work allowed for a search request. */\nexport type RetrievalQuality = 'fast' | 'balanced' | 'thorough';\n\n/** Search options for the compact engine */\nexport interface SearchOptions {\n query: string;\n limit?: number;\n type?: ObservationType;\n projectId?: string;\n since?: string;\n until?: string;\n /** Token budget — trim results to fit within this many tokens (0 = unlimited) */\n maxTokens?: number;\n /** Filter by observation status. Default: 'active' (only show active memories) */\n status?: ObservationStatus | 'all';\n /** Filter by observation source: 'agent', 'git', 'manual', or undefined for all */\n source?: 'agent' | 'git' | 'manual';\n /** Internal observability probes can disable access tracking without affecting normal search behavior. */\n trackAccess?: boolean;\n /** Internal reader context for agent-facing visibility filtering. */\n reader?: ObservationReader;\n /**\n * `fast` stays fully local, `balanced` (default) permits embeddings, and\n * `thorough` explicitly permits optional LLM query rewrite and reranking.\n */\n quality?: RetrievalQuality;\n}\n\n/** Topic key family heuristics for suggesting stable topic keys */\nexport const TOPIC_KEY_FAMILIES: Record<string, string[]> = {\n 'architecture': ['architecture', 'design', 'adr', 'structure', 'pattern'],\n 'bug': ['bugfix', 'fix', 'error', 'regression', 'crash', 'problem-solution'],\n 'decision': ['decision', 'trade-off', 'choice', 'strategy'],\n 'config': ['config', 'setup', 'env', 'environment', 'deployment'],\n 'discovery': ['discovery', 'learning', 'insight', 'gotcha'],\n 'pattern': ['pattern', 'convention', 'standard', 'best-practice'],\n};\n\n// ============================================================\n// Orama Document Schema\n// ============================================================\n\n/** The document shape stored in Orama */\nexport interface MemorixDocument {\n id: string;\n observationId: number;\n entityName: string;\n type: string;\n title: string;\n narrative: string;\n facts: string;\n filesModified: string;\n concepts: string;\n tokens: number;\n createdAt: string;\n projectId: string;\n /** Number of times this observation was returned in search results */\n accessCount: number;\n /** ISO timestamp of last access via search/detail */\n lastAccessedAt: string;\n /** Lifecycle status: active, resolved, archived */\n status: string;\n /** Origin: agent, git, manual */\n source: string;\n /** Provenance detail: explicit, hook, or git-ingest */\n sourceDetail?: string;\n /** Value category from formation evaluation */\n valueCategory?: string;\n /** Control-plane admission state for automatic capture and delivery. */\n admissionState?: string;\n /** Short, sanitized explanation for the latest admission decision. */\n admissionReason?: string;\n /** Retrieval scope for agent-facing filtering. */\n visibility?: string;\n /** Agent that owns a personal record, or authored a shared record. */\n createdByAgentId?: string;\n /** Explicit readers for a targeted personal record. */\n sharedWithAgentIds?: string;\n /** Optional vector embedding for semantic/hybrid retrieval */\n embedding?: number[];\n /** Document type: observation or mini-skill (Phase 3a) */\n documentType?: DocumentType;\n /** Knowledge layer for layer-aware ranking (Phase 3a) */\n knowledgeLayer?: KnowledgeLayer;\n}\n\n// ============================================================\n// Rules System (Memorix original — extensible for new agents)\n// ============================================================\n\n/**\n * Supported agent/IDE rule sources.\n * All 7 major AI IDEs are supported.\n */\nexport type RuleSource =\n | 'cursor'\n | 'claude-code'\n | 'codex'\n | 'windsurf'\n | 'antigravity'\n | 'gemini-cli'\n | 'copilot'\n | 'kiro'\n | 'trae'\n | 'memorix';\n\n/** A parsed rule in the unified intermediate representation */\nexport interface UnifiedRule {\n id: string;\n content: string;\n description?: string;\n source: RuleSource;\n scope: 'global' | 'project' | 'path-specific';\n paths?: string[];\n alwaysApply?: boolean;\n priority: number;\n hash: string;\n}\n\n/**\n * Format adapter interface — implement this for each agent/IDE.\n * Adding a new agent (e.g., Kiro) only requires implementing this interface.\n */\nexport interface RuleFormatAdapter {\n /** Unique identifier for this agent format */\n readonly source: RuleSource;\n\n /** File paths/globs this adapter can parse */\n readonly filePatterns: string[];\n\n /** Parse rule files into unified representation */\n parse(filePath: string, content: string): UnifiedRule[];\n\n /** Generate rule file content from unified representation */\n generate(rules: UnifiedRule[]): { filePath: string; content: string }[];\n}\n\n// ============================================================\n// Project Identity\n// ============================================================\n\nexport interface ProjectInfo {\n id: string;\n name: string;\n gitRemote?: string;\n rootPath: string;\n}\n\n/**\n * Diagnostic failure info from project detection.\n * Tells callers exactly WHY detection failed so they can report actionable errors.\n */\nexport type DetectionFailureReason =\n | 'path_not_found'\n | 'not_a_directory'\n | 'no_git'\n | 'git_worktree_error'\n | 'git_safe_directory'\n | 'remote_resolve_failed';\n\nexport interface DetectionFailure {\n reason: DetectionFailureReason;\n path: string;\n detail: string;\n}\n\nexport interface DetectionResult {\n project: ProjectInfo | null;\n failure: DetectionFailure | null;\n}\n\n// ============================================================\n// Memorix Server Configuration\n// ============================================================\n\nexport interface MemorixConfig {\n dataDir: string;\n projectId: string;\n projectName: string;\n enableEmbeddings: boolean;\n enableRulesSync: boolean;\n watchRuleFiles: boolean;\n}\n\nexport const DEFAULT_CONFIG: Partial<MemorixConfig> = {\n enableEmbeddings: false,\n enableRulesSync: false,\n watchRuleFiles: false,\n};\n\n// ============================================================\n// Workspace Sync — Cross-Agent workspace migration\n// ============================================================\n\n/** Supported agent targets for workspace sync */\nexport type AgentTarget =\n | 'windsurf'\n | 'cursor'\n | 'claude-code'\n | 'codex'\n | 'copilot'\n | 'antigravity'\n | 'gemini-cli'\n | 'openclaw'\n | 'hermes'\n | 'omp'\n | 'kiro'\n | 'opencode'\n | 'trae';\n\n/** A unified MCP server entry across all agent config formats */\nexport interface MCPServerEntry {\n name: string;\n /** Command for stdio transport */\n command: string;\n /** Args for stdio transport */\n args: string[];\n /** Environment variables */\n env?: Record<string, string> | null;\n /** URL for HTTP/SSE transport (Codex uses `url`, Windsurf uses `serverUrl`) */\n url?: string;\n /** HTTP headers (Windsurf uses `headers` for HTTP transport) */\n headers?: Record<string, string>;\n /** Whether this server is disabled */\n disabled?: boolean;\n /** Claude Code: force small core tool sets to load before the first prompt */\n alwaysLoad?: boolean;\n}\n\n/** Unified workflow entry */\nexport interface WorkflowEntry {\n name: string;\n description: string;\n content: string;\n source: AgentTarget;\n filePath: string;\n}\n\n/** A skill folder discovered from an agent's skills directory */\nexport interface SkillEntry {\n name: string;\n description: string;\n sourcePath: string;\n sourceAgent: AgentTarget;\n}\n\n/** Conflict when two agents have a skill with the same folder name */\nexport interface SkillConflict {\n name: string;\n kept: SkillEntry;\n skipped: SkillEntry;\n}\n\n/** Result of a workspace sync operation */\nexport interface WorkspaceSyncResult {\n mcpServers: {\n scanned: MCPServerEntry[];\n generated: { filePath: string; content: string }[];\n };\n workflows: {\n scanned: WorkflowEntry[];\n generated: { filePath: string; content: string }[];\n };\n rules: {\n scanned: number;\n generated: number;\n };\n skills: {\n scanned: SkillEntry[];\n conflicts: SkillConflict[];\n copied: string[];\n skipped: string[];\n };\n}\n\n// ============================================================\n// Mini-Skills — Promoted memories that never decay\n// ============================================================\n\n/** A mini-skill promoted from one or more observations */\nexport interface MiniSkill {\n id: number;\n /** Observation IDs this mini-skill was derived from (live refs, best-effort) */\n sourceObservationIds: number[];\n /** Entity the source observations belong to */\n sourceEntity: string;\n /** Short title for the skill */\n title: string;\n /** What the agent should do (imperative instruction) */\n instruction: string;\n /** When this skill should be applied (scenario description) */\n trigger: string;\n /** Key facts extracted from source observations */\n facts: string[];\n /** Project this skill belongs to */\n projectId: string;\n /** ISO timestamp */\n createdAt: string;\n /** How many times this skill was injected in session_start */\n usedCount: number;\n /** Classification tags */\n tags: string[];\n /** Frozen source observation content at promote time (JSON, immutable provenance proof) */\n sourceSnapshot?: string;\n /** ISO timestamp of last modification (Phase 3a: set once at creation) */\n updatedAt?: string;\n}\n\n// ============================================================\n// Source Snapshot — immutable provenance proof for promoted knowledge\n// ============================================================\n\n/** A single observation entry within a source snapshot */\nexport interface SnapshotObservation {\n id: number;\n title: string;\n type: string;\n narrative: string;\n facts: string[];\n entityName: string;\n projectId: string;\n createdAt: string;\n /** Frozen source detail for provenance (explicit / hook / git-ingest) */\n sourceDetail?: string;\n}\n\n/** Frozen source content captured at promote time */\nexport interface SourceSnapshot {\n observations: SnapshotObservation[];\n promotedAt: string;\n}\n\n// ============================================================\n// Knowledge Layer — Phase 3a retrieval classification\n// ============================================================\n\n/** Classification of knowledge for layer-aware ranking */\nexport type KnowledgeLayer = 'project-truth' | 'promoted' | 'evidence';\n\n/** Document type discriminator for Orama index */\nexport type DocumentType = 'observation' | 'mini-skill';\n\n// ============================================================\n// Typed Memory Reference — Phase 3a reference protocol\n// ============================================================\n\n/** A typed reference to a memory object (observation or mini-skill) */\nexport interface MemoryRef {\n kind: 'obs' | 'skill';\n id: number;\n projectId?: string;\n}\n\n/** MCP config format adapter interface */\nexport interface MCPConfigAdapter {\n readonly source: AgentTarget;\n /** Parse MCP server entries from a config file */\n parse(content: string): MCPServerEntry[];\n /** Generate config file content from MCP server entries */\n generate(servers: MCPServerEntry[]): string;\n /** Get the default config file path for this agent */\n getConfigPath(projectRoot?: string): string;\n}\n","/**\n * File Lock & Atomic Write Utilities\n *\n * Provides cross-process file locking using .lock files with atomic creation\n * (O_CREAT | O_EXCL), and atomic file writes via temp-file-then-rename.\n *\n * This prevents data corruption when multiple MCP server instances\n * (e.g., Cursor + Windsurf) write to the same project directory simultaneously.\n */\n\nimport { promises as fs } from 'node:fs';\nimport { randomUUID } from 'node:crypto';\nimport path from 'node:path';\n\n/** Lock is considered stale after 10 seconds (process crash recovery) */\nconst LOCK_STALE_MS = 10_000;\n/** Retry interval when waiting for lock */\nconst RETRY_INTERVAL_MS = 50;\n/** Maximum retries before giving up (50ms × 60 = 3 seconds) */\nconst MAX_RETRIES = 60;\nconst atomicWriteTails = new Map<string, Promise<void>>();\n\n/**\n * Acquire a lock file atomically.\n * Uses O_WRONLY | O_CREAT | O_EXCL — fails if file already exists.\n * Handles stale locks from crashed processes.\n */\nexport async function acquireLock(lockPath: string): Promise<void> {\n for (let i = 0; i < MAX_RETRIES; i++) {\n try {\n const fd = await fs.open(lockPath, 'wx');\n await fd.writeFile(JSON.stringify({ pid: process.pid, time: Date.now() }));\n await fd.close();\n return;\n } catch (err: unknown) {\n const code = err instanceof Error && 'code' in err ? (err as NodeJS.ErrnoException).code : undefined;\n if (code === 'EEXIST' || code === 'EPERM') {\n // Lock exists — check if stale\n try {\n const stat = await fs.stat(lockPath);\n if (Date.now() - stat.mtimeMs > LOCK_STALE_MS) {\n await fs.unlink(lockPath).catch(() => {});\n continue;\n }\n } catch {\n continue; // Lock disappeared — retry immediately\n }\n await new Promise(r => setTimeout(r, RETRY_INTERVAL_MS));\n } else {\n throw err;\n }\n }\n }\n // Last resort: force-remove stale lock and try once more\n await fs.unlink(lockPath).catch(() => {});\n try {\n const fd = await fs.open(lockPath, 'wx');\n await fd.writeFile(JSON.stringify({ pid: process.pid, time: Date.now() }));\n await fd.close();\n return;\n } catch {\n throw new Error(`Failed to acquire lock: ${lockPath} (timeout after ${MAX_RETRIES * RETRY_INTERVAL_MS}ms)`);\n }\n}\n\n/**\n * Release a lock file.\n */\nexport async function releaseLock(lockPath: string): Promise<void> {\n await fs.unlink(lockPath).catch(() => {});\n}\n\n/**\n * Execute a function while holding a project-level lock.\n * Ensures only one process writes to the project directory at a time.\n *\n * @param projectDir - The project data directory to lock\n * @param fn - The async function to execute while holding the lock\n * @returns The return value of fn\n */\nexport async function withFileLock<T>(projectDir: string, fn: () => Promise<T>): Promise<T> {\n const lockPath = path.join(projectDir, '.memorix.lock');\n await acquireLock(lockPath);\n try {\n return await fn();\n } finally {\n await releaseLock(lockPath);\n }\n}\n\n/**\n * Write a file atomically: write to .tmp, then rename.\n * Prevents partial writes from corrupting data files on crash.\n *\n * On most filesystems, rename() is atomic within the same directory,\n * so readers always see either the old complete file or the new complete file.\n */\nasync function atomicWriteFileOnce(filePath: string, data: string): Promise<void> {\n const tmpPath = filePath + `.tmp.${process.pid}.${randomUUID()}`;\n try {\n await fs.writeFile(tmpPath, data, 'utf-8');\n await fs.rename(tmpPath, filePath);\n } catch (error) {\n await fs.unlink(tmpPath).catch(() => {});\n throw error;\n }\n}\n\n/**\n * Serialize same-process writes to one target. Windows refuses concurrent\n * replacements of the same path even when each writer has its own temp file.\n */\nexport function atomicWriteFile(filePath: string, data: string): Promise<void> {\n const previous = atomicWriteTails.get(filePath) ?? Promise.resolve();\n const next = previous.catch(() => undefined).then(() => atomicWriteFileOnce(filePath, data));\n atomicWriteTails.set(filePath, next);\n return next.finally(() => {\n if (atomicWriteTails.get(filePath) === next) atomicWriteTails.delete(filePath);\n });\n}\n","/**\n * MiniSkillStore — persistence abstraction for mini-skills.\n *\n * Backends:\n * - MiniSkillSqliteStore — canonical store, uses shared DB handle from sqlite-db.ts\n * - MiniSkillGracefulDegrade — no-op fallback when SQLite is unavailable\n *\n * Phase 2 debt-zero: SQLite is the only canonical store for mini-skills.\n * JSON files are migration source only. No writable JSON fallback exists.\n */\n\nimport type { MiniSkill } from '../types.js';\nimport { getDatabase } from './sqlite-db.js';\nimport {\n loadMiniSkillsJson,\n} from './persistence.js';\nimport path from 'node:path';\nimport fs from 'node:fs';\n\n// ── Interface ───────────────────────────────────────────────────────\n\nexport interface MiniSkillStore {\n init(dataDir: string): Promise<void>;\n loadAll(): Promise<MiniSkill[]>;\n loadByProject(projectId: string): Promise<MiniSkill[]>;\n insert(skill: MiniSkill): Promise<void>;\n update(skill: MiniSkill): Promise<void>;\n remove(id: number): Promise<void>;\n loadIdCounter(): Promise<number>;\n saveIdCounter(nextId: number): Promise<void>;\n /**\n * Atomic create: allocate ID + insert skill + bump counter in one transaction.\n * Prevents concurrent promotes from receiving the same ID.\n */\n atomicInsertWithId(skill: Omit<MiniSkill, 'id'>): Promise<MiniSkill>;\n ensureFresh(): Promise<boolean>;\n getGeneration(): number;\n getBackendName(): 'sqlite' | 'degraded';\n}\n\n// ── Row <-> MiniSkill serialization ─────────────────────────────────\n\nfunction skillToRow(skill: MiniSkill): Record<string, unknown> {\n return {\n id: skill.id,\n sourceObservationIds: JSON.stringify(skill.sourceObservationIds ?? []),\n sourceEntity: skill.sourceEntity ?? 'unknown',\n title: skill.title,\n instruction: skill.instruction ?? '',\n trigger_desc: skill.trigger ?? '',\n facts: JSON.stringify(skill.facts ?? []),\n projectId: skill.projectId,\n createdAt: skill.createdAt,\n usedCount: skill.usedCount ?? 0,\n tags: JSON.stringify(skill.tags ?? []),\n sourceSnapshot: skill.sourceSnapshot ?? '',\n updatedAt: skill.updatedAt ?? null,\n };\n}\n\nfunction rowToSkill(row: any): MiniSkill {\n return {\n id: row.id,\n sourceObservationIds: safeJsonParse(row.sourceObservationIds, []),\n sourceEntity: row.sourceEntity ?? 'unknown',\n title: row.title,\n instruction: row.instruction ?? '',\n trigger: row.trigger_desc ?? '',\n facts: safeJsonParse(row.facts, []),\n projectId: row.projectId,\n createdAt: row.createdAt,\n usedCount: row.usedCount ?? 0,\n tags: safeJsonParse(row.tags, []),\n sourceSnapshot: row.sourceSnapshot || undefined,\n updatedAt: row.updatedAt || undefined,\n };\n}\n\nfunction safeJsonParse(val: string | null | undefined, fallback: any): any {\n if (val == null || val === '') return fallback;\n try { return JSON.parse(val); } catch { return fallback; }\n}\n\n// ── SQLite Backend ──────────────────────────────────────────────────\n\nexport class MiniSkillSqliteStore implements MiniSkillStore {\n private db: any = null;\n private dataDir: string = '';\n private knownGeneration: number = 0;\n\n private stmtInsert: any = null;\n private stmtDelete: any = null;\n private stmtSelectAll: any = null;\n private stmtSelectByProject: any = null;\n private stmtGetMeta: any = null;\n private stmtSetMeta: any = null;\n private stmtSelectGeneration: any = null;\n private stmtBumpGeneration: any = null;\n\n async init(dataDir: string): Promise<void> {\n this.dataDir = dataDir;\n this.db = getDatabase(dataDir);\n\n // Prepare statements\n this.stmtInsert = this.db.prepare(`\n INSERT OR REPLACE INTO mini_skills\n (id, sourceObservationIds, sourceEntity, title, instruction, trigger_desc,\n facts, projectId, createdAt, usedCount, tags, sourceSnapshot, updatedAt)\n VALUES\n (@id, @sourceObservationIds, @sourceEntity, @title, @instruction, @trigger_desc,\n @facts, @projectId, @createdAt, @usedCount, @tags, @sourceSnapshot, @updatedAt)\n `);\n this.stmtDelete = this.db.prepare(`DELETE FROM mini_skills WHERE id = ?`);\n this.stmtSelectAll = this.db.prepare(`SELECT * FROM mini_skills`);\n this.stmtSelectByProject = this.db.prepare(`SELECT * FROM mini_skills WHERE projectId = ?`);\n this.stmtGetMeta = this.db.prepare(`SELECT value FROM meta WHERE key = ?`);\n this.stmtSetMeta = this.db.prepare(`INSERT OR REPLACE INTO meta (key, value) VALUES (?, ?)`);\n this.stmtSelectGeneration = this.db.prepare(`SELECT value FROM meta WHERE key = 'mini_skills_generation'`);\n this.stmtBumpGeneration = this.db.prepare(`UPDATE meta SET value = CAST(CAST(value AS INTEGER) + 1 AS TEXT) WHERE key = 'mini_skills_generation'`);\n\n // Read initial generation\n this.knownGeneration = this.readGeneration();\n\n // One-time migration from mini-skills.json\n await this.migrateFromJsonIfNeeded();\n }\n\n private readGeneration(): number {\n const row = this.stmtSelectGeneration.get();\n return row ? parseInt(row.value, 10) : 0;\n }\n\n private bumpGeneration(): void {\n this.stmtBumpGeneration.run();\n this.knownGeneration = this.readGeneration();\n }\n\n // ── Migration ────────────────────────────────────────────────────\n\n private async migrateFromJsonIfNeeded(): Promise<void> {\n const count = this.db.prepare(`SELECT COUNT(*) AS cnt FROM mini_skills`).get();\n if (count.cnt > 0) return;\n\n const jsonPath = path.join(this.dataDir, 'mini-skills.json');\n if (!fs.existsSync(jsonPath)) return;\n\n try {\n const raw = fs.readFileSync(jsonPath, 'utf-8');\n const skills: MiniSkill[] = JSON.parse(raw);\n if (!Array.isArray(skills) || skills.length === 0) return;\n\n console.error(`[memorix] Migrating ${skills.length} mini-skills from JSON to SQLite...`);\n\n const insertMany = this.db.transaction((list: MiniSkill[]) => {\n for (const skill of list) {\n this.stmtInsert.run(skillToRow(skill));\n }\n });\n insertMany(skills);\n\n // Migrate counter\n const counterPath = path.join(this.dataDir, 'mini-skills-counter.json');\n if (fs.existsSync(counterPath)) {\n try {\n const counterData = JSON.parse(fs.readFileSync(counterPath, 'utf-8'));\n const nextId = counterData.nextId ?? (Math.max(...skills.map(s => s.id)) + 1);\n this.stmtSetMeta.run('mini_skills_next_id', String(nextId));\n } catch {\n this.stmtSetMeta.run('mini_skills_next_id', String(Math.max(...skills.map(s => s.id)) + 1));\n }\n } else {\n this.stmtSetMeta.run('mini_skills_next_id', String(Math.max(...skills.map(s => s.id)) + 1));\n }\n\n this.bumpGeneration();\n console.error(`[memorix] Mini-skills migration complete. ${skills.length} skills now in SQLite.`);\n } catch (err) {\n console.error(`[memorix] Mini-skills JSON->SQLite migration failed (non-fatal): ${err}`);\n }\n }\n\n // ── Public read ──────────────────────────────────────────────────\n\n async loadAll(): Promise<MiniSkill[]> {\n return this.stmtSelectAll.all().map(rowToSkill);\n }\n\n async loadByProject(projectId: string): Promise<MiniSkill[]> {\n return this.stmtSelectByProject.all(projectId).map(rowToSkill);\n }\n\n async loadIdCounter(): Promise<number> {\n const row = this.stmtGetMeta.get('mini_skills_next_id');\n return row ? parseInt(row.value, 10) : 1;\n }\n\n // ── Public write (each bumps generation) ─────────────────────────\n\n async insert(skill: MiniSkill): Promise<void> {\n this.stmtInsert.run(skillToRow(skill));\n this.bumpGeneration();\n }\n\n async update(skill: MiniSkill): Promise<void> {\n this.stmtInsert.run(skillToRow(skill)); // INSERT OR REPLACE\n this.bumpGeneration();\n }\n\n async remove(id: number): Promise<void> {\n this.stmtDelete.run(id);\n this.bumpGeneration();\n }\n\n async saveIdCounter(nextId: number): Promise<void> {\n this.stmtSetMeta.run('mini_skills_next_id', String(nextId));\n }\n\n /**\n * Atomic create: allocate ID + insert + bump counter in a single SQLite transaction.\n * SQLite serializes write transactions, so concurrent calls are safely sequenced.\n */\n async atomicInsertWithId(skillWithoutId: Omit<MiniSkill, 'id'>): Promise<MiniSkill> {\n const result = this.db.transaction(() => {\n // 1. Read current counter inside the transaction\n const row = this.stmtGetMeta.get('mini_skills_next_id');\n const nextId = row ? parseInt(row.value, 10) : 1;\n\n // 2. Build the full skill with the allocated ID\n const skill: MiniSkill = { ...skillWithoutId, id: nextId } as MiniSkill;\n\n // 3. Insert\n this.stmtInsert.run(skillToRow(skill));\n\n // 4. Bump counter\n this.stmtSetMeta.run('mini_skills_next_id', String(nextId + 1));\n\n // 5. Bump generation\n this.stmtBumpGeneration.run();\n this.knownGeneration = this.readGeneration();\n\n return skill;\n })();\n return result;\n }\n\n // ── Freshness ────────────────────────────────────────────────────\n\n async ensureFresh(): Promise<boolean> {\n const remoteGen = this.readGeneration();\n if (remoteGen > this.knownGeneration) {\n this.knownGeneration = remoteGen;\n return true;\n }\n return false;\n }\n\n getGeneration(): number {\n return this.knownGeneration;\n }\n\n getBackendName(): 'sqlite' | 'degraded' {\n return 'sqlite';\n }\n}\n\n// ── Graceful Degrade Fallback ────────────────────────────────────────\n//\n// Phase 2 debt-zero rule: mini-skills have NO writable JSON fallback.\n// In JSON-only environments (no better-sqlite3), reads return empty\n// and writes are no-ops with a warning. This prevents a parallel\n// canonical JSON write path from existing alongside SQLite.\n\nexport class MiniSkillGracefulDegrade implements MiniSkillStore {\n private warned = false;\n\n private warn(): void {\n if (!this.warned) {\n console.error('[memorix] MiniSkillStore: SQLite unavailable — mini-skills are disabled (read-only empty). Install better-sqlite3 for full functionality.');\n this.warned = true;\n }\n }\n\n async init(_dataDir: string): Promise<void> {\n this.warn();\n }\n\n async loadAll(): Promise<MiniSkill[]> { return []; }\n async loadByProject(_projectId: string): Promise<MiniSkill[]> { return []; }\n async loadIdCounter(): Promise<number> { return 1; }\n\n async insert(_skill: MiniSkill): Promise<void> { this.warn(); }\n async update(_skill: MiniSkill): Promise<void> { this.warn(); }\n async remove(_id: number): Promise<void> { this.warn(); }\n async saveIdCounter(_nextId: number): Promise<void> { /* no-op */ }\n async atomicInsertWithId(skillWithoutId: Omit<MiniSkill, 'id'>): Promise<MiniSkill> {\n this.warn();\n return { ...skillWithoutId, id: 0 } as MiniSkill;\n }\n\n async ensureFresh(): Promise<boolean> { return false; }\n getGeneration(): number { return 0; }\n getBackendName(): 'sqlite' | 'degraded' { return 'degraded'; }\n}\n\n// ── Singleton access ────────────────────────────────────────────────\n\nlet _store: MiniSkillStore | null = null;\nlet _storeDataDir: string | null = null;\n\nexport function isMiniSkillStoreInitialized(): boolean {\n return _store !== null;\n}\n\nexport function getMiniSkillStore(): MiniSkillStore {\n if (!_store) {\n throw new Error('[memorix] MiniSkillStore not initialized — call initMiniSkillStore() first');\n }\n return _store;\n}\n\nexport function resetMiniSkillStore(): void {\n _store = null;\n _storeDataDir = null;\n}\n\nexport async function initMiniSkillStore(dataDir: string): Promise<MiniSkillStore> {\n if (_store && _storeDataDir === dataDir) return _store;\n\n _store = null;\n _storeDataDir = null;\n\n // Try SQLite first\n try {\n const store = new MiniSkillSqliteStore();\n await store.init(dataDir);\n _store = store;\n _storeDataDir = dataDir;\n return store;\n } catch (err) {\n console.error(`[memorix] MiniSkillSqliteStore unavailable, running in degraded read-only mode: ${err instanceof Error ? err.message : err}`);\n }\n\n // Fallback: graceful degrade (no writable JSON backend per debt-zero rule)\n const store = new MiniSkillGracefulDegrade();\n await store.init(dataDir);\n _store = store;\n _storeDataDir = dataDir;\n return store;\n}\n","/**\n * Token Budget Manager\n *\n * Provides token counting and budget management for Progressive Disclosure.\n * Source: gpt-tokenizer (737 stars, JS port of OpenAI's tiktoken)\n *\n * Used by the Compact Engine to determine which layer of detail\n * fits within the caller's token budget.\n */\n\nimport { countTokens, isWithinTokenLimit } from 'gpt-tokenizer';\n\n/**\n * Count tokens in a string.\n */\nexport function countTextTokens(text: string): number {\n return countTokens(text);\n}\n\n/**\n * Check if text fits within a token limit.\n * Returns the token count if within limit, false otherwise.\n */\nexport function fitsInBudget(text: string, limit: number): number | false {\n return isWithinTokenLimit(text, limit);\n}\n\n/**\n * Truncate text to fit within a token budget.\n * Truncates at sentence boundaries when possible.\n */\nexport function truncateToTokenBudget(text: string, budget: number): string {\n if (fitsInBudget(text, budget) !== false) {\n return text;\n }\n\n // Binary search for the right length\n const sentences = text.split(/(?<=[.!?])\\s+/);\n let result = '';\n\n for (const sentence of sentences) {\n const candidate = result ? `${result} ${sentence}` : sentence;\n if (fitsInBudget(candidate, budget) === false) {\n break;\n }\n result = candidate;\n }\n\n // If no complete sentence fits, truncate by characters\n if (!result) {\n // Rough estimate: 1 token ≈ 4 chars for English, ≈ 1.5 chars for Chinese\n const estimatedChars = budget * 2;\n result = text.slice(0, estimatedChars);\n // Refine\n while (fitsInBudget(result, budget) === false && result.length > 0) {\n result = result.slice(0, Math.floor(result.length * 0.9));\n }\n if (result.length < text.length) {\n // A character estimate can end halfway through a flag, path, or symbol.\n // Drop the incomplete whitespace-delimited token instead of returning\n // misleading fragments such as `AUTH...`.\n const nextCharacter = text.charAt(result.length);\n if (nextCharacter && !/[\\s.,;:!?)}\\]]/.test(nextCharacter)) {\n const boundary = result.search(/\\s+\\S*$/);\n result = boundary > 0 ? result.slice(0, boundary).trimEnd() : '';\n }\n\n // Keep the suffix inside the stated budget when there is room. An empty\n // prefix is more honest than a partial identifier that appears valid.\n while (result && fitsInBudget(result + '...', budget) === false) {\n const boundary = result.lastIndexOf(' ');\n result = boundary > 0 ? result.slice(0, boundary).trimEnd() : '';\n }\n result = result ? result + '...' : '...';\n }\n }\n\n return result;\n}\n\n/**\n * Estimate the token cost of an IndexEntry line.\n * Used to predict compact index size.\n */\nexport function estimateIndexEntryTokens(title: string): number {\n // Format: \"| #ID | Time | Icon | Title | ~Tokens |\"\n // Overhead is roughly 15 tokens for formatting\n return countTextTokens(title) + 15;\n}\n","/**\n * Mini-Skills Engine — Promoted memories that never decay\n *\n * Converts important observations into permanent, actionable \"mini-skills\"\n * that are automatically injected into agent context during session_start.\n *\n * Unlike generic SKILL.md files from marketplaces, mini-skills are:\n * - Derived from YOUR project's actual memories (gotchas, decisions, fixes)\n * - Immune from retention decay (permanent knowledge)\n * - Auto-injected at session start (agents proactively apply them)\n * - Cross-IDE shared (stored in ~/.memorix/data/ alongside observations)\n *\n * Lifecycle: observation → memorix_promote → mini-skill → session_start injection\n */\n\nimport type { MiniSkill, Observation, SourceSnapshot, SnapshotObservation, KnowledgeLayer, DocumentType, MemorixDocument } from '../types.js';\nimport { getMiniSkillStore } from '../store/mini-skill-store.js';\nimport { countTextTokens } from '../compact/token-budget.js';\n\n// Hard filter: command execution logs are not promotable knowledge\nconst COMMAND_LOG_TITLE = /^(Ran:|Command:|Executed:)\\s/i;\n\n// ── Promote observations to mini-skills ──────────────────────────\n\nexport interface PromoteOptions {\n /** Override auto-generated trigger description */\n trigger?: string;\n /** Override auto-generated instruction */\n instruction?: string;\n /** Extra tags */\n tags?: string[];\n /** Bypass R2 (no command logs) and R3 (has content) validation. Cannot bypass R1 (sources must exist). */\n force?: boolean;\n}\n\n/** Provenance status of a mini-skill relative to its source observations */\nexport type ProvenanceStatus =\n | 'verified' // all source observations exist and are active\n | 'partial' // some source observations exist\n | 'snapshot-only' // no sources available, but snapshot exists\n | 'legacy'; // no snapshot AND no sources (unverifiable)\n\n/**\n * Promote one or more observations into a mini-skill.\n * The source observations are NOT deleted — they remain in the observation store\n * but the mini-skill is the permanent, never-decaying version.\n */\nexport async function promoteToMiniSkill(\n projectDir: string,\n projectId: string,\n observations: Observation[],\n options?: PromoteOptions,\n): Promise<MiniSkill> {\n // ── Promote-time validation ────────────────────────────────────\n // R1a: Sources must exist (cannot be bypassed)\n if (observations.length === 0) {\n throw new Error('Cannot promote: no source observations provided');\n }\n\n // R1b: All sources must be active — stale/archived knowledge must never be\n // permanently promoted. This check is NOT bypassable by force=true.\n const nonActive = observations.filter(o => (o.status ?? 'active') !== 'active');\n if (nonActive.length > 0) {\n throw new Error(\n `Cannot promote: ${nonActive.length} observation(s) are not active. ` +\n `Blocked: ${nonActive.map(o => `#${o.id} (${o.status ?? 'unknown'})`).join(', ')}. ` +\n `Only active observations can be promoted to permanent knowledge.`,\n );\n }\n\n // R1c: Probe observations are operational heartbeats -- never promotable, even with force=true\n const probes = observations.filter(o => o.type === 'probe');\n if (probes.length > 0) {\n throw new Error(\n `Cannot promote probe observations — they are operational heartbeats, not durable knowledge. ` +\n `Blocked: ${probes.map(o => `#${o.id} \"${o.title.substring(0, 60)}\"`).join(', ')}.`,\n );\n }\n\n if (!options?.force) {\n // R2: No command-log noise\n const commandLogs = observations.filter(o => COMMAND_LOG_TITLE.test(o.title));\n if (commandLogs.length > 0) {\n throw new Error(\n `Cannot promote command execution logs — use a knowledge observation instead. ` +\n `Blocked: ${commandLogs.map(o => `#${o.id} \"${o.title.substring(0, 60)}\"`).join(', ')}. ` +\n `Use force=true to override.`,\n );\n }\n\n // R3: Has substantive content\n const hasContent = observations.some(\n o => (o.narrative && o.narrative.trim().length > 0) ||\n (o.facts && o.facts.length > 0 && o.facts.some(f => f.trim().length > 0)),\n );\n if (!hasContent) {\n throw new Error(\n 'Cannot promote: source observations have no substantive content (empty narrative and facts). ' +\n 'Use force=true to override.',\n );\n }\n }\n\n // ── Freeze source snapshot (immutable provenance proof) ────────\n const snapshot = createSourceSnapshot(observations);\n const snapshotJson = JSON.stringify(snapshot);\n\n const store = getMiniSkillStore();\n\n // Auto-generate content from observations\n const title = generateTitle(observations);\n const instruction = options?.instruction || generateInstruction(observations);\n const trigger = options?.trigger || generateTrigger(observations);\n const facts = extractFacts(observations);\n const tags = [\n ...(options?.tags || []),\n ...extractTags(observations),\n ];\n\n const now = new Date().toISOString();\n\n // Atomic: ID allocation + insert + counter bump in a single SQLite transaction.\n // Prevents concurrent promotes from receiving the same ID.\n const skill = await store.atomicInsertWithId({\n sourceObservationIds: observations.map(o => o.id),\n sourceEntity: observations[0]?.entityName || 'unknown',\n title,\n instruction,\n trigger,\n facts,\n projectId,\n createdAt: now,\n usedCount: 0,\n tags: [...new Set(tags)],\n sourceSnapshot: snapshotJson,\n updatedAt: now,\n });\n\n return skill;\n}\n\n// ── Load & query mini-skills ─────────────────────────────────────\n\n/**\n * Load all mini-skills for a project.\n */\nexport async function loadMiniSkills(\n projectDir: string,\n projectId?: string,\n): Promise<MiniSkill[]> {\n const store = getMiniSkillStore();\n if (!projectId) return store.loadAll();\n return store.loadByProject(projectId);\n}\n\n/**\n * Load all mini-skills (unfiltered).\n */\nexport async function loadAllMiniSkills(projectDir: string): Promise<MiniSkill[]> {\n return getMiniSkillStore().loadAll();\n}\n\n/**\n * Delete a mini-skill by ID.\n */\nexport async function deleteMiniSkill(\n projectDir: string,\n skillId: number,\n): Promise<boolean> {\n const store = getMiniSkillStore();\n const all = await store.loadAll();\n const exists = all.some(s => s.id === skillId);\n if (!exists) return false;\n await store.remove(skillId);\n return true;\n}\n\n/**\n * Increment usedCount for skills that were injected in session_start.\n */\nexport async function recordMiniSkillUsage(\n projectDir: string,\n skillIds: number[],\n): Promise<void> {\n if (skillIds.length === 0) return;\n const store = getMiniSkillStore();\n const existing = await store.loadAll();\n for (const skill of existing) {\n if (skillIds.includes(skill.id)) {\n skill.usedCount++;\n await store.update(skill);\n }\n }\n}\n\n// ── Format mini-skills for session injection ─────────────────────\n\n/**\n * Format mini-skills for injection into session_start context.\n * Returns a markdown string ready to append to session context.\n */\nexport function formatMiniSkillsForInjection(skills: MiniSkill[]): string {\n if (skills.length === 0) return '';\n\n const lines = [\n `## [SESSION] Project Mini-Skills (${skills.length} active)`,\n '',\n ];\n\n for (const skill of skills) {\n lines.push(`### ${skill.title}`);\n lines.push(`**Do**: ${skill.instruction}`);\n lines.push(`**When**: ${skill.trigger}`);\n if (skill.facts.length > 0) {\n for (const fact of skill.facts) {\n lines.push(`- ${fact}`);\n }\n }\n lines.push('');\n }\n\n return lines.join('\\n');\n}\n\n// ── Auto-generation helpers ──────────────────────────────────────\n\nfunction generateTitle(observations: Observation[]): string {\n if (observations.length === 1) {\n return observations[0].title;\n }\n // Multiple observations — use the first one's title as base\n return observations[0].title;\n}\n\nfunction generateInstruction(observations: Observation[]): string {\n // Convert narrative into imperative instruction\n const obs = observations[0];\n const narrative = obs.narrative || '';\n\n // For gotchas, flip to \"avoid\" instruction\n if (obs.type === 'gotcha') {\n return `Avoid: ${narrative.split('\\n')[0]}`;\n }\n // For decisions, state the chosen approach\n if (obs.type === 'decision') {\n return `Follow: ${narrative.split('\\n')[0]}`;\n }\n // For problem-solution, state the solution\n if (obs.type === 'problem-solution') {\n return `Apply fix: ${narrative.split('\\n')[0]}`;\n }\n // Default: use narrative as-is\n return narrative.split('\\n')[0] || obs.title;\n}\n\nfunction generateTrigger(observations: Observation[]): string {\n const obs = observations[0];\n\n // Use entity name + file paths as trigger context\n const parts: string[] = [];\n if (obs.entityName && obs.entityName !== 'unknown') {\n parts.push(`Working on ${obs.entityName}`);\n }\n if (obs.filesModified.length > 0) {\n parts.push(`touching ${obs.filesModified.slice(0, 3).join(', ')}`);\n }\n if (obs.concepts.length > 0) {\n parts.push(`involving ${obs.concepts.slice(0, 3).join(', ')}`);\n }\n\n return parts.length > 0 ? parts.join('; ') : `Related to ${obs.title}`;\n}\n\nfunction extractFacts(observations: Observation[]): string[] {\n const facts = new Set<string>();\n for (const obs of observations) {\n for (const f of obs.facts) {\n facts.add(f);\n }\n }\n return [...facts].slice(0, 10);\n}\n\nfunction extractTags(observations: Observation[]): string[] {\n const tags = new Set<string>();\n for (const obs of observations) {\n tags.add(obs.type);\n for (const c of obs.concepts) {\n if (c.length <= 30) tags.add(c.toLowerCase());\n }\n }\n return [...tags].slice(0, 10);\n}\n\n// ── Provenance helpers (Phase 3a) ────────────────────────────────\n\n/**\n * Create an immutable source snapshot from observations at promote time.\n * Contains the minimum field set needed for self-contained provenance proof.\n */\nfunction createSourceSnapshot(observations: Observation[]): SourceSnapshot {\n return {\n observations: observations.map((o): SnapshotObservation => ({\n id: o.id,\n title: o.title,\n type: o.type,\n narrative: o.narrative,\n facts: [...o.facts],\n entityName: o.entityName,\n projectId: o.projectId,\n createdAt: o.createdAt,\n sourceDetail: o.sourceDetail,\n })),\n promotedAt: new Date().toISOString(),\n };\n}\n\n/**\n * Resolve the provenance status of a mini-skill by checking whether its\n * source observations still exist.\n *\n * @param skill The mini-skill to check\n * @param getObservationById Lookup function: (id) => Observation | undefined\n */\nexport function resolveProvenanceStatus(\n skill: MiniSkill,\n getObservationById: (id: number) => { id: number; status?: string } | undefined,\n): ProvenanceStatus {\n const ids = skill.sourceObservationIds;\n if (ids.length === 0) {\n return skill.sourceSnapshot ? 'snapshot-only' : 'legacy';\n }\n const found = ids.filter(id => {\n const obs = getObservationById(id);\n return obs && (obs.status ?? 'active') === 'active';\n });\n if (found.length === ids.length) return 'verified';\n if (found.length > 0) return 'partial';\n return skill.sourceSnapshot ? 'snapshot-only' : 'legacy';\n}\n\n// ── Knowledge Layer helpers (Phase 3a) ───────────────────────────\n\n/**\n * Resolve the knowledge layer for a document based on its type and source.\n * This is computed at index time — NOT stored in SQLite.\n */\nexport function resolveKnowledgeLayer(\n documentType: DocumentType,\n sourceDetail?: string,\n source?: string,\n): KnowledgeLayer {\n if (documentType === 'mini-skill') return 'promoted';\n if (sourceDetail === 'git-ingest' || source === 'git') return 'evidence';\n return 'project-truth';\n}\n\n/**\n * Convert a MiniSkill into a MemorixDocument for Orama indexing.\n * The document carries documentType='mini-skill' and knowledgeLayer='promoted'.\n */\nexport function miniSkillToDocument(skill: MiniSkill): MemorixDocument {\n const content = skill.instruction + '\\n' + skill.facts.join('\\n');\n return {\n id: `skill:${encodeURIComponent(skill.projectId)}:${skill.id}`,\n observationId: skill.id,\n entityName: skill.sourceEntity,\n type: 'mini-skill',\n title: skill.title,\n narrative: skill.instruction,\n facts: skill.facts.join('\\n'),\n filesModified: '',\n concepts: skill.tags.join(', '),\n tokens: countTextTokens(content),\n createdAt: skill.createdAt,\n projectId: skill.projectId,\n accessCount: skill.usedCount,\n lastAccessedAt: '',\n status: 'active',\n source: 'agent',\n sourceDetail: 'explicit',\n valueCategory: 'core',\n documentType: 'mini-skill',\n knowledgeLayer: 'promoted',\n };\n}\n","import type { ObservationReader, ObservationVisibility } from '../types.js';\n\n/** Minimal common shape shared by persisted observations and Orama documents. */\nexport interface VisibilityRecord {\n projectId: string;\n visibility?: ObservationVisibility | string;\n createdByAgentId?: string;\n sharedWithAgentIds?: string[] | string;\n}\n\n/**\n * Pre-control-plane records were intentionally project-shared. Preserve that\n * behavior so an upgrade does not make a user's historical memory disappear.\n */\nexport function resolveObservationVisibility(record: Pick<VisibilityRecord, 'visibility'>): ObservationVisibility {\n switch (record.visibility) {\n case 'personal':\n case 'team':\n case 'project':\n return record.visibility;\n default:\n return 'project';\n }\n}\n\nfunction sharedAgentIds(record: VisibilityRecord): string[] {\n if (Array.isArray(record.sharedWithAgentIds)) return record.sharedWithAgentIds;\n if (typeof record.sharedWithAgentIds !== 'string' || !record.sharedWithAgentIds) return [];\n try {\n const parsed = JSON.parse(record.sharedWithAgentIds);\n return Array.isArray(parsed) ? parsed.filter((id): id is string => typeof id === 'string') : [];\n } catch {\n return [];\n }\n}\n\n/**\n * The policy is intentionally fail-closed for personal and team scopes. A\n * missing actor never turns a private record into a project-wide result.\n * `undefined` is reserved for trusted internal maintenance, not MCP delivery.\n */\nexport function canReadObservation(record: VisibilityRecord, reader?: ObservationReader): boolean {\n if (!reader) return true;\n\n const sameProject = reader.projectId === record.projectId;\n const visibility = resolveObservationVisibility(record);\n // An explicit global search may inspect project-visible facts across projects,\n // but it never gains a team or personal scope without a bound project.\n if (visibility === 'project') return !reader.projectId || sameProject;\n if (!sameProject || !reader.agentId) return false;\n\n if (visibility === 'team') return reader.isTeamMember === true;\n return record.createdByAgentId === reader.agentId || sharedAgentIds(record).includes(reader.agentId);\n}\n\n/**\n * Reading a targeted handoff does not grant the recipient permission to alter\n * it. Project evidence is jointly maintainable; personal records stay owned by\n * their creator; team records require an active team member.\n */\nexport function canManageObservation(record: VisibilityRecord, reader?: ObservationReader): boolean {\n if (!reader) return true;\n if (!reader.projectId || reader.projectId !== record.projectId) return false;\n\n switch (resolveObservationVisibility(record)) {\n case 'project':\n return true;\n case 'team':\n return reader.isTeamMember === true;\n case 'personal':\n return Boolean(reader.agentId && record.createdByAgentId === reader.agentId);\n }\n}\n\nexport function filterReadableObservations<T extends VisibilityRecord>(\n observations: readonly T[],\n reader?: ObservationReader,\n): T[] {\n return reader ? observations.filter((observation) => canReadObservation(observation, reader)) : [...observations];\n}\n","/**\n * FastEmbed Provider\n *\n * Local ONNX-based embedding using fastembed (Qdrant).\n * Model: BAAI/bge-small-en-v1.5 (384 dimensions, ~30MB)\n *\n * This is an optional dependency — if fastembed is not installed,\n * the provider module gracefully falls back to fulltext-only search.\n *\n * Persistent disk cache: embeddings are saved to ~/.memorix/data/.embedding-cache.json\n * so server restarts don't need to regenerate them (saves minutes of CPU on 500+ obs).\n */\n\nimport { createHash } from 'node:crypto';\nimport { readFile, writeFile, mkdir } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\nimport type { EmbeddingProvider } from './provider.js';\n\nconst CACHE_DIR = process.env.MEMORIX_DATA_DIR || join(homedir(), '.memorix', 'data');\nconst CACHE_FILE = join(CACHE_DIR, '.embedding-cache.json');\n\n// In-memory cache keyed by text hash → embedding\nconst cache = new Map<string, number[]>();\nconst MAX_CACHE_SIZE = 5000;\nlet diskCacheDirty = false;\n\nfunction textHash(text: string): string {\n return createHash('sha256').update(text).digest('hex').slice(0, 16);\n}\n\nasync function loadDiskCache(): Promise<void> {\n try {\n const raw = await readFile(CACHE_FILE, 'utf-8');\n const entries: [string, number[]][] = JSON.parse(raw);\n for (const [k, v] of entries) cache.set(k, v);\n console.error(`[memorix] Loaded ${entries.length} cached embeddings from disk`);\n } catch {\n // No cache file or corrupt — start fresh\n }\n}\n\nasync function saveDiskCache(): Promise<void> {\n if (!diskCacheDirty) return;\n try {\n await mkdir(CACHE_DIR, { recursive: true });\n const entries = Array.from(cache.entries());\n await writeFile(CACHE_FILE, JSON.stringify(entries));\n diskCacheDirty = false;\n } catch {\n // Ignore write errors — cache is an optimization, not critical\n }\n}\n\nexport class FastEmbedProvider implements EmbeddingProvider {\n readonly name = 'fastembed-bge-small';\n readonly dimensions = 384;\n\n private model: { embed: (docs: string[], batchSize?: number) => AsyncGenerator<number[][]>; queryEmbed: (query: string) => Promise<number[]> };\n\n private constructor(model: FastEmbedProvider['model']) {\n this.model = model;\n }\n\n /**\n * Initialize the FastEmbed provider.\n * Downloads model on first use (~30MB), cached locally after.\n * Loads persistent embedding cache from disk.\n */\n static async create(): Promise<FastEmbedProvider> {\n // Dynamic import — throws if fastembed is not installed\n const { EmbeddingModel, FlagEmbedding } = await import('fastembed');\n const model = await FlagEmbedding.init({\n model: EmbeddingModel.BGESmallENV15,\n });\n // Load disk cache before returning — subsequent embedBatch calls will hit cache\n await loadDiskCache();\n return new FastEmbedProvider(model);\n }\n\n async embed(text: string): Promise<number[]> {\n const hash = textHash(text);\n const cached = cache.get(hash);\n if (cached) return cached;\n\n const raw = await this.model.queryEmbed(text);\n // Ensure plain number[] (fastembed may return Float32Array)\n const result = Array.from(raw) as number[];\n if (result.length !== this.dimensions) {\n throw new Error(`Expected ${this.dimensions}d embedding, got ${result.length}d`);\n }\n this.cacheSet(hash, result);\n return result;\n }\n\n async embedBatch(texts: string[]): Promise<number[][]> {\n const results: number[][] = new Array(texts.length);\n const uncachedIndices: number[] = [];\n const uncachedTexts: string[] = [];\n\n // Check cache for each text (by hash)\n for (let i = 0; i < texts.length; i++) {\n const hash = textHash(texts[i]);\n const cached = cache.get(hash);\n if (cached) {\n results[i] = cached;\n } else {\n uncachedIndices.push(i);\n uncachedTexts.push(texts[i]);\n }\n }\n\n // Batch embed uncached texts\n if (uncachedTexts.length > 0) {\n console.error(`[memorix] Embedding ${uncachedTexts.length}/${texts.length} uncached texts (${texts.length - uncachedTexts.length} from cache)`);\n let batchIdx = 0;\n for await (const batch of this.model.embed(uncachedTexts, 64)) {\n for (const vec of batch) {\n const originalIdx = uncachedIndices[batchIdx];\n const plain = Array.from(vec) as number[];\n results[originalIdx] = plain;\n this.cacheSet(textHash(uncachedTexts[batchIdx]), plain);\n batchIdx++;\n }\n }\n // Persist cache to disk after batch operations\n await saveDiskCache();\n }\n\n return results;\n }\n\n private cacheSet(hash: string, value: number[]): void {\n // Evict oldest entries if cache is full\n if (cache.size >= MAX_CACHE_SIZE) {\n const firstKey = cache.keys().next().value;\n if (firstKey !== undefined) cache.delete(firstKey);\n }\n cache.set(hash, value);\n diskCacheDirty = true;\n }\n}\n","/**\n * Transformers.js Provider\n *\n * Pure JavaScript embedding using @huggingface/transformers (HuggingFace).\n * Model: Xenova/all-MiniLM-L6-v2 (384 dimensions, ~22MB quantized)\n *\n * Key advantages over fastembed:\n * - No native ONNX binding required (pure JS / WASM)\n * - Works out-of-the-box on Windows, macOS, Linux\n * - Supports quantized models (q8, q4) for smaller footprint\n *\n * This is an optional dependency — if @huggingface/transformers is not\n * installed, the provider module gracefully falls back to the next option.\n *\n * Inspired by Mem0's multi-provider embedding architecture.\n */\n\nimport type { EmbeddingProvider } from './provider.js';\n\n// In-memory LRU cache\nconst cache = new Map<string, number[]>();\nconst MAX_CACHE_SIZE = 5000;\n\nexport class TransformersProvider implements EmbeddingProvider {\n readonly name = 'transformers-minilm';\n readonly dimensions = 384;\n\n private extractor: any; // Pipeline instance\n\n private constructor(extractor: any) {\n this.extractor = extractor;\n }\n\n /**\n * Initialize the Transformers.js provider.\n * Downloads model on first use (~22MB quantized), cached locally after.\n */\n static async create(): Promise<TransformersProvider> {\n // Dynamic import — throws if @huggingface/transformers is not installed\n const { pipeline } = await import('@huggingface/transformers');\n const extractor = await pipeline(\n 'feature-extraction',\n 'Xenova/all-MiniLM-L6-v2',\n { dtype: 'q8' }, // Quantized for small footprint\n );\n return new TransformersProvider(extractor);\n }\n\n async embed(text: string): Promise<number[]> {\n // Check cache first\n const cached = cache.get(text);\n if (cached) return cached;\n\n const output = await this.extractor(text, {\n pooling: 'mean',\n normalize: true,\n });\n\n // output.tolist() returns [[...384 floats]]\n const result: number[] = Array.from(output.tolist()[0]);\n if (result.length !== this.dimensions) {\n throw new Error(`Expected ${this.dimensions}d embedding, got ${result.length}d`);\n }\n\n this.cacheSet(text, result);\n return result;\n }\n\n async embedBatch(texts: string[]): Promise<number[][]> {\n const results: number[][] = new Array(texts.length);\n const uncachedIndices: number[] = [];\n const uncachedTexts: string[] = [];\n\n // Check cache for each text\n for (let i = 0; i < texts.length; i++) {\n const cached = cache.get(texts[i]);\n if (cached) {\n results[i] = cached;\n } else {\n uncachedIndices.push(i);\n uncachedTexts.push(texts[i]);\n }\n }\n\n // Batch embed uncached texts\n if (uncachedTexts.length > 0) {\n const output = await this.extractor(uncachedTexts, {\n pooling: 'mean',\n normalize: true,\n });\n const allVecs: number[][] = output.tolist();\n\n for (let i = 0; i < allVecs.length; i++) {\n const vec = Array.from(allVecs[i]) as number[];\n const originalIdx = uncachedIndices[i];\n results[originalIdx] = vec;\n this.cacheSet(uncachedTexts[i], vec);\n }\n }\n\n return results;\n }\n\n private cacheSet(key: string, value: number[]): void {\n if (cache.size >= MAX_CACHE_SIZE) {\n const firstKey = cache.keys().next().value;\n if (firstKey !== undefined) cache.delete(firstKey);\n }\n cache.set(key, value);\n }\n}\n","/**\n * API Embedding Provider\n *\n * Remote embedding via any OpenAI-compatible /v1/embeddings endpoint.\n * Works with OpenAI, DashScope/Qwen, Ollama-compatible gateways, and similar providers.\n */\n\nimport { createHash } from 'node:crypto';\nimport { readFile, writeFile, mkdir } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\nimport type { EmbeddingProvider } from './provider.js';\n\nconst CACHE_DIR = process.env.MEMORIX_DATA_DIR || join(homedir(), '.memorix', 'data');\nconst CACHE_FILE = join(CACHE_DIR, '.embedding-api-cache.json');\nconst DIMS_CACHE_FILE = join(CACHE_DIR, '.embedding-dims-cache.json');\nconst CACHE_META_FILE = join(CACHE_DIR, '.embedding-api-cache-meta.json');\n\nconst cache = new Map<string, number[]>();\nconst MAX_CACHE_SIZE = 10000;\nlet diskCacheDirty = false;\nlet diskSaveTimer: ReturnType<typeof setTimeout> | null = null;\nlet diskCacheLoaded = false;\nlet diskCacheLoadPromise: Promise<void> | null = null;\n\nconst MAX_INPUT_CHARS = 32000;\nconst MAX_CONCURRENCY = 4;\nconst DISK_SAVE_DEBOUNCE_MS = 5000;\n\nconst DEFAULT_MAX_BATCH_SIZE = 2048;\nconst DASHSCOPE_MAX_BATCH_SIZE = 10;\nconst MAX_RETRIES = 3;\nconst BASE_DELAY_MS = 500;\n\nfunction normalizeText(text: string): string {\n return text.replace(/\\s+/g, ' ').trim().slice(0, MAX_INPUT_CHARS);\n}\n\nfunction cacheNamespace(config: Pick<APIEmbeddingConfig, 'baseUrl' | 'model' | 'requestedDimensions'>): string {\n return [\n 'v2',\n config.baseUrl.replace(/\\/+$/, ''),\n config.model,\n config.requestedDimensions ?? 'native',\n ].join('|');\n}\n\nfunction textHash(text: string, namespace: string): string {\n return createHash('sha256').update(`${namespace}\\u0000${text}`).digest('hex').slice(0, 16);\n}\n\nasync function loadDiskCache(): Promise<void> {\n if (diskCacheLoaded) return;\n try {\n const raw = await readFile(CACHE_FILE, 'utf-8');\n const entries: [string, number[]][] = JSON.parse(raw);\n for (const [k, v] of entries) cache.set(k, v);\n console.error(`[memorix] Loaded ${entries.length} cached API embeddings from disk`);\n } catch {\n // No cache file or corrupt cache; start fresh.\n }\n diskCacheLoaded = true;\n}\n\n/** Start loading disk cache in background (non-blocking). */\nfunction startDiskCacheLoad(): void {\n if (diskCacheLoaded || diskCacheLoadPromise) return;\n diskCacheLoadPromise = loadDiskCache().catch(() => {});\n}\n\n/** Ensure disk cache is loaded (await if still in progress). */\nasync function ensureDiskCacheLoaded(): Promise<void> {\n if (diskCacheLoaded) return;\n if (diskCacheLoadPromise) { await diskCacheLoadPromise; return; }\n await loadDiskCache();\n}\n\nfunction dimsCacheKey(config: Pick<APIEmbeddingConfig, 'baseUrl' | 'model' | 'requestedDimensions'>): string {\n return [\n config.baseUrl.replace(/\\/+$/, ''),\n config.model,\n config.requestedDimensions ?? 'native',\n ].join('|');\n}\n\ninterface CacheMetadataEntry {\n namespace: string;\n dimensions: number;\n ts: number;\n}\n\nfunction isValidDimension(value: unknown): value is number {\n return typeof value === 'number' && Number.isInteger(value) && value > 0;\n}\n\n/**\n * The vector cache keeps a tiny, redundant namespace → dimensions map. It lets\n * cache-first startup recover when the separate dimensions cache is missing.\n */\nasync function loadCachedVectorDimensions(\n config: Pick<APIEmbeddingConfig, 'baseUrl' | 'model' | 'requestedDimensions'>,\n): Promise<number | null> {\n try {\n const raw = await readFile(CACHE_META_FILE, 'utf-8');\n const data = JSON.parse(raw);\n const namespace = cacheNamespace(config);\n if (!Array.isArray(data?.entries)) return null;\n const entry = data.entries.find((candidate: unknown) =>\n typeof candidate === 'object' &&\n candidate !== null &&\n (candidate as { namespace?: unknown }).namespace === namespace &&\n isValidDimension((candidate as { dimensions?: unknown }).dimensions),\n ) as CacheMetadataEntry | undefined;\n return entry?.dimensions ?? null;\n } catch {\n return null;\n }\n}\n\nasync function saveCachedVectorDimensions(\n config: Pick<APIEmbeddingConfig, 'baseUrl' | 'model' | 'requestedDimensions'>,\n dimensions: number,\n): Promise<void> {\n if (!isValidDimension(dimensions)) return;\n try {\n await mkdir(CACHE_DIR, { recursive: true });\n let entries: CacheMetadataEntry[] = [];\n try {\n const raw = await readFile(CACHE_META_FILE, 'utf-8');\n const data = JSON.parse(raw);\n if (Array.isArray(data?.entries)) {\n entries = data.entries.filter((candidate: unknown): candidate is CacheMetadataEntry =>\n typeof candidate === 'object' &&\n candidate !== null &&\n typeof (candidate as { namespace?: unknown }).namespace === 'string' &&\n isValidDimension((candidate as { dimensions?: unknown }).dimensions) &&\n typeof (candidate as { ts?: unknown }).ts === 'number',\n );\n }\n } catch {\n // The cache metadata is a best-effort acceleration layer.\n }\n\n const namespace = cacheNamespace(config);\n entries = entries.filter((entry) => entry.namespace !== namespace);\n entries.push({ namespace, dimensions, ts: Date.now() });\n await writeFile(CACHE_META_FILE, JSON.stringify({ version: 1, entries }));\n } catch {\n // A missing or read-only cache must never block embedding requests.\n }\n}\n\n/** Load cached probe dimensions from disk. Returns null if not cached. */\nasync function loadCachedDims(config: Pick<APIEmbeddingConfig, 'baseUrl' | 'model' | 'requestedDimensions'>): Promise<number | null> {\n try {\n const raw = await readFile(DIMS_CACHE_FILE, 'utf-8');\n const data = JSON.parse(raw);\n\n const key = dimsCacheKey(config);\n\n if (Array.isArray(data.entries)) {\n const entry = data.entries.find((candidate: unknown) =>\n typeof candidate === 'object' &&\n candidate !== null &&\n 'key' in candidate &&\n 'dimensions' in candidate &&\n (candidate as { key?: string }).key === key &&\n typeof (candidate as { dimensions?: unknown }).dimensions === 'number',\n ) as { dimensions: number } | undefined;\n if (entry) return entry.dimensions;\n }\n\n if (\n data.baseUrl === config.baseUrl &&\n data.model === config.model &&\n typeof data.dimensions === 'number' &&\n (data.requestedDimensions ?? null) === (config.requestedDimensions ?? null)\n ) {\n return data.dimensions;\n }\n\n if (\n data.baseUrl === config.baseUrl &&\n data.model === config.model &&\n typeof data.dimensions === 'number' &&\n (config.requestedDimensions ?? null) === null &&\n !('requestedDimensions' in data)\n ) {\n return data.dimensions;\n }\n } catch { /* no cache or corrupt */ }\n return null;\n}\n\n/** Persist probe dimensions for fast subsequent starts. */\nasync function saveCachedDims(config: Pick<APIEmbeddingConfig, 'baseUrl' | 'model' | 'requestedDimensions'>, dimensions: number): Promise<void> {\n try {\n await mkdir(CACHE_DIR, { recursive: true });\n const key = dimsCacheKey(config);\n let entries: Array<{ key: string; baseUrl: string; model: string; requestedDimensions: number | null; dimensions: number; ts: number }> = [];\n\n try {\n const raw = await readFile(DIMS_CACHE_FILE, 'utf-8');\n const data = JSON.parse(raw);\n if (Array.isArray(data.entries)) {\n entries = data.entries.filter((entry: unknown) =>\n typeof entry === 'object' &&\n entry !== null &&\n 'key' in entry &&\n typeof (entry as { key?: unknown }).key === 'string',\n ) as typeof entries;\n } else if (\n data &&\n typeof data === 'object' &&\n typeof data.baseUrl === 'string' &&\n typeof data.model === 'string' &&\n typeof data.dimensions === 'number'\n ) {\n entries = [{\n key: dimsCacheKey({\n baseUrl: data.baseUrl,\n model: data.model,\n requestedDimensions: data.requestedDimensions ?? null,\n }),\n baseUrl: data.baseUrl,\n model: data.model,\n requestedDimensions: data.requestedDimensions ?? null,\n dimensions: data.dimensions,\n ts: typeof data.ts === 'number' ? data.ts : Date.now(),\n }];\n }\n } catch {\n // no existing cache\n }\n\n const nextEntry = {\n key,\n baseUrl: config.baseUrl,\n model: config.model,\n requestedDimensions: config.requestedDimensions ?? null,\n dimensions,\n ts: Date.now(),\n };\n\n entries = entries.filter((entry) => entry.key !== key);\n entries.push(nextEntry);\n\n await writeFile(DIMS_CACHE_FILE, JSON.stringify({ entries }));\n } catch { /* best-effort */ }\n await saveCachedVectorDimensions(config, dimensions);\n}\n\nasync function saveDiskCacheNow(): Promise<void> {\n if (!diskCacheDirty) return;\n try {\n await mkdir(CACHE_DIR, { recursive: true });\n const entries = Array.from(cache.entries());\n await writeFile(CACHE_FILE, JSON.stringify(entries));\n diskCacheDirty = false;\n } catch {\n // Cache persistence is best-effort only.\n }\n}\n\nfunction scheduleDiskSave(): void {\n if (diskSaveTimer) clearTimeout(diskSaveTimer);\n diskSaveTimer = setTimeout(() => {\n saveDiskCacheNow().catch(() => {});\n diskSaveTimer = null;\n }, DISK_SAVE_DEBOUNCE_MS);\n}\n\nfunction cacheSet(hash: string, value: number[]): void {\n if (cache.size >= MAX_CACHE_SIZE) {\n const firstKey = cache.keys().next().value;\n if (firstKey !== undefined) cache.delete(firstKey);\n }\n cache.set(hash, value);\n diskCacheDirty = true;\n}\n\ninterface EmbeddingAPIResponse {\n object: string;\n data: Array<{\n object: string;\n index: number;\n embedding: number[];\n }>;\n model: string;\n usage?: {\n prompt_tokens: number;\n total_tokens: number;\n };\n}\n\ninterface APIEmbeddingConfig {\n apiKey: string;\n baseUrl: string;\n model: string;\n requestedDimensions: number | null;\n}\n\nexport interface APIEmbeddingProviderCreateOptions {\n /**\n * When false, only previously persisted dimension metadata may initialize\n * the provider. This keeps startup/cache hydration off the remote API path.\n */\n allowNetworkProbe?: boolean;\n}\n\nfunction resolveEnvEmbeddingApiKey(): string | undefined {\n return process.env.MEMORIX_EMBEDDING_API_KEY;\n}\n\nfunction getPreferredBatchSize(config: APIEmbeddingConfig): number {\n if (/dashscope\\.aliyuncs\\.com/i.test(config.baseUrl)) {\n return DASHSCOPE_MAX_BATCH_SIZE;\n }\n return DEFAULT_MAX_BATCH_SIZE;\n}\n\nfunction parseBatchLimit(error: unknown): number | null {\n if (!(error instanceof Error)) return null;\n\n const explicit = error.message.match(/should not be larger than\\s+(\\d+)/i);\n if (explicit) return parseInt(explicit[1], 10);\n\n if (/batch size/i.test(error.message)) {\n const fallback = error.message.match(/(\\d+)/);\n if (fallback) return parseInt(fallback[1], 10);\n }\n\n return null;\n}\n\nexport class APIEmbeddingProvider implements EmbeddingProvider {\n readonly name: string;\n readonly dimensions: number;\n\n private config: APIEmbeddingConfig;\n private readonly cacheKeyNamespace: string;\n private totalTokensUsed = 0;\n private totalApiCalls = 0;\n\n private constructor(config: APIEmbeddingConfig, detectedDimensions: number) {\n this.config = config;\n this.cacheKeyNamespace = cacheNamespace(config);\n this.dimensions = detectedDimensions;\n this.name = `api-${config.model.replace(/\\//g, '-')}`;\n }\n\n static async create(): Promise<APIEmbeddingProvider>;\n static async create(options: APIEmbeddingProviderCreateOptions & { allowNetworkProbe: false }): Promise<APIEmbeddingProvider | null>;\n static async create(options: APIEmbeddingProviderCreateOptions): Promise<APIEmbeddingProvider | null>;\n static async create(options: APIEmbeddingProviderCreateOptions = {}): Promise<APIEmbeddingProvider | null> {\n const config = APIEmbeddingProvider.resolveConfig();\n const allowNetworkProbe = options.allowNetworkProbe !== false;\n\n // Try cached dimensions first to avoid a network probe on cold start\n let probeDimensions = await loadCachedDims(config);\n let dimensionSource: 'dims-cache' | 'vector-cache' | 'probe' = 'dims-cache';\n if (probeDimensions === null) {\n probeDimensions = await loadCachedVectorDimensions(config);\n if (probeDimensions !== null) dimensionSource = 'vector-cache';\n }\n if (probeDimensions !== null) {\n console.error(`[memorix] API embedding: ${config.model} @ ${config.baseUrl} (${probeDimensions}d) [${dimensionSource}]`);\n if (dimensionSource === 'dims-cache') {\n void saveCachedVectorDimensions(config, probeDimensions);\n }\n } else {\n if (!allowNetworkProbe) return null;\n probeDimensions = await APIEmbeddingProvider.probeAPI(config);\n console.error(`[memorix] API embedding: ${config.model} @ ${config.baseUrl} (${probeDimensions}d)`);\n // Persist for next cold start\n saveCachedDims(config, probeDimensions).catch(() => {});\n }\n if (config.requestedDimensions) {\n console.error(`[memorix] Dimension shortening: ${config.requestedDimensions}d requested`);\n }\n\n // The cache can only be used after dimensions are known. In cache-only\n // startup with no metadata, skip parsing the potentially large cache file\n // altogether and stay lexical until a normal embedding lane is needed.\n startDiskCacheLoad();\n\n return new APIEmbeddingProvider(config, probeDimensions);\n }\n\n private static resolveConfig(): APIEmbeddingConfig {\n let apiKey: string | undefined;\n let baseUrl: string;\n let model: string;\n let requestedDimensions: number | null;\n\n try {\n let cfg: {\n getEmbeddingApiKey: () => string | undefined;\n getEmbeddingBaseUrl: () => string;\n getEmbeddingModel: () => string;\n getEmbeddingDimensions: () => number | null;\n };\n try {\n cfg = require('../config.ts');\n } catch {\n cfg = require('../config.js');\n }\n baseUrl = cfg.getEmbeddingBaseUrl();\n apiKey = cfg.getEmbeddingApiKey();\n model = cfg.getEmbeddingModel();\n requestedDimensions = cfg.getEmbeddingDimensions();\n } catch {\n baseUrl =\n process.env.MEMORIX_EMBEDDING_BASE_URL ||\n 'https://api.openai.com/v1';\n apiKey = resolveEnvEmbeddingApiKey();\n model = process.env.MEMORIX_EMBEDDING_MODEL || 'text-embedding-3-small';\n const dimStr = process.env.MEMORIX_EMBEDDING_DIMENSIONS;\n requestedDimensions = dimStr ? parseInt(dimStr, 10) : null;\n }\n\n if (!apiKey) {\n throw new Error(\n 'No API key for embedding. Set MEMORIX_EMBEDDING_API_KEY or configure embedding.apiKey in memorix.yml / ~/.memorix/config.json.',\n );\n }\n\n baseUrl = baseUrl.replace(/\\/+$/, '');\n\n return { apiKey, baseUrl, model, requestedDimensions };\n }\n\n private static async probeAPI(config: APIEmbeddingConfig): Promise<number> {\n const body: Record<string, unknown> = {\n model: config.model,\n input: 'dimension probe',\n };\n if (config.requestedDimensions) {\n body.dimensions = config.requestedDimensions;\n }\n\n const response = await fetchWithRetry(\n `${config.baseUrl}/embeddings`,\n config.apiKey,\n body,\n );\n\n if (response.data.length === 0 || !response.data[0].embedding) {\n throw new Error('API probe returned no embeddings; check model name and API key');\n }\n\n return response.data[0].embedding.length;\n }\n\n async embed(text: string): Promise<number[]> {\n const normalized = normalizeText(text);\n const hash = textHash(normalized, this.cacheKeyNamespace);\n\n // Fast path: cache already loaded (warm process) — instant lookup\n if (diskCacheLoaded) {\n const cached = cache.get(hash);\n if (cached) return cached;\n }\n\n // Cold-start path: cache is still loading in background.\n // Race the cache completion (may have a hit) against the API call.\n // Whichever resolves first with a valid embedding wins.\n const apiCall = async (): Promise<number[]> => {\n const body: Record<string, unknown> = {\n model: this.config.model,\n input: normalized,\n };\n if (this.config.requestedDimensions) {\n body.dimensions = this.config.requestedDimensions;\n }\n const response = await fetchWithRetry(\n `${this.config.baseUrl}/embeddings`,\n this.config.apiKey,\n body,\n );\n const embedding = response.data[0].embedding;\n if (embedding.length !== this.dimensions) {\n throw new Error(`Expected ${this.dimensions}d, got ${embedding.length}d; dimension mismatch`);\n }\n this.trackUsage(response);\n return embedding;\n };\n\n let embedding: number[];\n\n if (!diskCacheLoaded && diskCacheLoadPromise) {\n // Race: cache load + lookup vs API call\n const cacheRace = diskCacheLoadPromise.then(() => {\n const cached = cache.get(hash);\n if (cached) return cached;\n return null; // miss — let API win\n });\n\n const result = await Promise.race([\n cacheRace,\n apiCall().then(v => ({ __api: true, v } as const)),\n ]);\n\n if (result && typeof result === 'object' && '__api' in result) {\n // API finished first\n embedding = result.v;\n } else if (result) {\n // Cache hit won the race\n return result as number[];\n } else {\n // Cache loaded but missed — await the API call\n embedding = await apiCall();\n }\n } else {\n // No cache loading — just call API\n embedding = await apiCall();\n }\n\n cacheSet(hash, embedding);\n scheduleDiskSave();\n return embedding;\n }\n\n async embedBatch(texts: string[]): Promise<number[][]> {\n await ensureDiskCacheLoaded();\n const normalizedTexts = texts.map(normalizeText);\n const results: number[][] = new Array(texts.length);\n const uncachedIndices: number[] = [];\n const uncachedTexts: string[] = [];\n\n for (let i = 0; i < normalizedTexts.length; i++) {\n const hash = textHash(normalizedTexts[i], this.cacheKeyNamespace);\n const cached = cache.get(hash);\n if (cached) {\n results[i] = cached;\n } else {\n uncachedIndices.push(i);\n uncachedTexts.push(normalizedTexts[i]);\n }\n }\n\n if (uncachedTexts.length === 0) return results;\n\n const cacheHitRate = ((texts.length - uncachedTexts.length) / texts.length * 100).toFixed(1);\n console.error(\n `[memorix] API embedding ${uncachedTexts.length}/${texts.length} texts (cache hit: ${cacheHitRate}%)`,\n );\n\n const processChunk = async (chunkTexts: string[], chunkIndices: number[]): Promise<void> => {\n if (chunkTexts.length === 0) return;\n\n const body: Record<string, unknown> = {\n model: this.config.model,\n input: chunkTexts,\n };\n if (this.config.requestedDimensions) {\n body.dimensions = this.config.requestedDimensions;\n }\n\n try {\n const response = await fetchWithRetry(\n `${this.config.baseUrl}/embeddings`,\n this.config.apiKey,\n body,\n );\n\n this.trackUsage(response);\n\n for (const item of response.data) {\n const originalIdx = chunkIndices[item.index];\n results[originalIdx] = item.embedding;\n cacheSet(textHash(normalizedTexts[originalIdx], this.cacheKeyNamespace), item.embedding);\n }\n } catch (error) {\n const providerLimit = parseBatchLimit(error);\n const fallbackSize = providerLimit ?? Math.ceil(chunkTexts.length / 2);\n\n if (chunkTexts.length > 1 && fallbackSize < chunkTexts.length) {\n console.error(\n `[memorix] Embedding batch too large for provider, retrying in chunks of ${fallbackSize}`,\n );\n for (let start = 0; start < chunkTexts.length; start += fallbackSize) {\n await processChunk(\n chunkTexts.slice(start, start + fallbackSize),\n chunkIndices.slice(start, start + fallbackSize),\n );\n }\n return;\n }\n\n throw error;\n }\n };\n\n const preferredBatchSize = getPreferredBatchSize(this.config);\n const chunks: { texts: string[]; indices: number[] }[] = [];\n for (let batchStart = 0; batchStart < uncachedTexts.length; batchStart += preferredBatchSize) {\n chunks.push({\n texts: uncachedTexts.slice(batchStart, batchStart + preferredBatchSize),\n indices: uncachedIndices.slice(batchStart, batchStart + preferredBatchSize),\n });\n }\n\n for (let ci = 0; ci < chunks.length; ci += MAX_CONCURRENCY) {\n const concurrentChunks = chunks.slice(ci, ci + MAX_CONCURRENCY);\n await Promise.all(concurrentChunks.map((chunk) => processChunk(chunk.texts, chunk.indices)));\n }\n\n scheduleDiskSave();\n return results;\n }\n\n async getCachedEmbeddings(texts: string[]): Promise<(number[] | null)[]> {\n await ensureDiskCacheLoaded();\n return texts.map((text) => {\n const hash = textHash(normalizeText(text), this.cacheKeyNamespace);\n return cache.get(hash) ?? null;\n });\n }\n\n getStats(): { totalTokens: number; totalApiCalls: number; cacheSize: number } {\n return {\n totalTokens: this.totalTokensUsed,\n totalApiCalls: this.totalApiCalls,\n cacheSize: cache.size,\n };\n }\n\n private trackUsage(response: EmbeddingAPIResponse): void {\n this.totalApiCalls++;\n if (response.usage) {\n this.totalTokensUsed += response.usage.total_tokens;\n }\n }\n}\n\nasync function fetchWithRetry(\n url: string,\n apiKey: string,\n body: Record<string, unknown>,\n attempt = 0,\n): Promise<EmbeddingAPIResponse> {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), 10_000);\n let response: Response;\n try {\n response = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${apiKey}`,\n },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n } catch (err: unknown) {\n clearTimeout(timeout);\n if (err instanceof Error && err.name === 'AbortError') {\n throw new Error(`Embedding API timeout after 10s: ${url}`);\n }\n throw err;\n }\n clearTimeout(timeout);\n\n if (response.ok) {\n return response.json() as Promise<EmbeddingAPIResponse>;\n }\n\n if ((response.status === 429 || response.status >= 500) && attempt < MAX_RETRIES) {\n const delay = BASE_DELAY_MS * Math.pow(2, attempt);\n const retryAfter = response.headers.get('retry-after');\n const waitMs = retryAfter ? parseInt(retryAfter, 10) * 1000 : delay;\n console.error(`[memorix] Embedding API ${response.status}, retry ${attempt + 1}/${MAX_RETRIES} in ${waitMs}ms`);\n await new Promise(resolve => setTimeout(resolve, waitMs));\n return fetchWithRetry(url, apiKey, body, attempt + 1);\n }\n\n const errorText = await response.text().catch(() => 'unknown error');\n throw new Error(`Embedding API error (${response.status}): ${errorText}`);\n}\n","/**\n * Embedding Provider — Abstraction Layer\n *\n * Extensible embedding interface. **Disabled by default** to minimize resource usage.\n *\n * Environment variable MEMORIX_EMBEDDING controls which provider to use:\n * - MEMORIX_EMBEDDING=off (default) → no embedding, BM25 fulltext search only (~50MB RAM)\n * - MEMORIX_EMBEDDING=fastembed → local ONNX inference (384-dim bge-small, ~300MB RAM)\n * - MEMORIX_EMBEDDING=transformers → pure JS WASM inference (384-dim MiniLM, ~500MB RAM)\n * - MEMORIX_EMBEDDING=api → remote API via OpenAI-compatible /v1/embeddings (zero local RAM)\n * - MEMORIX_EMBEDDING=auto → try configured API → fastembed → transformers → off\n *\n * API mode env vars (MEMORIX_EMBEDDING=api):\n * - MEMORIX_EMBEDDING_API_KEY → embedding API key\n * - MEMORIX_EMBEDDING_BASE_URL → base URL (default: https://api.openai.com/v1)\n * - MEMORIX_EMBEDDING_MODEL → model (default: text-embedding-3-small)\n * - MEMORIX_EMBEDDING_DIMENSIONS → optional dimension override\n *\n * Resource impact of local embedding:\n * - First load: 90%+ CPU for 5-30 seconds (model initialization)\n * - Steady state: 300-500MB RAM (model in memory)\n * - Per-query: 10-50ms CPU (embedding generation)\n *\n * Most users don't need vector search — BM25 fulltext is sufficient for keyword matching.\n * Vector search is useful for semantic similarity (e.g., \"auth\" matches \"authentication\").\n *\n * Architecture inspired by Mem0's multi-provider embedding design.\n */\n\nexport interface EmbeddingProvider {\n /** Provider name for logging/cache keys */\n readonly name: string;\n /** Vector dimensions (e.g., 384 for bge-small) */\n readonly dimensions: number;\n /** Generate embedding for a single text */\n embed(text: string): Promise<number[]>;\n /** Generate embeddings for multiple texts (batch) */\n embedBatch(texts: string[]): Promise<number[][]>;\n /** Return already-persisted embeddings without generating new vectors. */\n getCachedEmbeddings?(texts: string[]): Promise<(number[] | null)[]>;\n}\n\nexport interface GetEmbeddingProviderOptions {\n /** Avoid remote API dimension probes while preparing a startup index. */\n allowNetworkProbe?: boolean;\n}\n\n/** Singleton provider instance (null = not available) */\nlet provider: EmbeddingProvider | null = null;\nlet initPromise: Promise<EmbeddingProvider | null> | null = null;\n\ntype EmbeddingMode = 'off' | 'fastembed' | 'transformers' | 'api' | 'auto';\ntype ProviderKind = 'api' | 'fastembed' | 'transformers' | 'unknown';\n\n/**\n * Tracks whether the last init attempt resulted in a temporary failure\n * (mode != 'off' but provider returned null). When true, the next\n * getEmbeddingProvider() call will retry instead of returning cached null.\n */\nlet lastInitWasTemporaryFailure = false;\nlet lastEmbeddingWarning = '';\nlet lastEmbeddingWarningAt = 0;\nconst WARNING_COOLDOWN_MS = 30_000;\n\nfunction warnOnce(message: string): void {\n const now = Date.now();\n if (message === lastEmbeddingWarning && now - lastEmbeddingWarningAt < WARNING_COOLDOWN_MS) {\n return;\n }\n lastEmbeddingWarning = message;\n lastEmbeddingWarningAt = now;\n console.error(message);\n}\n\n/**\n * Get configured embedding mode from environment.\n * Default is 'off' to minimize resource usage.\n */\nfunction getEmbeddingMode(): EmbeddingMode {\n // Unified: env vars > config.json > 'off'\n try {\n let cfg: { getEmbeddingMode: () => EmbeddingMode };\n try {\n cfg = require('../config.ts');\n } catch {\n cfg = require('../config.js');\n }\n const { getEmbeddingMode: cfgMode } = cfg;\n return cfgMode();\n } catch {\n // Fallback if config module not available\n const env = process.env.MEMORIX_EMBEDDING?.toLowerCase()?.trim();\n if (env === 'fastembed' || env === 'transformers' || env === 'api' || env === 'auto') return env;\n return 'off';\n }\n}\n\nfunction hasAPIEmbeddingConfig(): boolean {\n try {\n let cfg: {\n getEmbeddingApiKey: () => string | undefined;\n getEmbeddingBaseUrl: () => string | undefined;\n getEmbeddingModel: () => string | undefined;\n };\n try {\n cfg = require('../config.ts');\n } catch {\n cfg = require('../config.js');\n }\n const {\n getEmbeddingApiKey,\n getEmbeddingBaseUrl,\n getEmbeddingModel,\n } = cfg;\n\n return Boolean(\n getEmbeddingApiKey?.() &&\n getEmbeddingBaseUrl?.() &&\n getEmbeddingModel?.(),\n );\n } catch {\n return Boolean(process.env.MEMORIX_EMBEDDING_API_KEY);\n }\n}\n\nfunction getProviderKind(candidate: EmbeddingProvider): ProviderKind {\n if (candidate.name.startsWith('api-')) return 'api';\n if (candidate.name.startsWith('fastembed-')) return 'fastembed';\n if (candidate.name.startsWith('transformers-')) return 'transformers';\n return 'unknown';\n}\n\nfunction isTemporaryEmbeddingFailure(error: unknown): boolean {\n if (!(error instanceof Error)) return false;\n return (\n /embedding api error \\(401\\)/i.test(error.message) ||\n /invalid_api_key/i.test(error.message) ||\n /incorrect api key/i.test(error.message) ||\n /unauthorized/i.test(error.message) ||\n /embedding api timeout/i.test(error.message) ||\n /embedding api error \\((402|429|5\\d\\d)\\)/i.test(error.message) ||\n /quota exceeded/i.test(error.message) ||\n /account balance/i.test(error.message) ||\n /fetch failed/i.test(error.message) ||\n /econnreset/i.test(error.message) ||\n /econnrefused/i.test(error.message) ||\n /temporarily unavailable/i.test(error.message)\n );\n}\n\nfunction markTemporaryFailure(reason: unknown): void {\n provider = null;\n initPromise = null;\n lastInitWasTemporaryFailure = true;\n lastFailureTimestamp = Date.now();\n const message = reason instanceof Error ? reason.message : String(reason);\n warnOnce(`[memorix] Embedding provider temporarily unavailable at runtime: ${message}`);\n}\n\nasync function createFastEmbedProvider(): Promise<EmbeddingProvider | null> {\n try {\n const { FastEmbedProvider } = await import('./fastembed-provider.js');\n return await FastEmbedProvider.create();\n } catch (e) {\n warnOnce(`[memorix] Failed to load fastembed: ${e instanceof Error ? e.message : e}`);\n warnOnce('[memorix] Install with: npm install fastembed');\n return null;\n }\n}\n\nasync function createTransformersProvider(): Promise<EmbeddingProvider | null> {\n try {\n const { TransformersProvider } = await import('./transformers-provider.js');\n return await TransformersProvider.create();\n } catch (e) {\n warnOnce(`[memorix] Failed to load transformers: ${e instanceof Error ? e.message : e}`);\n warnOnce('[memorix] Install with: npm install @huggingface/transformers');\n return null;\n }\n}\n\nasync function createAPIProvider(options?: GetEmbeddingProviderOptions): Promise<EmbeddingProvider | null> {\n try {\n const { APIEmbeddingProvider } = await import('./api-provider.js');\n return await APIEmbeddingProvider.create(options ?? {});\n } catch (e) {\n warnOnce(`[memorix] Failed to init API embedding: ${e instanceof Error ? e.message : e}`);\n return null;\n }\n}\n\nasync function createLocalFallbackProvider(): Promise<EmbeddingProvider | null> {\n const fastembed = await createFastEmbedProvider();\n if (fastembed) return fastembed;\n\n const transformers = await createTransformersProvider();\n if (transformers) return transformers;\n\n return null;\n}\n\nfunction wrapProvider(candidate: EmbeddingProvider): EmbeddingProvider {\n const kind = getProviderKind(candidate);\n\n return {\n name: candidate.name,\n dimensions: candidate.dimensions,\n async embed(text: string): Promise<number[]> {\n try {\n return await candidate.embed(text);\n } catch (error) {\n if (kind === 'api' && getEmbeddingMode() === 'auto' && isTemporaryEmbeddingFailure(error)) {\n warnOnce('[memorix] API embedding temporarily unavailable — switching to local fallback provider');\n const fallback = await createLocalFallbackProvider();\n if (fallback) {\n provider = wrapProvider(fallback);\n warnOnce(`[memorix] Embedding fallback activated: ${provider.name} (${provider.dimensions}d)`);\n return provider.embed(text);\n }\n }\n\n if (isTemporaryEmbeddingFailure(error)) {\n markTemporaryFailure(error);\n }\n throw error;\n }\n },\n async embedBatch(texts: string[]): Promise<number[][]> {\n try {\n return await candidate.embedBatch(texts);\n } catch (error) {\n if (kind === 'api' && getEmbeddingMode() === 'auto' && isTemporaryEmbeddingFailure(error)) {\n warnOnce('[memorix] API embedding temporarily unavailable — switching to local fallback provider');\n const fallback = await createLocalFallbackProvider();\n if (fallback) {\n provider = wrapProvider(fallback);\n warnOnce(`[memorix] Embedding fallback activated: ${provider.name} (${provider.dimensions}d)`);\n return provider.embedBatch(texts);\n }\n }\n\n if (isTemporaryEmbeddingFailure(error)) {\n markTemporaryFailure(error);\n }\n throw error;\n }\n },\n ...(candidate.getCachedEmbeddings\n ? {\n async getCachedEmbeddings(texts: string[]): Promise<(number[] | null)[]> {\n return candidate.getCachedEmbeddings!(texts);\n },\n }\n : {}),\n };\n}\n\n/** Minimum interval between retry attempts after a temporary failure (ms). */\nconst RETRY_COOLDOWN_MS = 30_000;\nlet lastFailureTimestamp = 0;\n\n/**\n * Get the embedding provider. Returns null if disabled or unavailable.\n * Lazy-initialized on first call. Concurrent callers share the same Promise.\n *\n * Recovery semantics:\n * - mode === 'off' → permanently null (no retry)\n * - mode === 'auto' and NO local provider installed → permanently null (no retry)\n * - provider init failed due to network/API/temp error → retry after cooldown\n *\n * Controlled by MEMORIX_EMBEDDING environment variable (default: off).\n */\nexport async function getEmbeddingProvider(\n options: GetEmbeddingProviderOptions = {},\n): Promise<EmbeddingProvider | null> {\n // If we already have a successfully initialized provider, return it immediately\n if (provider) return provider;\n\n // Startup hydration is allowed to use API vectors already described by local\n // dimension metadata, but it must never turn a missing cache into a network\n // probe. A normal retrieval/write path will initialize the provider later.\n if (options.allowNetworkProbe === false) {\n const mode = getEmbeddingMode();\n if (mode !== 'api' && !(mode === 'auto' && hasAPIEmbeddingConfig())) {\n return null;\n }\n const cached = await createAPIProvider({ allowNetworkProbe: false });\n return cached ? wrapProvider(cached) : null;\n }\n\n // If a previous attempt failed temporarily, allow retry after cooldown\n if (lastInitWasTemporaryFailure) {\n const elapsed = Date.now() - lastFailureTimestamp;\n if (elapsed < RETRY_COOLDOWN_MS) {\n // Still within cooldown — return cached null without retrying\n return null;\n }\n // Cooldown expired — clear cached promise to allow retry\n initPromise = null;\n lastInitWasTemporaryFailure = false;\n }\n\n if (initPromise) return initPromise;\n\n initPromise = (async () => {\n const mode = getEmbeddingMode();\n\n // Explicit OFF — skip all embedding initialization (permanent, no retry)\n if (mode === 'off') {\n warnOnce('[memorix] Embedding disabled (MEMORIX_EMBEDDING=off) — using BM25 fulltext search');\n return null;\n }\n\n // Explicit fastembed\n if (mode === 'fastembed') {\n const initialized = await createFastEmbedProvider();\n if (!initialized) return null;\n provider = wrapProvider(initialized);\n warnOnce(`[memorix] Embedding provider: ${provider.name} (${provider.dimensions}d)`);\n return provider;\n }\n\n // Explicit transformers\n if (mode === 'transformers') {\n const initialized = await createTransformersProvider();\n if (!initialized) return null;\n provider = wrapProvider(initialized);\n warnOnce(`[memorix] Embedding provider: ${provider.name} (${provider.dimensions}d)`);\n return provider;\n }\n\n // API mode: remote embedding via OpenAI-compatible endpoint\n if (mode === 'api') {\n const initialized = await createAPIProvider();\n if (!initialized) return null;\n provider = wrapProvider(initialized);\n warnOnce(`[memorix] Embedding provider: ${provider.name} (${provider.dimensions}d)`);\n return provider;\n }\n\n // Auto mode: try configured API first, then local fallbacks\n if (hasAPIEmbeddingConfig()) {\n const initialized = await createAPIProvider();\n if (initialized) {\n provider = wrapProvider(initialized);\n warnOnce(`[memorix] Embedding provider: ${provider.name} (${provider.dimensions}d)`);\n return provider;\n }\n }\n\n const localFallback = await createLocalFallbackProvider();\n if (localFallback) {\n provider = wrapProvider(localFallback);\n warnOnce(`[memorix] Embedding provider: ${provider.name} (${provider.dimensions}d)`);\n return provider;\n }\n\n warnOnce('[memorix] No embedding provider available — using BM25 fulltext search');\n return null;\n })();\n\n // After the init promise resolves, decide whether to cache or allow retry\n const result = await initPromise;\n if (result === null && !isEmbeddingExplicitlyDisabled()) {\n // Temporary failure — mark for retry and record timestamp\n const mode = getEmbeddingMode();\n // 'auto' mode with no local providers installed is permanent (not retryable)\n if (mode === 'api' || mode === 'fastembed' || mode === 'transformers') {\n lastInitWasTemporaryFailure = true;\n lastFailureTimestamp = Date.now();\n warnOnce(`[memorix] Embedding provider temporarily unavailable — will retry after ${RETRY_COOLDOWN_MS / 1000}s`);\n }\n // 'auto' with no providers → permanent null, no retry needed\n }\n\n return result;\n}\n\n/**\n * Check if vector search is available.\n */\nexport async function isVectorSearchAvailable(): Promise<boolean> {\n const p = await getEmbeddingProvider();\n return p !== null;\n}\n\n/**\n * Check if embedding is explicitly disabled by configuration (mode === 'off').\n *\n * When true, there is no provider to backfill from and observations can be\n * safely removed from the vector-missing queue.\n *\n * When false, the provider MAY still be null due to initialization failure,\n * API error, or missing dependencies — in those cases the observation should\n * stay in the backfill queue for later retry.\n */\nexport function isEmbeddingExplicitlyDisabled(): boolean {\n return getEmbeddingMode() === 'off';\n}\n\n/**\n * Reset provider (for testing).\n */\nexport function resetProvider(): void {\n provider = null;\n initPromise = null;\n lastInitWasTemporaryFailure = false;\n lastFailureTimestamp = 0;\n lastEmbeddingWarning = '';\n lastEmbeddingWarningAt = 0;\n}\n","/**\n * Project Affinity Scoring\n *\n * Prevents cross-project memory pollution by scoring search results\n * based on how well they match the current project context.\n *\n * Inspired by mcp-memory-service's memory-scorer.js:\n * - High affinity: content mentions project name → full score\n * - Medium affinity: related concepts but no direct mention → 0.7x\n * - Low affinity: no project reference → 0.3x (heavily penalized)\n *\n * This runs AFTER projectId filtering, as a second layer of defense\n * against memories that were stored under the correct projectId but\n * contain content about a different project (e.g., discussing Memorix\n * development while in a test project workspace).\n */\n\nexport interface AffinityContext {\n /** Current project name (e.g., \"for_memmcp_test\", \"memorix\") */\n projectName: string;\n /** Current project ID (e.g., \"local/for_memmcp_test\", \"AVIDS2/memorix\") */\n projectId: string;\n /** Optional: keywords that indicate project relevance */\n projectKeywords?: string[];\n}\n\nexport interface MemoryContent {\n title: string;\n narrative?: string;\n facts?: string[];\n concepts?: string[];\n entityName?: string;\n filesModified?: string[];\n}\n\nexport interface AffinityResult {\n /** Affinity score 0-1 (1 = high affinity, 0 = no affinity) */\n score: number;\n /** Affinity level for debugging */\n level: 'high' | 'medium' | 'low' | 'none';\n /** Reason for the score */\n reason: string;\n}\n\n/**\n * Calculate project affinity score for a memory.\n *\n * @param memory - The memory content to evaluate\n * @param context - Current project context\n * @returns AffinityResult with score, level, and reason\n */\nexport function calculateProjectAffinity(\n memory: MemoryContent,\n context: AffinityContext,\n): AffinityResult {\n const projectName = context.projectName.toLowerCase();\n const projectId = context.projectId.toLowerCase();\n \n // Extract base name from projectId (e.g., \"memorix\" from \"AVIDS2/memorix\")\n const projectBaseName = projectId.split('/').pop() ?? projectName;\n \n // Build searchable content string\n const contentParts = [\n memory.title,\n memory.narrative ?? '',\n memory.entityName ?? '',\n ...(memory.facts ?? []),\n ...(memory.concepts ?? []),\n ...(memory.filesModified ?? []),\n ];\n const content = contentParts.join(' ').toLowerCase();\n \n // Check for direct project name mention\n if (content.includes(projectName) || content.includes(projectBaseName)) {\n return { score: 1.0, level: 'high', reason: 'project_name_in_content' };\n }\n \n // Check for project keywords (if provided)\n if (context.projectKeywords && context.projectKeywords.length > 0) {\n const keywordsLower = context.projectKeywords.map(k => k.toLowerCase());\n const matchedKeywords = keywordsLower.filter(k => content.includes(k));\n if (matchedKeywords.length >= 2) {\n return { score: 0.9, level: 'high', reason: `keywords_matched: ${matchedKeywords.join(', ')}` };\n }\n if (matchedKeywords.length === 1) {\n return { score: 0.7, level: 'medium', reason: `keyword_matched: ${matchedKeywords[0]}` };\n }\n }\n \n // Check for file paths that suggest project relevance\n const files = memory.filesModified ?? [];\n if (files.some(f => f.toLowerCase().includes(projectName) || f.toLowerCase().includes(projectBaseName))) {\n return { score: 0.85, level: 'high', reason: 'project_in_file_path' };\n }\n \n // Check entity name\n if (memory.entityName) {\n const entityLower = memory.entityName.toLowerCase();\n if (entityLower.includes(projectName) || entityLower.includes(projectBaseName)) {\n return { score: 0.8, level: 'high', reason: 'project_in_entity' };\n }\n }\n \n // Check concepts for project-related terms\n const concepts = memory.concepts ?? [];\n if (concepts.some(c => c.toLowerCase().includes(projectName) || c.toLowerCase().includes(projectBaseName))) {\n return { score: 0.75, level: 'medium', reason: 'project_in_concepts' };\n }\n \n // No project reference found — this memory might be about a different project\n // Apply penalty but don't completely filter (might still be relevant)\n return { score: 0.65, level: 'low', reason: 'no_project_reference' };\n}\n\n/**\n * Apply project affinity scoring to search results.\n *\n * @param results - Search results with scores\n * @param memories - Full memory content for each result (keyed by ID)\n * @param context - Current project context\n * @param options - Scoring options\n * @returns Results with adjusted scores, sorted by affinity-weighted score\n */\nexport function applyProjectAffinity<T extends { id: number; score: number }>(\n results: T[],\n memories: Map<number, MemoryContent>,\n context: AffinityContext,\n options: {\n /** Minimum affinity score to include (default: 0, include all) */\n minAffinity?: number;\n /** Whether to filter out low-affinity results entirely (default: false) */\n filterLowAffinity?: boolean;\n } = {},\n): T[] {\n const { minAffinity = 0, filterLowAffinity = false } = options;\n \n // Calculate affinity for each result\n const withAffinity = results.map(result => {\n const memory = memories.get(result.id);\n if (!memory) {\n // No memory content available — assume medium affinity\n return { ...result, affinity: 0.5, affinityLevel: 'medium' as const };\n }\n \n const { score: affinityScore, level } = calculateProjectAffinity(memory, context);\n return {\n ...result,\n score: result.score * affinityScore, // Apply affinity as multiplier\n affinity: affinityScore,\n affinityLevel: level,\n };\n });\n \n // Filter by minimum affinity if requested\n let filtered = withAffinity;\n if (filterLowAffinity) {\n filtered = withAffinity.filter(r => r.affinity >= 0.5);\n } else if (minAffinity > 0) {\n filtered = withAffinity.filter(r => r.affinity >= minAffinity);\n }\n \n // Re-sort by affinity-weighted score\n filtered.sort((a, b) => b.score - a.score);\n \n // Return without the extra affinity fields (keep original shape)\n return filtered.map(({ affinity: _, affinityLevel: __, ...rest }) => rest as T);\n}\n\n/**\n * Extract project keywords from project name and common patterns.\n * Used to improve affinity detection for projects with distinctive names.\n */\nexport function extractProjectKeywords(projectName: string, projectId: string): string[] {\n const keywords: string[] = [projectName];\n \n // Add base name from projectId\n const baseName = projectId.split('/').pop();\n if (baseName && baseName !== projectName) {\n keywords.push(baseName);\n }\n \n // Add common variations\n const variations = [\n projectName.replace(/-/g, '_'),\n projectName.replace(/_/g, '-'),\n projectName.replace(/[_-]/g, ''),\n ];\n for (const v of variations) {\n if (v !== projectName && !keywords.includes(v)) {\n keywords.push(v);\n }\n }\n \n return keywords.filter(k => k.length > 2);\n}\n","/**\n * Intent-Aware Recall — Query Intent Detection\n *\n * Detects the underlying intent of a search query (why/when/how/what)\n * and returns type-specific boosting factors to improve recall precision.\n *\n * Inspired by MemCP's intent routing architecture.\n * Uses fast keyword/pattern matching (no LLM needed).\n */\n\nimport type { ObservationType } from '../types.js';\n\n// ─── Types ───\n\nexport type QueryIntent = 'why' | 'when' | 'how' | 'what_changed' | 'problem' | 'general';\n\nexport interface IntentResult {\n /** Detected intent category */\n intent: QueryIntent;\n /** Confidence score 0-1 */\n confidence: number;\n /** Observation type → boost multiplier (applied to search scores) */\n typeBoosts: Partial<Record<ObservationType, number>>;\n /** Field weight overrides for Orama search (optional) */\n fieldBoosts?: Record<string, number>;\n /** Whether to prefer chronological ordering over relevance */\n preferChronological: boolean;\n /** Source → boost multiplier for source-aware retrieval */\n sourceBoosts?: Partial<Record<'agent' | 'git' | 'manual', number>>;\n}\n\n// ─── Intent Patterns ───\n\ninterface IntentPattern {\n intent: QueryIntent;\n patterns: RegExp[];\n /** Higher weight = stronger match when multiple intents match */\n weight: number;\n}\n\nconst INTENT_PATTERNS: IntentPattern[] = [\n {\n intent: 'why',\n patterns: [\n /\\bwhy\\b/i,\n /\\breason(?:s|ing)?\\b/i,\n /\\brationale\\b/i,\n /\\bmotivat(?:ion|ed)\\b/i,\n /\\bjustif(?:y|ication)\\b/i,\n /\\bchose|chosen|picked\\b/i,\n /\\bdecid(?:e[ds]?|ing)\\b/i,\n /\\btrade-?off\\b/i,\n /为什么/,\n /原因/,\n /理由/,\n /为何/,\n ],\n weight: 1.0,\n },\n {\n intent: 'when',\n patterns: [\n /\\bwhen\\b/i,\n /\\btimeline\\b/i,\n /\\bhistory\\b/i,\n /\\blast\\s+(week|month|time|session)\\b/i,\n /\\brecent(?:ly)?\\b/i,\n /\\byesterday\\b/i,\n /\\btoday\\b/i,\n /\\bchronolog/i,\n /什么时候/,\n /何时/,\n /最近/,\n /上次/,\n ],\n weight: 0.9,\n },\n {\n intent: 'how',\n patterns: [\n /\\bhow\\s+(does|do|to|is|can|did|should|would)\\b/i,\n /\\barchitecture\\b/i,\n /\\bmechanism\\b/i,\n /\\bimplement(?:ation|ed|ing)?\\b/i,\n /\\bwork(?:s|ing|ed)?\\b/i,\n /\\bexplain\\b/i,\n /\\bunderstand\\b/i,\n /怎么/,\n /如何/,\n /机制/,\n /原理/,\n /架构/,\n ],\n weight: 0.85,\n },\n {\n intent: 'what_changed',\n patterns: [\n /\\bwhat\\s+changed\\b/i,\n /\\bwhat\\s+was\\s+(modified|updated|changed)\\b/i,\n /\\bdiff(?:erence)?\\b/i,\n /\\bchangelog\\b/i,\n /\\bmodifi(?:ed|cation)\\b/i,\n /\\bupdat(?:e[ds]?|ing)\\b/i,\n /\\brefactor(?:ed|ing)?\\b/i,\n /改了/,\n /修改/,\n /变更/,\n /变化/,\n ],\n weight: 0.8,\n },\n {\n intent: 'problem',\n patterns: [\n /\\bbug(?:s|gy)?\\b/i,\n /\\berror(?:s)?\\b/i,\n /\\bfix(?:e[ds]|ing)?\\b/i,\n /\\bissue(?:s)?\\b/i,\n /\\bproblem(?:s)?\\b/i,\n /\\bcrash(?:e[ds]|ing)?\\b/i,\n /\\bfail(?:e[ds]|ure|ing)?\\b/i,\n /\\bbroken\\b/i,\n /\\bgotcha\\b/i,\n /\\bpitfall\\b/i,\n /\\bworkaround\\b/i,\n /\\btroubleshoot/i,\n /\\bdebug(?:ging)?\\b/i,\n /报错/,\n /问题/,\n /修复/,\n /故障/,\n /异常/,\n ],\n weight: 0.9,\n },\n];\n\n// ─── Type Boost Maps ───\n\nconst INTENT_TYPE_BOOSTS: Record<QueryIntent, Partial<Record<ObservationType, number>>> = {\n why: {\n 'decision': 3.0,\n 'why-it-exists': 3.0,\n 'trade-off': 2.5,\n 'how-it-works': 1.2,\n },\n when: {\n // Temporal queries don't strongly prefer any type — they prefer recency\n 'what-changed': 1.5,\n 'session-request': 1.3,\n },\n how: {\n 'how-it-works': 3.0,\n 'discovery': 2.0,\n 'decision': 1.3,\n },\n what_changed: {\n 'what-changed': 3.0,\n 'discovery': 1.5,\n 'session-request': 1.2,\n },\n problem: {\n 'problem-solution': 3.0,\n 'gotcha': 2.5,\n 'discovery': 1.3,\n },\n general: {\n // No special boosting\n },\n};\n\n// ─── Source Boost Maps ───\n// Maps intent to preferred memory sources for source-aware retrieval.\n// git source = ground truth (commits), agent source = reasoning/decisions.\n\nconst INTENT_SOURCE_BOOSTS: Partial<Record<QueryIntent, Partial<Record<'agent' | 'git' | 'manual', number>>>> = {\n what_changed: {\n git: 2.0, // \"what changed\" → prefer commit-derived ground truth\n agent: 0.8,\n },\n when: {\n git: 1.8, // Temporal queries → git has precise timestamps\n agent: 1.0,\n },\n why: {\n agent: 2.0, // \"why\" → prefer reasoning/decision memories\n git: 0.7, // commits rarely explain WHY\n },\n how: {\n agent: 1.5, // \"how\" → prefer explanations\n git: 1.0,\n },\n problem: {\n git: 1.5, // Bug fixes often in commit history\n agent: 1.5, // But also in problem-solution memories\n },\n};\n\nconst INTENT_FIELD_BOOSTS: Partial<Record<QueryIntent, Record<string, number>>> = {\n why: {\n title: 2,\n entityName: 1.5,\n narrative: 2.5, // WHY queries need narrative context\n facts: 1.5,\n concepts: 1,\n filesModified: 0.3,\n },\n problem: {\n title: 3,\n entityName: 2,\n narrative: 2,\n facts: 2, // Bug details often in facts\n concepts: 1,\n filesModified: 1.5, // File paths help find the right bug fix\n },\n};\n\n// ─── Detection ───\n\n/**\n * Detect the intent of a search query.\n *\n * Returns the best matching intent with confidence score and\n * type-specific boosting factors to apply during search.\n */\nexport function detectQueryIntent(query: string): IntentResult {\n if (!query || query.length < 2) {\n return {\n intent: 'general',\n confidence: 0,\n typeBoosts: {},\n preferChronological: false,\n };\n }\n\n let bestIntent: QueryIntent = 'general';\n let bestScore = 0;\n let totalMatches = 0;\n\n for (const { intent, patterns, weight } of INTENT_PATTERNS) {\n let matchCount = 0;\n for (const pattern of patterns) {\n if (pattern.test(query)) matchCount++;\n }\n if (matchCount > 0) {\n const score = matchCount * weight;\n totalMatches += matchCount;\n if (score > bestScore) {\n bestScore = score;\n bestIntent = intent;\n }\n }\n }\n\n // Confidence: how strongly did we match vs. random noise\n const confidence = totalMatches === 0\n ? 0\n : Math.min(1, bestScore / 2); // 2+ pattern matches → high confidence\n\n return {\n intent: bestIntent,\n confidence,\n typeBoosts: INTENT_TYPE_BOOSTS[bestIntent],\n fieldBoosts: INTENT_FIELD_BOOSTS[bestIntent],\n sourceBoosts: INTENT_SOURCE_BOOSTS[bestIntent],\n preferChronological: bestIntent === 'when',\n };\n}\n\n/**\n * Apply intent-based type boosting to a search result's score.\n *\n * @param score Original search score\n * @param type Observation type of the result\n * @param intentResult Detected intent from detectQueryIntent()\n * @returns Boosted score\n */\nexport function applyIntentBoost(\n score: number,\n type: string,\n intentResult: IntentResult,\n): number {\n if (intentResult.confidence < 0.3) return score; // Low confidence → no boost\n const boost = intentResult.typeBoosts[type as ObservationType] ?? 1.0;\n // Scale boost by confidence: full boost at confidence=1, partial at lower\n const effectiveBoost = 1 + (boost - 1) * intentResult.confidence;\n return score * effectiveBoost;\n}\n","import { callLLM, initLLM, isLLMEnabled } from '../llm/provider.js';\n\nconst CJK_PATTERN = /[\\u4e00-\\u9fff\\u3040-\\u309f\\u30a0-\\u30ff\\uac00-\\ud7af]/g;\nconst COMMAND_LIKE_QUERY = /\\b(git|npm|npx|pnpm|yarn|node|bash|powershell|curl|memorix)\\b/i;\n\nconst QUERY_EXPANSION_PROMPT = `You rewrite coding-memory search queries for retrieval.\n\nRules:\n- Input may be Chinese, Japanese, or Korean\n- Output one short English search phrase only\n- Keep the technical meaning\n- Prefer wording that would match engineering notes or memory titles\n- No bullets, no JSON, no explanation, no quotes\n- 4 to 12 words is ideal`;\n\nfunction isCjkHeavy(query: string): boolean {\n const cjkCount = (query.match(CJK_PATTERN) || []).length;\n return query.length > 0 && cjkCount / query.length > 0.3;\n}\n\nfunction normalizeExpansion(text: string): string {\n return text\n .trim()\n .replace(/^[-*]\\s*/, '')\n .replace(/^[\"'`]+|[\"'`]+$/g, '')\n .split(/\\r?\\n/)[0]\n .trim();\n}\n\nexport async function maybeExpandSearchQuery(query: string): Promise<string> {\n if (!query || !isCjkHeavy(query) || COMMAND_LIKE_QUERY.test(query)) {\n return query;\n }\n\n if (!isLLMEnabled()) {\n initLLM();\n }\n\n if (!isLLMEnabled()) {\n return query;\n }\n\n try {\n const response = await callLLM(QUERY_EXPANSION_PROMPT, query);\n const expanded = normalizeExpansion(response.content);\n if (!expanded) return query;\n if (expanded.toLowerCase() === query.toLowerCase()) return query;\n return `${query} ${expanded}`.slice(0, 500);\n } catch {\n return query;\n }\n}\n","/**\n * Run an operation with a bounded wait without leaving its watchdog alive.\n *\n * The underlying operation is not force-cancelled because many existing\n * callers do not expose an AbortSignal. Its settlement is still observed so a\n * late rejection is handled, while the caller receives the timeout promptly.\n */\nexport function withTimeout<T>(promise: Promise<T>, ms: number, label: string): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n const timer = setTimeout(() => reject(new Error(`${label} timed out after ${ms}ms`)), ms);\n\n promise.then(\n (value) => {\n clearTimeout(timer);\n resolve(value);\n },\n (error) => {\n clearTimeout(timer);\n reject(error);\n },\n );\n });\n}\n","/**\n * Project Alias Registry\n *\n * Solves the \"project identity split\" problem: the same project gets different\n * projectIds depending on which IDE detects it (git remote vs local path vs placeholder).\n *\n * Maintains a registry file (~/.memorix/data/.project-aliases.json) that groups\n * all known IDs for the same physical project under one canonical ID.\n *\n * Canonical ID priority: git remote > local > placeholder\n *\n * Matching heuristics (any match → same project):\n * 1. Same normalized rootPath\n * 2. Same git remote URL\n */\n\nimport { promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport os from 'node:os';\nimport type { ProjectInfo } from '../types.js';\n\nconst DEFAULT_DATA_DIR = process.env.MEMORIX_DATA_DIR || path.join(os.homedir(), '.memorix', 'data');\nconst ALIAS_FILE = '.project-aliases.json';\n\n/** A group of project IDs that all refer to the same physical project */\nexport interface AliasGroup {\n /** The best-known ID for this project (git remote > local > placeholder) */\n canonical: string;\n /** All known IDs including canonical */\n aliases: string[];\n /** All known root paths (normalized) for this project */\n rootPaths: string[];\n /** Git remote URL if known */\n gitRemote?: string;\n}\n\ninterface AliasRegistry {\n version: 1;\n groups: AliasGroup[];\n}\n\n/** In-memory cache of the registry */\nlet registryCache: AliasRegistry | null = null;\nlet registryDir: string | null = null;\n\n/**\n * Normalize a root path for comparison.\n * - Forward slashes\n * - Lowercase on Windows\n * - No trailing slash\n */\nfunction normalizePath(p: string): string {\n let normalized = p.replace(/\\\\/g, '/').replace(/\\/+$/, '');\n if (process.platform === 'win32') {\n normalized = normalized.toLowerCase();\n }\n return normalized;\n}\n\n/**\n * Determine the priority of a project ID prefix.\n * Higher = better canonical candidate.\n */\nfunction idPriority(id: string): number {\n if (id.startsWith('untracked/')) return 0;\n if (id.startsWith('local/')) return 1;\n // Git remote-based IDs (e.g., \"user/repo\") have no prefix → highest priority\n return 2;\n}\n\n/**\n * Get the alias registry file path.\n */\nfunction getRegistryPath(baseDir?: string): string {\n return path.join(baseDir ?? registryDir ?? DEFAULT_DATA_DIR, ALIAS_FILE);\n}\n\n/**\n * Load the alias registry from disk.\n */\nasync function loadRegistry(baseDir?: string): Promise<AliasRegistry> {\n if (registryCache) return registryCache;\n try {\n const data = await fs.readFile(getRegistryPath(baseDir), 'utf-8');\n const parsed = JSON.parse(data);\n if (parsed.version === 1 && Array.isArray(parsed.groups)) {\n registryCache = parsed;\n return registryCache!;\n }\n } catch { /* file doesn't exist yet */ }\n registryCache = { version: 1, groups: [] };\n return registryCache;\n}\n\n/**\n * Save the alias registry to disk.\n */\nasync function saveRegistry(baseDir?: string): Promise<void> {\n if (!registryCache) return;\n const filePath = getRegistryPath(baseDir);\n await fs.mkdir(path.dirname(filePath), { recursive: true });\n await fs.writeFile(filePath, JSON.stringify(registryCache, null, 2), 'utf-8');\n}\n\n/**\n * Find an existing alias group that matches the given project info.\n *\n * Match criteria (any one is sufficient):\n * 1. Group already contains this exact ID\n * 2. Group has a matching normalized rootPath\n * 3. Group has a matching gitRemote\n */\nfunction findMatchingGroup(\n registry: AliasRegistry,\n projectInfo: ProjectInfo,\n): AliasGroup | null {\n const normalizedRoot = normalizePath(projectInfo.rootPath);\n\n for (const group of registry.groups) {\n // Match by ID\n if (group.aliases.includes(projectInfo.id)) return group;\n\n // Match by rootPath\n if (group.rootPaths.some((rp) => rp === normalizedRoot)) return group;\n\n // Match by git remote\n if (projectInfo.gitRemote && group.gitRemote && group.gitRemote === projectInfo.gitRemote) {\n return group;\n }\n }\n\n return null;\n}\n\n/**\n * Select the best canonical ID from a list of aliases.\n * Priority: git remote-based > local > placeholder\n */\nfunction selectCanonical(aliases: string[]): string {\n return [...aliases].sort((a, b) => idPriority(b) - idPriority(a))[0];\n}\n\n/**\n * Register a detected project in the alias registry.\n *\n * If the project matches an existing group, merges the new ID/rootPath into it.\n * If not, creates a new group.\n *\n * Returns the **canonical** project ID that should be used for storage and search.\n *\n * @param projectInfo - The detected project info from detectProject()\n * @param baseDir - Override data directory (for testing)\n * @returns The canonical project ID\n */\nexport async function registerAlias(projectInfo: ProjectInfo, baseDir?: string): Promise<string> {\n const registry = await loadRegistry(baseDir);\n const normalizedRoot = normalizePath(projectInfo.rootPath);\n\n const existingGroup = findMatchingGroup(registry, projectInfo);\n\n if (existingGroup) {\n // Merge into existing group\n let changed = false;\n\n if (!existingGroup.aliases.includes(projectInfo.id)) {\n existingGroup.aliases.push(projectInfo.id);\n changed = true;\n }\n\n if (!existingGroup.rootPaths.includes(normalizedRoot)) {\n existingGroup.rootPaths.push(normalizedRoot);\n changed = true;\n }\n\n if (projectInfo.gitRemote && !existingGroup.gitRemote) {\n existingGroup.gitRemote = projectInfo.gitRemote;\n changed = true;\n }\n\n // Re-evaluate canonical (maybe we just learned a git remote ID)\n const newCanonical = selectCanonical(existingGroup.aliases);\n if (newCanonical !== existingGroup.canonical) {\n existingGroup.canonical = newCanonical;\n changed = true;\n }\n\n if (changed) {\n await saveRegistry(baseDir);\n }\n\n return existingGroup.canonical;\n }\n\n // Create new group\n const newGroup: AliasGroup = {\n canonical: projectInfo.id,\n aliases: [projectInfo.id],\n rootPaths: [normalizedRoot],\n ...(projectInfo.gitRemote ? { gitRemote: projectInfo.gitRemote } : {}),\n };\n registry.groups.push(newGroup);\n await saveRegistry(baseDir);\n\n return newGroup.canonical;\n}\n\n/**\n * Resolve all known aliases for a project ID.\n *\n * Used in search to expand the projectId filter so that observations stored\n * under any alias are found regardless of which IDE stored them.\n *\n * @returns Array of all known IDs for the same project, or [projectId] if no aliases found.\n */\nexport async function resolveAliases(projectId: string, baseDir?: string): Promise<string[]> {\n const registry = await loadRegistry(baseDir);\n\n for (const group of registry.groups) {\n if (group.aliases.includes(projectId) || group.canonical === projectId) {\n return [...group.aliases];\n }\n }\n\n return [projectId];\n}\n\n/**\n * Get the canonical ID for a project ID.\n *\n * @returns The canonical ID, or the input ID if no alias group found.\n */\nexport async function getCanonicalId(projectId: string, baseDir?: string): Promise<string> {\n const registry = await loadRegistry(baseDir);\n\n for (const group of registry.groups) {\n if (group.aliases.includes(projectId) || group.canonical === projectId) {\n return group.canonical;\n }\n }\n\n return projectId;\n}\n\n/**\n * Get all alias groups (for dashboard/debug).\n */\nexport async function getAllAliasGroups(baseDir?: string): Promise<AliasGroup[]> {\n const registry = await loadRegistry(baseDir);\n return registry.groups;\n}\n\n/**\n * Auto-merge obvious alias groups by scanning existing observation projectIds.\n *\n * Detects project IDs that share the same base name but have different prefixes:\n * - placeholder/foo + local/foo → merge under the higher-priority one\n * - AVIDS2/test-repo + local/test-repo → merge under AVIDS2/test-repo\n *\n * Called once during server startup after observations are loaded.\n *\n * @param observedIds - All unique projectIds found in observations data\n * @returns Number of new merges performed\n */\nexport async function autoMergeByBaseName(\n observedIds: string[],\n baseDir?: string,\n): Promise<number> {\n if (observedIds.length <= 1) return 0;\n\n const registry = await loadRegistry(baseDir);\n\n // Group observed IDs by their base name (the part after the last /)\n const byBaseName = new Map<string, string[]>();\n for (const id of observedIds) {\n const baseName = id.split('/').pop() ?? id;\n if (!byBaseName.has(baseName)) byBaseName.set(baseName, []);\n byBaseName.get(baseName)!.push(id);\n }\n\n let mergeCount = 0;\n\n for (const [_baseName, ids] of byBaseName) {\n if (ids.length <= 1) continue;\n\n // Check if these IDs are already in the same alias group\n const existingGroups = new Set<number>();\n const ungroupedIds: string[] = [];\n\n for (const id of ids) {\n const groupIdx = registry.groups.findIndex(\n g => g.aliases.includes(id) || g.canonical === id,\n );\n if (groupIdx >= 0) {\n existingGroups.add(groupIdx);\n } else {\n ungroupedIds.push(id);\n }\n }\n\n // If all IDs are already in the same group, skip\n if (existingGroups.size <= 1 && ungroupedIds.length === 0) continue;\n\n // Merge: pick the best canonical from all IDs\n const allIdsInGroup = [...ids];\n const canonical = selectCanonical(allIdsInGroup);\n\n if (existingGroups.size > 0) {\n // Merge into the first existing group\n const primaryIdx = [...existingGroups][0];\n const primaryGroup = registry.groups[primaryIdx];\n\n // Add all IDs to primary group\n for (const id of allIdsInGroup) {\n if (!primaryGroup.aliases.includes(id)) {\n primaryGroup.aliases.push(id);\n }\n }\n\n // Absorb other existing groups into primary\n const otherIdxs = [...existingGroups].slice(1).sort((a, b) => b - a);\n for (const idx of otherIdxs) {\n const other = registry.groups[idx];\n for (const alias of other.aliases) {\n if (!primaryGroup.aliases.includes(alias)) {\n primaryGroup.aliases.push(alias);\n }\n }\n for (const rp of other.rootPaths) {\n if (!primaryGroup.rootPaths.includes(rp)) {\n primaryGroup.rootPaths.push(rp);\n }\n }\n if (other.gitRemote && !primaryGroup.gitRemote) {\n primaryGroup.gitRemote = other.gitRemote;\n }\n registry.groups.splice(idx, 1);\n }\n\n // Re-evaluate canonical\n primaryGroup.canonical = selectCanonical(primaryGroup.aliases);\n mergeCount++;\n } else {\n // All ungrouped — create new group\n registry.groups.push({\n canonical,\n aliases: allIdsInGroup,\n rootPaths: [],\n });\n mergeCount++;\n }\n }\n\n if (mergeCount > 0) {\n await saveRegistry(baseDir);\n }\n\n return mergeCount;\n}\n\n/**\n * Initialize the alias registry with a data directory.\n * Should be called once during server startup.\n */\nexport function initAliasRegistry(dataDir: string): void {\n registryDir = dataDir;\n registryCache = null; // Force reload from new location\n}\n\n/**\n * Reset the in-memory cache (for testing).\n */\nexport function resetAliasCache(): void {\n registryCache = null;\n}\n","/**\n * LLM Quality Enhancements\n *\n * Premium memory quality features powered by LLM:\n * 1. Narrative Compression — compress verbose narratives into concise core knowledge\n * 2. Search Reranking — rerank search results by relevance to current task context\n *\n * Both features gracefully degrade: when LLM is not configured, they return\n * the original data unchanged.\n *\n * Performance targets:\n * - Compression: ~60% token reduction per stored memory\n * - Reranking: ~40% improvement in Top-5 precision\n */\n\nimport { callLLM, isLLMEnabled } from './provider.js';\n\n// ── Narrative Compression ────────────────────────────────────────\n\nconst COMPRESS_PROMPT = `You are a memory compression engine for a coding assistant.\n\nCompress the given narrative while preserving ALL technical facts and reasoning.\n\nRules:\n- Remove: filler words, debugging journey, repeated info already in facts\n- Keep: specific values, file paths, error messages, version numbers, config keys, causal relationships, design reasoning\n- Merge related points into dense sentences\n- If facts are provided separately, do NOT repeat them in the compressed narrative\n- Output the compressed text ONLY, no explanation or wrapper\n\nExamples:\nInput: \"我在调试过程中发现JWT token的refresh机制存在问题,具体来说是因为服务端没有实现自动续签,导致用户在24小时后会遇到静默的认证失败,之前我一直以为是网络问题但后来排查发现是token过期了\"\nOutput: \"JWT refresh无自动续签→24h后静默认证失败(非网络问题)\"\n\nInput: \"Final deployment model for shadcn-blog is stable: GitHub Actions build locally, SCP artifacts to VPS, systemd manages the process. Docker was considered but rejected due to complexity overhead for a simple blog. The whole pipeline takes about 2 minutes from push to live.\"\nOutput: \"shadcn-blog部署: GH Actions构建→SCP到VPS→systemd管理, 弃Docker(复杂度过高), push到上线~2min\"`;\n\n/** Gentler prompt for high-value types where reasoning context matters */\nconst COMPRESS_PROMPT_GENTLE = `You are a memory compression engine for a coding assistant.\n\nLightly compress the given narrative — preserve reasoning, trade-offs, and \"why\" context.\n\nRules:\n- Only remove: obvious filler, debugging detours, info already in the separate facts list\n- PRESERVE: design reasoning, rejected alternatives, trade-off analysis, causal chains\n- Aim for ~70-80% of original length, NOT aggressive compression\n- If facts are provided separately, do NOT repeat them in the compressed narrative\n- Output the compressed text ONLY, no explanation or wrapper`;\n\n/**\n * Compress a narrative to its essential core using LLM.\n *\n * Returns the original narrative if:\n * - LLM is not enabled\n * - Narrative is already short (≤80 chars)\n * - Narrative is already concise (commands, file paths, git operations)\n * - LLM call fails\n */\nexport async function compressNarrative(\n narrative: string,\n facts?: string[],\n type?: string,\n): Promise<{ compressed: string; saved: number; usedLLM: boolean }> {\n const originalTokens = estimateTokens(narrative);\n\n // Skip compression for short narratives (≤150 chars is already concise)\n if (!isLLMEnabled() || narrative.length <= 150) {\n return { compressed: narrative, saved: 0, usedLLM: false };\n }\n\n // Skip compression for already-concise content that LLM can't meaningfully compress\n if (shouldSkipCompression(narrative, type)) {\n return { compressed: narrative, saved: 0, usedLLM: false };\n }\n\n try {\n const factsContext = facts && facts.length > 0\n ? `\\n\\nSeparate facts (already stored, don't repeat): ${facts.join('; ')}`\n : '';\n\n // Use gentler compression for high-value types where reasoning matters\n const HIGH_VALUE_TYPES = new Set(['decision', 'trade-off', 'why-it-exists', 'how-it-works']);\n const prompt = (type && HIGH_VALUE_TYPES.has(type)) ? COMPRESS_PROMPT_GENTLE : COMPRESS_PROMPT;\n const response = await callLLM(prompt, narrative + factsContext);\n const compressed = response.content.trim();\n\n // Sanity check: compressed should be shorter and non-empty\n if (!compressed || compressed.length >= narrative.length) {\n return { compressed: narrative, saved: 0, usedLLM: true };\n }\n\n const compressedTokens = estimateTokens(compressed);\n return {\n compressed,\n saved: originalTokens - compressedTokens,\n usedLLM: true,\n };\n } catch {\n return { compressed: narrative, saved: 0, usedLLM: false };\n }\n}\n\n// ── Search Reranking ─────────────────────────────────────────────\n\n/** Minimal search result for reranking */\nexport interface RerankCandidate {\n id: string;\n title: string;\n type: string;\n score: number;\n narrative?: string;\n}\n\nconst RERANK_PROMPT = `You are a memory relevance ranker for a coding assistant.\n\nGiven a QUERY (what the user/agent is looking for) and a list of CANDIDATE memories,\nrerank them by relevance to the query.\n\nRules:\n- Consider semantic relevance, not just keyword overlap\n- Gotchas and decisions related to the query topic should rank higher\n- Recent problem-solutions for the same component should rank higher\n- 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\n- Generic or loosely related memories should rank lower\n- Output ONLY a JSON array of IDs in order of relevance (most relevant first)\n- Include ALL candidate IDs, just reorder them\n\nExample output: [\"r1\", \"r3\", \"r2\"]`;\n\n/**\n * Rerank search results using LLM contextual understanding.\n *\n * Takes Orama's initial ranking and improves it by considering\n * semantic relevance to the current query/task context.\n *\n * Returns original order if LLM is not enabled or call fails.\n */\nexport async function rerankResults(\n query: string,\n candidates: RerankCandidate[],\n): Promise<{ reranked: RerankCandidate[]; usedLLM: boolean }> {\n // Skip if too few results or LLM not available\n if (!isLLMEnabled() || candidates.length <= 2) {\n return { reranked: candidates, usedLLM: false };\n }\n\n // Only rerank top-N to save LLM tokens (reranking 20+ is wasteful)\n const MAX_RERANK = 10;\n const toRerank = candidates.slice(0, MAX_RERANK);\n const rest = candidates.slice(MAX_RERANK);\n\n try {\n const candidateList = toRerank.map(c =>\n `[ID: ${c.id}] (${c.type}) ${c.title}${c.narrative ? ` — ${c.narrative.substring(0, 100)}` : ''}`,\n ).join('\\n');\n\n const response = await callLLM(RERANK_PROMPT, `QUERY: ${query}\\n\\nCANDIDATES:\\n${candidateList}`);\n\n // Parse response — handle markdown code blocks\n let content = response.content.trim();\n if (content.startsWith('```')) {\n content = content.replace(/^```(?:json)?\\s*/, '').replace(/\\s*```$/, '');\n }\n\n const rankedIds = JSON.parse(content) as string[];\n\n // Validate: must be an array of IDs matching our candidates\n if (!Array.isArray(rankedIds) || rankedIds.length === 0) {\n return { reranked: candidates, usedLLM: true };\n }\n\n // Build reranked list preserving original scores for display\n const idMap = new Map(toRerank.map(c => [c.id, c]));\n const reranked: RerankCandidate[] = [];\n const seen = new Set<string>();\n\n // Add IDs in LLM-reranked order\n for (const id of rankedIds) {\n const candidate = idMap.get(id);\n if (candidate && !seen.has(id)) {\n reranked.push(candidate);\n seen.add(id);\n }\n }\n\n // Add any candidates the LLM missed (safety: never lose results)\n for (const c of toRerank) {\n if (!seen.has(c.id)) {\n reranked.push(c);\n }\n }\n\n // Append non-reranked tail\n reranked.push(...rest);\n\n return { reranked, usedLLM: true };\n } catch {\n return { reranked: candidates, usedLLM: false };\n }\n}\n\n// ── Smart Compression Filtering ──────────────────────────────────\n\n/** Patterns that indicate already-concise content not worth compressing */\nconst SKIP_PATTERNS = [\n /^(?:Command|Run|Execute):\\s/i, // Shell commands\n /^(?:File|Edit|Changed):\\s/i, // File change descriptions\n /^git\\s+(?:add|commit|push|pull|log)/i, // Git operations\n /^(?:npm|npx|pnpm|yarn|bun)\\s/i, // Package manager commands\n /^(?:Remove-Item|New-Item|Set-Content)/i, // PowerShell commands\n /^[A-Za-z]:\\\\[\\w\\\\]/, // Windows file paths\n /^\\/(?:usr|home|var|etc|opt)\\//, // Unix file paths\n];\n\n/** Low-value observation types that hooks auto-capture (usually already terse) */\nconst LOW_COMPRESSION_TYPES = new Set(['what-changed', 'discovery', 'session-request']);\n\n/**\n * Determine if a narrative should skip LLM compression.\n *\n * Skip when:\n * - Content starts with command/path patterns (already structured, not prose)\n * - Type is hooks-auto-captured AND narrative is relatively short\n * - Narrative is mostly code/paths (high ratio of special chars)\n */\nfunction shouldSkipCompression(narrative: string, type?: string): boolean {\n // Skip command/path-like content\n const firstLine = narrative.split('\\n')[0];\n if (SKIP_PATTERNS.some(p => p.test(firstLine))) return true;\n\n // Skip short auto-captured observations (hooks produce terse what-changed)\n if (type && LOW_COMPRESSION_TYPES.has(type) && narrative.length < 200) return true;\n\n // Skip if narrative is mostly code/structured data (high special char ratio)\n const specialChars = (narrative.match(/[{}()\\[\\]<>:;=|\\\\\\/\\-_\\.@#$%^&*+~`\"']/g) || []).length;\n if (specialChars / narrative.length > 0.35) return true;\n\n return false;\n}\n\n// ── Utility ──────────────────────────────────────────────────────\n\n/** Rough token estimate: ~4 chars per token for English, ~2 for CJK */\nfunction estimateTokens(text: string): number {\n const cjkChars = (text.match(/[\\u4e00-\\u9fff\\u3040-\\u309f\\u30a0-\\u30ff\\uac00-\\ud7af]/g) || []).length;\n const otherChars = text.length - cjkChars;\n return Math.ceil(cjkChars / 1.5 + otherChars / 4);\n}\n","/**\n * Unified Freshness Gate (Phase 3a)\n *\n * Replaces withFreshObservations() as the public API for all retrieval\n * surfaces. Checks both observation and mini-skill generation counters\n * to ensure the Orama index is fully up-to-date before any read.\n *\n * withFreshObservations() remains in observations.ts as @internal —\n * only called by this module and legacy test code.\n */\n\nimport { ensureFreshObservations } from './observations.js';\nimport { getMiniSkillStore, isMiniSkillStoreInitialized } from '../store/mini-skill-store.js';\nimport { miniSkillToDocument } from '../skills/mini-skills.js';\nimport { insert, remove } from '@orama/orama';\n\n// ── Mini-skill index state ──────────────────────────────────────\n\nlet lastMiniSkillGeneration = -1;\n\n/**\n * Check if mini-skills have changed since our last index sync.\n * If stale, reindex all mini-skills in Orama.\n *\n * Returns true if the index was refreshed.\n */\nexport async function ensureFreshMiniSkills(): Promise<boolean> {\n // Skip silently when the store has not been initialized yet —\n // observation-only paths never call initMiniSkillStore().\n if (!isMiniSkillStoreInitialized()) return false;\n\n try {\n const store = getMiniSkillStore();\n const wasStale = await store.ensureFresh();\n const currentGen = store.getGeneration();\n\n if (wasStale || currentGen !== lastMiniSkillGeneration) {\n await reindexMiniSkills();\n lastMiniSkillGeneration = currentGen;\n return true;\n }\n } catch (err) {\n // Best-effort — don't crash the read path, but log for diagnostics\n console.warn(`[memorix] ensureFreshMiniSkills failed: ${err instanceof Error ? err.message : err}`);\n }\n return false;\n}\n\n// Deterministic tracking of indexed mini-skill doc IDs — avoids empty-term search\nconst indexedSkillDocIds = new Set<string>();\n\n/**\n * Reindex all mini-skills into the Orama database.\n * Uses deterministic doc ID tracking instead of empty-term search to ensure\n * all stale documents are removed reliably.\n */\nexport async function reindexMiniSkills(): Promise<number> {\n // Lazy import to avoid circular dependency\n const { getDb } = await import('../store/orama-store.js');\n const database = await getDb();\n\n // Remove previously tracked mini-skill documents by their known IDs\n for (const docId of indexedSkillDocIds) {\n try { await remove(database, docId); } catch { /* already removed or never existed */ }\n }\n indexedSkillDocIds.clear();\n\n // Load and index all current mini-skills\n const store = getMiniSkillStore();\n const skills = await store.loadAll();\n let indexed = 0;\n\n for (const skill of skills) {\n try {\n const doc = miniSkillToDocument(skill);\n await insert(database, doc);\n indexedSkillDocIds.add(doc.id);\n indexed++;\n } catch (err) {\n console.error(`[memorix] Failed to index mini-skill ${skill.id}: ${err instanceof Error ? err.message : err}`);\n }\n }\n\n return indexed;\n}\n\n// ── Unified gate ────────────────────────────────────────────────\n\n/**\n * Ensure both observations and mini-skills are fresh in the Orama index.\n * Returns true if any data source was refreshed.\n */\nexport async function ensureFreshIndex(): Promise<boolean> {\n let anyStale = false;\n const obsStale = await ensureFreshObservations();\n if (obsStale) anyStale = true;\n const skillsStale = await ensureFreshMiniSkills();\n if (skillsStale) anyStale = true;\n return anyStale;\n}\n\n/**\n * Centralized freshness gate — wraps a read-facing function with\n * ensureFreshIndex() so callers cannot forget the freshness check.\n *\n * Usage:\n * return withFreshIndex(async () => { ... read from Orama ... });\n *\n * Phase 3a: replaces withFreshObservations() at all retrieval call sites.\n */\nexport async function withFreshIndex<T>(fn: () => T | Promise<T>): Promise<T> {\n await ensureFreshIndex();\n return fn();\n}\n\n/**\n * Reset mini-skill freshness tracking. Used in tests.\n */\nexport function resetMiniSkillFreshness(): void {\n lastMiniSkillGeneration = -1;\n indexedSkillDocIds.clear();\n}\n","/**\n * Orama Store\n *\n * Full-text + vector + hybrid search engine backed by Orama.\n * Source: @orama/orama (10.1K stars, <2KB, pure JS, zero deps)\n *\n * Schema designed to store Observations with all searchable fields.\n * Vector search (embeddings) will be added in P1 phase.\n */\n\nimport { create, insert, search, remove, update, count, getByID, type AnyOrama } from '@orama/orama';\nimport type { MemorixDocument, SearchOptions, IndexEntry, KnowledgeLayer, ObservationReader } from '../types.js';\nimport { OBSERVATION_ICONS, type ObservationType } from '../types.js';\nimport { resolveKnowledgeLayer } from '../skills/mini-skills.js';\nimport { canReadObservation } from '../memory/visibility.js';\nimport { getEmbeddingProvider, type EmbeddingProvider } from '../embedding/provider.js';\nimport { calculateProjectAffinity, extractProjectKeywords, type AffinityContext, type MemoryContent } from './project-affinity.js';\nimport { detectQueryIntent, applyIntentBoost } from '../search/intent-detector.js';\nimport { maybeExpandSearchQuery } from '../search/query-expansion.js';\nimport { withTimeout } from '../timeout.js';\n\nlet db: AnyOrama | null = null;\nlet dbInitPromise: Promise<AnyOrama> | null = null;\nlet dbGeneration = 0;\nlet embeddingEnabled = false;\nlet embeddingDimensions: number | null = null;\nlet indexEmbeddingProvider: EmbeddingProvider | null = null;\nlet deferredCachedVectorHydration: Promise<void> | null = null;\nconst docByObservationKey = new Map<string, MemorixDocument>();\nconst NON_CJK_HYBRID_SIMILARITY = 0.45;\nconst lastSearchModeByProject = new Map<string, string>();\nconst SEARCH_MODE_DEFAULT_KEY = '__global__';\nexport function getLastSearchMode(projectId?: string): string {\n return lastSearchModeByProject.get(projectId ?? SEARCH_MODE_DEFAULT_KEY) ?? 'fulltext';\n}\n// Hard filter: titles starting with these are command execution logs, not knowledge.\n// They are excluded from results entirely (not just demoted) unless the query is command-like.\nconst COMMAND_LOG_TITLE = /^(Ran:|Command:|Executed:)\\s/i;\n// Soft demotion: titles containing shell-specific patterns get a score penalty.\nconst COMMAND_STYLE_TITLE = /(\\bfindstr\\b|\\bSelect-String\\b|\\bGet-Content\\b|\\bnpx\\s+vitest\\b|\\bnpx\\s+tsc\\b|\\b2>&1\\b)/i;\nconst COMMAND_LIKE_QUERY = /\\b(git|npm|npx|pnpm|yarn|node|bash|powershell|curl|memorix)\\b/i;\n// Stricter pattern: query IS a command (tool word at start, e.g. \"git status\", \"npm install\").\n// Does NOT match natural language like \"why is memorix search slow\".\nconst COMMAND_INTENT_QUERY = /^\\s*(git|npm|npx|pnpm|yarn|node|bash|powershell|curl|memorix)\\s/i;\n// Natural language markers — if ANY of these appear in the query, it is NOT a pure command.\n// Covers: question words, problem descriptors, reasoning words.\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;\n\n/**\n * Build a globally unique Orama document ID for an observation.\n * observationId is only unique within a project, so projectId must be included.\n */\nexport function makeOramaObservationId(projectId: string, observationId: number): string {\n return `obs-${encodeURIComponent(projectId)}-${observationId}`;\n}\n\nfunction makeEntryKey(projectId: string | undefined, observationId: number): string {\n return `${projectId ?? ''}::${observationId}`;\n}\n\nfunction rememberObservationDoc(doc: MemorixDocument): MemorixDocument {\n const publicDoc = { ...doc };\n delete publicDoc.embedding;\n if (doc.projectId && typeof doc.observationId === 'number') {\n docByObservationKey.set(makeEntryKey(doc.projectId, doc.observationId), publicDoc);\n }\n return publicDoc;\n}\n\nfunction isCommandLikeQuery(query: string): boolean {\n return COMMAND_LIKE_QUERY.test(query);\n}\n\n/**\n * Resolve the effective source label for intent-boost purposes.\n * Phase 1 introduced sourceDetail='git-ingest' as a more precise signal than\n * source='git'. Treat them as equivalent so intent-based source boosts\n * (e.g. what_changed → git: 2.0) apply to both representations.\n * Used in the source-aware retrieval path only — not stored or exported.\n */\nfunction effectiveSource(\n source: 'agent' | 'git' | 'manual',\n sourceDetail?: 'explicit' | 'hook' | 'git-ingest',\n): 'agent' | 'git' | 'manual' {\n return sourceDetail === 'git-ingest' ? 'git' : source;\n}\n\n/** True when the query IS a command (tool word leads), not just mentioning a tool. */\nfunction isCommandIntentQuery(query: string): boolean {\n if (!COMMAND_INTENT_QUERY.test(query)) return false;\n // If the query contains natural language markers (question words, problem\n // descriptors), it is a human question about a tool, not a CLI invocation.\n if (NATURAL_LANGUAGE_MARKERS.test(query)) return false;\n return true;\n}\n\n/** @internal Exported for testing only. */\nexport { classifyQueryTier as _classifyQueryTier };\n\n/**\n * Query tier classification for performance-aware search.\n * - 'fast': short/exact/command queries → fulltext only, no embedding, no rerank\n * - 'standard': normal queries → fulltext + embedding, no rerank\n * - 'heavy': CJK or long ambiguous queries → expansion + embedding + rerank\n */\ntype QueryTier = 'fast' | 'standard' | 'heavy';\n\nfunction classifyQueryTier(query: string): QueryTier {\n if (!query || query.trim().length === 0) return 'fast';\n // CJK-heavy queries must be checked FIRST — CJK text has no word-separating\n // spaces, so word-count heuristics would misclassify them as \"fast\".\n const cjkCount = (query.match(/[\\u4e00-\\u9fff\\u3040-\\u309f\\u30a0-\\u30ff\\uac00-\\ud7af]/g) || []).length;\n if (cjkCount / query.length > 0.3) return 'heavy';\n // Single-word or very short queries: fast path\n const words = query.trim().split(/\\s+/);\n if (words.length <= 1 && query.length <= 20) return 'fast';\n // Command-intent queries: fast path (\"git status\", \"npm install\")\n // NOT triggered by natural language mentioning a tool (\"why is memorix search slow\")\n if (isCommandIntentQuery(query)) return 'fast';\n // Long multi-word queries: heavy path\n if (words.length >= 5) return 'heavy';\n // Everything else: standard\n return 'standard';\n}\n\nfunction isCommandLogEntry(title: string): boolean {\n return COMMAND_LOG_TITLE.test(title);\n}\n\nfunction isCommandStyleEntry(title: string): boolean {\n return COMMAND_STYLE_TITLE.test(title);\n}\n\nfunction isVectorDimensionMismatchError(error: unknown): boolean {\n if (!(error instanceof Error)) return false;\n return (\n /declared as a \\d+-dimensional vector, but got a \\d+-dimensional vector/i.test(error.message) ||\n /dimension mismatch/i.test(error.message)\n );\n}\n\nfunction stripVectorSearchParams(params: Record<string, unknown>): Record<string, unknown> {\n const { mode, vector, similarity, hybridWeights, ...rest } = params;\n return rest;\n}\n\n/**\n * Initialize or return the Orama database instance.\n * Schema conditionally includes vector field based on embedding provider.\n * Graceful degradation: no provider → fulltext only, provider → hybrid.\n */\nasync function initializeDb(\n options: { allowNetworkProbe?: boolean },\n generation: number,\n): Promise<AnyOrama> {\n // Check if embedding provider is available.\n const provider = await getEmbeddingProvider({ allowNetworkProbe: options.allowNetworkProbe });\n const nextEmbeddingEnabled = provider !== null;\n const nextEmbeddingDimensions = provider?.dimensions ?? null;\n\n const baseSchema = {\n id: 'string' as const,\n observationId: 'number' as const,\n entityName: 'string' as const,\n type: 'string' as const,\n title: 'string' as const,\n narrative: 'string' as const,\n facts: 'string' as const,\n filesModified: 'string' as const,\n concepts: 'string' as const,\n tokens: 'number' as const,\n createdAt: 'string' as const,\n projectId: 'string' as const,\n accessCount: 'number' as const,\n lastAccessedAt: 'string' as const,\n status: 'string' as const,\n source: 'string' as const,\n sourceDetail: 'string' as const,\n valueCategory: 'string' as const,\n admissionState: 'string' as const,\n admissionReason: 'string' as const,\n visibility: 'string' as const,\n createdByAgentId: 'string' as const,\n sharedWithAgentIds: 'string' as const,\n documentType: 'string' as const,\n knowledgeLayer: 'string' as const,\n };\n\n // Dynamic vector dimensions based on provider (384 for local, 1024+ for API)\n const dims = nextEmbeddingDimensions ?? 384;\n const schema = nextEmbeddingEnabled\n ? { ...baseSchema, embedding: `vector[${dims}]` as const }\n : baseSchema;\n\n const nextDb = await create({ schema });\n\n // resetDb() may have started a new lifecycle while the provider was loading.\n // Discard this obsolete instance rather than letting it overwrite the new one.\n if (generation !== dbGeneration) {\n return getDb(options);\n }\n\n indexEmbeddingProvider = provider;\n embeddingEnabled = nextEmbeddingEnabled;\n embeddingDimensions = nextEmbeddingDimensions;\n db = nextDb;\n\n return nextDb;\n}\n\nexport async function getDb(options: { allowNetworkProbe?: boolean } = {}): Promise<AnyOrama> {\n if (db) return db;\n if (dbInitPromise) return dbInitPromise;\n\n const initPromise = initializeDb(options, dbGeneration);\n dbInitPromise = initPromise;\n\n try {\n return await initPromise;\n } finally {\n if (dbInitPromise === initPromise) {\n dbInitPromise = null;\n }\n }\n}\n\n/**\n * Reset the database instance (useful for testing).\n */\nexport async function resetDb(): Promise<void> {\n dbGeneration++;\n db = null;\n dbInitPromise = null;\n embeddingEnabled = false;\n embeddingDimensions = null;\n indexEmbeddingProvider = null;\n deferredCachedVectorHydration = null;\n lastSearchModeByProject.clear();\n docByObservationKey.clear();\n}\n\n/**\n * Check if embedding/vector search is active.\n */\nexport function isEmbeddingEnabled(): boolean {\n return embeddingEnabled;\n}\n\n/**\n * Current vector dimensions for the active Orama index.\n * Returns null when vector search is disabled for this process.\n */\nexport function getVectorDimensions(): number | null {\n return embeddingEnabled ? embeddingDimensions : null;\n}\n\n/**\n * Generate embedding for text content using the available provider.\n * Returns null if no provider is available.\n */\nexport async function generateEmbedding(text: string): Promise<number[] | null> {\n const provider = await getEmbeddingProvider();\n if (!provider) return null;\n return provider.embed(text);\n}\n\n/**\n * Batch-generate embeddings for multiple texts.\n * Much faster than individual calls — ONNX processes batches of 64 in parallel.\n * Returns null entries for texts that fail.\n */\nexport async function batchGenerateEmbeddings(texts: string[]): Promise<(number[] | null)[]> {\n const provider = await getEmbeddingProvider();\n if (!provider || texts.length === 0) return texts.map(() => null);\n try {\n const results = await provider.embedBatch(texts);\n return results;\n } catch (error) {\n console.error(\n `[memorix] Batch embedding failed, falling back to null vectors: ${error instanceof Error ? error.message : error}`,\n );\n return texts.map(() => null);\n }\n}\n\nasync function getCachedEmbeddings(texts: string[]): Promise<(number[] | null)[]> {\n if (!embeddingEnabled || texts.length === 0) return texts.map(() => null);\n const provider = indexEmbeddingProvider;\n if (!provider?.getCachedEmbeddings) return texts.map(() => null);\n try {\n return await provider.getCachedEmbeddings(texts);\n } catch {\n // Cached vectors are an optimization. Missing entries use background recovery.\n return texts.map(() => null);\n }\n}\n\n/**\n * Hydrate the Orama index from persisted observations.\n * Must be called before searching if the index was freshly created (TUI / CLI startup).\n * Skips observations already in the index (idempotent).\n */\nexport interface HydrateIndexOptions {\n /** Do not issue an API dimension probe while building the startup index. */\n allowNetworkProbe?: boolean;\n /** Attach cached vectors after lexical hydration instead of awaiting cache I/O. */\n deferCachedVectors?: boolean;\n}\n\ntype HydrationCandidate = { observation: any; id: string };\n\nfunction observationEmbeddingText(observation: any): string {\n return [\n observation.title ?? '',\n observation.narrative ?? '',\n ...(Array.isArray(observation.facts) ? observation.facts : []),\n ].join(' ');\n}\n\nfunction documentEmbeddingText(document: Pick<MemorixDocument, 'title' | 'narrative' | 'facts'>): string {\n return [document.title ?? '', document.narrative ?? '', document.facts ?? ''].join(' ');\n}\n\nfunction isCompatibleCachedVector(vector: number[] | null): vector is number[] {\n return Boolean(\n vector &&\n embeddingDimensions !== null &&\n vector.length === embeddingDimensions &&\n vector.every(Number.isFinite),\n );\n}\n\nasync function attachCachedVectors(\n database: AnyOrama,\n candidates: HydrationCandidate[],\n): Promise<void> {\n const cachedVectors = await getCachedEmbeddings(\n candidates.map(({ observation }) => observationEmbeddingText(observation)),\n );\n\n // A reset or project switch created a new index while the cache was loading.\n // Do not attach stale vectors to that new index.\n if (db !== database) return;\n\n for (let index = 0; index < candidates.length; index++) {\n const vector = cachedVectors[index];\n if (!isCompatibleCachedVector(vector)) continue;\n const existing = getByID(database, candidates[index].id) as MemorixDocument | undefined;\n if (!existing || documentEmbeddingText(existing) !== observationEmbeddingText(candidates[index].observation)) continue;\n try {\n await update(database, candidates[index].id, { ...existing, embedding: vector });\n } catch {\n // Vector cache hydration is best-effort. The normal backfill lane owns misses.\n }\n }\n}\n\nexport async function hydrateIndex(\n observations: any[],\n options: HydrateIndexOptions = {},\n): Promise<number> {\n const database = await getDb({ allowNetworkProbe: options.allowNetworkProbe });\n\n const candidates: HydrationCandidate[] = [];\n for (const observation of observations) {\n if (!observation || !observation.id || !observation.projectId) continue;\n const id = makeOramaObservationId(observation.projectId, observation.id);\n if (getByID(database, id)) continue;\n candidates.push({ observation, id });\n }\n\n const deferCachedVectors = options.deferCachedVectors === true && Boolean(indexEmbeddingProvider?.getCachedEmbeddings);\n const cachedVectors = deferCachedVectors\n ? candidates.map(() => null)\n : await getCachedEmbeddings(candidates.map(({ observation }) => observationEmbeddingText(observation)));\n\n let inserted = 0;\n for (let index = 0; index < candidates.length; index++) {\n const { observation: obs, id } = candidates[index];\n try {\n const vector = cachedVectors[index];\n const compatibleVector = isCompatibleCachedVector(vector) ? vector : null;\n const doc: MemorixDocument = {\n id,\n observationId: obs.id,\n entityName: obs.entityName || '',\n type: obs.type || 'discovery',\n title: obs.title || '',\n narrative: obs.narrative || '',\n facts: Array.isArray(obs.facts) ? obs.facts.join(' ') : '',\n filesModified: Array.isArray(obs.filesModified) ? obs.filesModified.join(' ') : '',\n concepts: Array.isArray(obs.concepts) ? obs.concepts.join(' ') : '',\n tokens: obs.tokens ?? 0,\n createdAt: obs.createdAt || '',\n projectId: obs.projectId,\n accessCount: obs.accessCount ?? 0,\n lastAccessedAt: obs.lastAccessedAt || '',\n status: obs.status ?? 'active',\n source: obs.source || 'agent',\n sourceDetail: obs.sourceDetail ?? '',\n valueCategory: obs.valueCategory ?? '',\n admissionState: obs.admissionState ?? '',\n admissionReason: obs.admissionReason ?? '',\n visibility: obs.visibility ?? 'project',\n createdByAgentId: obs.createdByAgentId ?? '',\n sharedWithAgentIds: JSON.stringify(obs.sharedWithAgentIds ?? []),\n documentType: 'observation',\n knowledgeLayer: resolveKnowledgeLayer('observation', obs.sourceDetail, obs.source),\n ...(compatibleVector ? { embedding: compatibleVector } : {}),\n };\n await insert(database, doc);\n rememberObservationDoc(doc);\n inserted++;\n } catch { /* skip malformed entries */ }\n }\n\n deferredCachedVectorHydration = deferCachedVectors\n ? attachCachedVectors(database, candidates).catch(() => {})\n : null;\n return inserted;\n}\n\n/**\n * Prepare the lexical index without probing a remote embedding API. Cached\n * vectors attach after the disk cache is ready, outside the startup path.\n */\nexport async function hydrateIndexForStartup(observations: any[]): Promise<number> {\n return hydrateIndex(observations, {\n allowNetworkProbe: false,\n deferCachedVectors: true,\n });\n}\n\n/**\n * Returns the background cache-only hydration started by the most recent\n * startup index pass. It never makes an embedding API call.\n */\nexport function getDeferredCachedVectorHydration(): Promise<void> | null {\n return deferredCachedVectorHydration;\n}\n\n/** Return whether the current in-memory index already has a usable vector. */\nexport function hasObservationVector(projectId: string, observationId: number): boolean {\n if (!db || !embeddingEnabled || embeddingDimensions === null) return false;\n const document = getByID(db, makeOramaObservationId(projectId, observationId)) as MemorixDocument | undefined;\n return Array.isArray(document?.embedding) &&\n document.embedding.length === embeddingDimensions &&\n document.embedding.every(Number.isFinite);\n}\n\n/**\n * Insert an observation document into the store.\n */\nexport async function insertObservation(doc: MemorixDocument): Promise<void> {\n const database = await getDb();\n await insert(database, doc);\n rememberObservationDoc(doc);\n}\n\n/**\n * Update retrieval metadata without rebuilding an embedding. Admission is\n * deliberately metadata-only: promotion must not create another embedding\n * request or delay a background qualification job.\n */\nexport async function updateObservationMetadata(\n projectId: string,\n observationId: number,\n patch: Partial<Pick<MemorixDocument, 'admissionState' | 'admissionReason' | 'visibility' | 'createdByAgentId' | 'sharedWithAgentIds'>>,\n): Promise<boolean> {\n const database = await getDb();\n const id = makeOramaObservationId(projectId, observationId);\n const existing = getByID(database, id) as MemorixDocument | undefined;\n if (!existing) return false;\n const next = { ...existing, ...patch };\n await update(database, id, next);\n rememberObservationDoc(next);\n return true;\n}\n\n/**\n * Remove an observation document by its Orama internal ID.\n */\nexport async function removeObservation(oramaId: string): Promise<void> {\n const database = await getDb();\n await remove(database, oramaId);\n for (const [key, doc] of docByObservationKey.entries()) {\n if (doc.id === oramaId) {\n docByObservationKey.delete(key);\n break;\n }\n }\n}\n\n/**\n * Search observations using Orama full-text search.\n * Returns L1 IndexEntry array (compact, ~50-100 tokens per result).\n *\n * Progressive Disclosure Layer 1 — adopted from claude-mem.\n */\nexport async function searchObservations(options: SearchOptions): Promise<IndexEntry[]> {\n const perf = !!process.env.MEMORIX_PERF;\n const t0 = perf ? performance.now() : 0;\n const mark = (label: string) => { if (perf) { const now = performance.now(); process.stderr.write(` [search-perf] ${label}: ${(now - t0).toFixed(0)}ms\\n`); } };\n const modeKey = options.projectId ?? SEARCH_MODE_DEFAULT_KEY;\n const quality = options.quality ?? 'balanced';\n const database = await getDb();\n lastSearchModeByProject.set(\n modeKey,\n quality === 'fast' ? 'fulltext (fast profile)' : embeddingEnabled ? 'hybrid' : 'fulltext',\n );\n\n // Resolve project aliases — safety net for observations not yet migrated to canonical ID.\n // After migration, this is typically a single-element array matching options.projectId.\n let projectIds: string[] | null = null;\n if (options.projectId) {\n try {\n const { resolveAliases } = await import('../project/aliases.js');\n projectIds = await resolveAliases(options.projectId);\n } catch {\n projectIds = [options.projectId];\n }\n }\n\n const filters: Record<string, unknown> = {};\n if (projectIds && projectIds.length === 1) {\n filters['projectId'] = projectIds[0];\n }\n // If multiple aliases exist, we skip the Orama projectId filter and post-filter instead\n if (options.type) {\n filters['type'] = options.type;\n }\n if (options.source) {\n filters['source'] = options.source;\n }\n\n // Determine search mode: hybrid (with vector) or fulltext (default)\n const hasQuery = options.query && options.query.trim().length > 0;\n const originalQuery = options.query;\n // The fast profile is a bounded local probe, not a lower-quality spelling\n // corrector. Skip query classification and the expensive recall enrichments\n // it would otherwise inherit from the balanced path.\n const tier = quality === 'fast' ? 'fast' as QueryTier : hasQuery ? classifyQueryTier(originalQuery!) : 'fast' as QueryTier;\n mark(`tier=${tier}`);\n\n // LLM quality work is explicit. It never runs on the default search path.\n if (quality === 'thorough' && hasQuery) {\n const { initLLM, isLLMEnabled } = await import('../llm/provider.js');\n if (!isLLMEnabled()) initLLM();\n }\n\n // Query expansion: only for thorough heavy-tier (CJK) searches.\n const expandedEmbeddingQuery = quality === 'thorough' && tier === 'heavy'\n ? await maybeExpandSearchQuery(options.query!)\n : options.query;\n mark('queryExpansion');\n\n // ── Intent-Aware Recall ──────────────────────────────────────\n // Detect query intent (why/when/how/what/problem) and adjust\n // field weights and type boosting accordingly.\n const intentResult = quality === 'fast' || !hasQuery ? null : detectQueryIntent(originalQuery!);\n\n // Orama's vector/hybrid search can leak cross-project hits even when `where`\n // is present, so always keep enough headroom for a deterministic post-filter.\n const requestLimit = projectIds\n ? (options.limit ?? 20) * 3\n : (options.limit ?? 20);\n\n // Default field boosts — overridden by intent-specific boosts when detected\n const defaultBoost: Record<string, number> = {\n title: 3,\n entityName: 2,\n concepts: 1.5,\n narrative: 1,\n facts: 1,\n filesModified: 0.5,\n };\n const fieldBoost = (intentResult?.confidence ?? 0) > 0.3 && intentResult?.fieldBoosts\n ? intentResult.fieldBoosts\n : defaultBoost;\n\n let searchParams: Record<string, unknown> = {\n term: originalQuery,\n limit: requestLimit,\n // Fast search never uses vectors, so returning them only adds work and\n // payload pressure to an explicitly latency-sensitive path.\n includeVectors: quality !== 'fast',\n ...(Object.keys(filters).length > 0 ? { where: filters } : {}),\n // Search specific fields (not tokens, accessCount, etc.)\n properties: ['title', 'entityName', 'narrative', 'facts', 'concepts', 'filesModified'],\n // Field boosting: intent-aware or default\n boost: fieldBoost,\n // Fuzzy tolerance: allow 1-char typos for short queries, 2 for longer\n // Fuzzy matching is useful for ordinary recall, but grows sharply with\n // corpus size. The fast profile deliberately uses exact lexical matching.\n ...(hasQuery && quality !== 'fast' ? { tolerance: originalQuery!.length > 6 ? 2 : 1 } : {}),\n };\n\n // If embedding provider is available and query tier warrants it, use hybrid search\n // Fast-tier queries skip embedding entirely (fulltext is sufficient)\n let queryVector: number[] | null = null;\n if (quality !== 'fast' && embeddingEnabled && hasQuery && tier !== 'fast') {\n try {\n const provider = await getEmbeddingProvider();\n if (provider) {\n const activeVectorDimensions = getVectorDimensions();\n if (activeVectorDimensions !== null && provider.dimensions !== activeVectorDimensions) {\n lastSearchModeByProject.set(\n modeKey,\n `fulltext (embedding dimension mismatch: provider ${provider.dimensions}d vs index ${activeVectorDimensions}d)`,\n );\n console.error(\n `[memorix] Embedding provider dimension mismatch (${provider.dimensions}d provider vs ${activeVectorDimensions}d index); using fulltext search`,\n );\n } else {\n // Embedding timeout: 15 seconds\n const EMBEDDING_TIMEOUT_MS = 15000;\n queryVector = await withTimeout(\n provider.embed(expandedEmbeddingQuery!),\n EMBEDDING_TIMEOUT_MS,\n 'Embedding',\n );\n mark('embedding');\n // Detect CJK-heavy queries: BM25 can't tokenize Chinese/Japanese/Korean well\n const cjkRatio = (originalQuery!.match(/[\\u4e00-\\u9fff\\u3040-\\u309f\\u30a0-\\u30ff\\uac00-\\ud7af]/g) || []).length / originalQuery!.length;\n const isCJKHeavy = cjkRatio > 0.3;\n lastSearchModeByProject.set(modeKey, 'hybrid');\n searchParams = {\n ...searchParams,\n mode: 'hybrid',\n vector: {\n value: queryVector,\n property: 'embedding',\n },\n // English paraphrase queries were getting clipped just below 0.5\n // even when vector-only search could already find the right memory.\n similarity: isCJKHeavy ? 0.3 : NON_CJK_HYBRID_SIMILARITY,\n hybridWeights: isCJKHeavy\n ? { text: 0.2, vector: 0.8 } // CJK: trust vector over BM25\n : { text: 0.6, vector: 0.4 },\n };\n }\n }\n } catch (error) {\n // Fallback to fulltext if embedding fails or times out\n lastSearchModeByProject.set(modeKey, 'fulltext (embedding unavailable)');\n console.error('[memorix] Embedding failed or timed out, falling back to fulltext search');\n }\n }\n\n mark('preSearch');\n let results;\n try {\n results = await search(database, searchParams);\n } catch (error) {\n if (queryVector && isVectorDimensionMismatchError(error)) {\n lastSearchModeByProject.set(modeKey, 'fulltext (embedding dimension mismatch)');\n console.error('[memorix] Vector search dimension mismatch detected, retrying without embeddings');\n results = await search(database, stripVectorSearchParams(searchParams));\n } else {\n throw error;\n }\n }\n mark('oramaSearch');\n\n // Fallback: if hybrid returned nothing but we have a vector, retry with vector-only\n if (results.count === 0 && queryVector && embeddingEnabled) {\n try {\n const vectorOnlyParams: Record<string, unknown> = {\n term: '',\n limit: requestLimit,\n includeVectors: true,\n ...(Object.keys(filters).length > 0 ? { where: filters } : {}),\n mode: 'vector',\n vector: {\n value: queryVector,\n property: 'embedding',\n },\n similarity: 0.25,\n };\n lastSearchModeByProject.set(modeKey, 'vector-only (hybrid empty fallback)');\n results = await search(database, vectorOnlyParams);\n } catch {\n // Keep original empty results\n }\n }\n\n // Status filter: default to 'active' only\n const statusFilter = options.status ?? 'active';\n\n // Build intermediate results with rawTime for temporal filtering\n let intermediate = results.hits\n // Always post-filter by projectIds. Vector/hybrid search can leak hits even when\n // the `where` clause is present, so this keeps project isolation deterministic.\n .filter((hit) => {\n if (!projectIds) return true;\n const doc = hit.document as unknown as MemorixDocument;\n return projectIds.includes(doc.projectId);\n })\n // Visibility is enforced before scoring/ranking so private records cannot\n // affect result order, fallback behavior, or downstream detail reads.\n .filter((hit) => canReadObservation(hit.document as unknown as MemorixDocument, options.reader))\n // Post-filter by status (active/resolved/archived)\n .filter((hit) => {\n if (statusFilter === 'all') return true;\n const doc = hit.document as unknown as MemorixDocument;\n return (doc.status || 'active') === statusFilter;\n })\n // Post-filter: exclude probe observations from default search.\n // Probe is operational memory (heartbeats, connectivity checks) — not durable knowledge.\n // Only included when the caller explicitly requests type: 'probe'.\n .filter((hit) => {\n if (options.type === 'probe') return true;\n const doc = hit.document as unknown as MemorixDocument;\n return doc.type !== 'probe';\n })\n .map((hit) => {\n const doc = hit.document as unknown as MemorixDocument;\n const obsType = doc.type as ObservationType;\n // Time decay: newer memories get higher boost\n const ageMs = Date.now() - new Date(doc.createdAt).getTime();\n const DAY = 86_400_000;\n let recencyBoost: number;\n if (ageMs < 1 * DAY) recencyBoost = 1.0;\n else if (ageMs < 7 * DAY) recencyBoost = 0.85;\n else if (ageMs < 30 * DAY) recencyBoost = 0.6;\n else recencyBoost = 0.35;\n\n return {\n id: doc.observationId,\n time: formatTime(doc.createdAt),\n rawTime: doc.createdAt,\n type: obsType,\n icon: OBSERVATION_ICONS[obsType] ?? '[UNKNOWN]',\n title: doc.title,\n tokens: doc.tokens,\n score: (hit.score ?? 1) * recencyBoost,\n projectId: doc.projectId,\n source: (doc.source || 'agent') as 'agent' | 'git' | 'manual',\n sourceDetail: (doc.sourceDetail || undefined) as 'explicit' | 'hook' | 'git-ingest' | undefined,\n valueCategory: (doc.valueCategory || undefined) as 'core' | 'contextual' | 'ephemeral' | undefined,\n admissionState: (doc.admissionState || undefined) as IndexEntry['admissionState'],\n visibility: (doc.visibility || undefined) as IndexEntry['visibility'],\n entityName: doc.entityName || undefined,\n documentType: (doc.documentType || 'observation') as 'observation' | 'mini-skill',\n knowledgeLayer: (doc.knowledgeLayer || 'project-truth') as KnowledgeLayer,\n _isCommandLog: isCommandLogEntry(doc.title),\n };\n });\n\n // ── Knowledge-Layer Boost (Phase 3a, step 3) ─────────────────\n // Explicit layer-aware ranking: promoted knowledge gets a mild boost\n // for general queries, evidence gets a boost for evidence-seeking queries.\n // This is the dedicated layer signal — NOT borrowed from valueCategory.\n {\n const isEvidenceSeeking = intentResult?.intent === 'what_changed' ||\n (hasQuery && /\\b(evidence|verify|proof|git|commit)\\b/i.test(originalQuery!));\n const layerBoosts: Record<string, number> = isEvidenceSeeking\n ? { promoted: 1.10, 'project-truth': 1.00, evidence: 1.15 }\n : { promoted: 1.20, 'project-truth': 1.00, evidence: 0.90 };\n intermediate = intermediate.map(entry => ({\n ...entry,\n score: entry.score * (layerBoosts[(entry as any).knowledgeLayer] ?? 1.0),\n }));\n }\n\n // ── Intent-Aware Type Boosting ───────────────────────────────\n // Boost scores for observation types that match the query intent\n if (intentResult && intentResult.confidence > 0.3) {\n intermediate = intermediate.map(entry => ({\n ...entry,\n score: applyIntentBoost(entry.score, entry.type, intentResult),\n }));\n }\n\n // ── Source-Aware Retrieval ─────────────────────────────────────\n // Boost scores based on memory source matching query intent.\n // e.g., \"what changed\" queries boost git-derived memories,\n // \"why\" queries boost agent-authored reasoning memories.\n if (intentResult && intentResult.confidence > 0.3 && intentResult.sourceBoosts) {\n const srcBoosts = intentResult.sourceBoosts;\n intermediate = intermediate.map(entry => {\n const boost = srcBoosts[effectiveSource(entry.source, entry.sourceDetail)] ?? 1.0;\n const effectiveBoost = 1 + (boost - 1) * intentResult.confidence;\n return { ...entry, score: entry.score * effectiveBoost };\n });\n }\n\n // ── Command-log noise suppression (two-pass) ────────────────\n // 73% of observations are Ran:/Command:/Executed: hook logs. When the query\n // is NOT command-like, we first try excluding them entirely. If that would\n // leave 0 real results (the query only matched command logs), we fall back to\n // keeping them with a very aggressive 0.05x demotion so SOMETHING is returned\n // but noise never dominates when real results exist.\n if (hasQuery && !isCommandLikeQuery(originalQuery!)) {\n const nonCommandEntries = intermediate.filter(e => !(e as any)._isCommandLog);\n if (nonCommandEntries.length > 0) {\n // Enough real results — drop command logs entirely\n intermediate = nonCommandEntries;\n } else {\n // Only command logs matched — keep them but demote heavily\n intermediate = intermediate.map(entry => ({\n ...entry,\n score: (entry as any)._isCommandLog ? entry.score * 0.05 : entry.score,\n }));\n }\n // Also soft-demote shell-specific patterns in remaining results\n intermediate = intermediate.map(entry => ({\n ...entry,\n score: isCommandStyleEntry(entry.title) ? entry.score * 0.3 : entry.score,\n }));\n }\n\n // Automatic capture is useful as an audit trail, but unqualified evidence\n // should not crowd out durable project knowledge in ordinary retrieval.\n // Keep it available as a fallback when it is all the project has.\n if (hasQuery) {\n const qualifiedEntries = intermediate.filter(\n (entry) => entry.admissionState !== 'candidate' && entry.admissionState !== 'ephemeral',\n );\n if (qualifiedEntries.length > 0) intermediate = qualifiedEntries;\n }\n\n // Re-sort: chronological for WHEN queries, relevance for others\n if (intentResult?.preferChronological) {\n intermediate.sort((a, b) => new Date(b.rawTime).getTime() - new Date(a.rawTime).getTime());\n } else {\n intermediate.sort((a, b) => b.score - a.score);\n }\n\n // ─── Project Affinity Scoring (mcp-memory-service style) ───\n // Penalize memories that don't reference the current project to prevent\n // cross-project pollution (e.g., discussing Memorix in a test project workspace)\n if (options.projectId && intermediate.length > 0) {\n const projectName = options.projectId.split('/').pop() ?? options.projectId;\n const affinityContext: AffinityContext = {\n projectName,\n projectId: options.projectId,\n projectKeywords: extractProjectKeywords(projectName, options.projectId),\n };\n\n // Build a map of memory content for affinity calculation\n const memoryContentMap = new Map<number, MemoryContent>();\n for (const hit of results.hits) {\n const doc = hit.document as unknown as MemorixDocument;\n memoryContentMap.set(doc.observationId, {\n title: doc.title,\n narrative: doc.narrative,\n facts: doc.facts?.split?.('\\n') ?? (Array.isArray(doc.facts) ? doc.facts : []),\n concepts: doc.concepts?.split?.('\\n') ?? (Array.isArray(doc.concepts) ? doc.concepts : []),\n entityName: doc.entityName,\n filesModified: doc.filesModified?.split?.('\\n') ?? (Array.isArray(doc.filesModified) ? doc.filesModified : []),\n });\n }\n\n // Apply affinity scoring to each result\n intermediate = intermediate.map(entry => {\n const memory = memoryContentMap.get(entry.id);\n if (!memory) return entry;\n\n const { score: affinityScore } = calculateProjectAffinity(memory, affinityContext);\n return {\n ...entry,\n score: entry.score * affinityScore, // Apply affinity as multiplier\n };\n });\n\n // Re-sort after affinity adjustment\n intermediate.sort((a, b) => b.score - a.score);\n }\n\n // Temporal filtering: since/until date range\n if (options.since) {\n const sinceDate = new Date(options.since).getTime();\n intermediate = intermediate.filter(e => new Date(e.rawTime).getTime() >= sinceDate);\n }\n if (options.until) {\n const untilDate = new Date(options.until).getTime();\n intermediate = intermediate.filter(e => new Date(e.rawTime).getTime() <= untilDate);\n }\n\n // Apply original limit after post-filtering (we intentionally over-requested when project filtering is active)\n if (projectIds) {\n intermediate = intermediate.slice(0, options.limit ?? 20);\n }\n\n // ── Provenance Tiebreaker (standard tier only) ──────────────────\n // When Orama scores converge — a common outcome in standard-tier queries\n // where both fulltext and embedding are used — this pass gives a tiny\n // preference to repository-backed and core memories within the top-K\n // results whose scores fall within a 20% window of the highest score.\n // Amplitudes are intentionally small: the tiebreaker must never reverse\n // a meaningful score gap, only resolve genuine ambiguity.\n // git-ingest / source=git → ×1.06 (repository evidence)\n // valueCategory=core → ×1.03 (explicitly classified durable memory)\n // Constraints:\n // - Standard tier only (fast has no ambiguity; heavy has LLM rerank)\n // - Top-8 results only (doesn't affect long tail)\n // - 20% score window from top score (score ≥ topScore × 0.80)\n if (tier === 'standard' && intermediate.length > 1) {\n const TIEBREAK_TOP_K = 8;\n const TIEBREAK_WINDOW = 0.20;\n const topScore = intermediate[0]?.score ?? 0;\n const threshold = topScore * (1 - TIEBREAK_WINDOW);\n let changed = false;\n for (let i = 0; i < Math.min(TIEBREAK_TOP_K, intermediate.length); i++) {\n const entry = intermediate[i];\n if (entry.score < threshold) break; // outside tiebreak window, stop\n const isGitEvidence = effectiveSource(entry.source, entry.sourceDetail) === 'git';\n const isCore = entry.valueCategory === 'core';\n if (isGitEvidence) {\n intermediate[i] = { ...entry, score: entry.score * 1.06 };\n changed = true;\n } else if (isCore) {\n intermediate[i] = { ...entry, score: entry.score * 1.03 };\n changed = true;\n }\n }\n if (changed) intermediate.sort((a, b) => b.score - a.score);\n }\n\n // ── Entity-affinity hint (standard + heavy tier only) ──────────────\n // When query tokens (4+ chars) match some entity names in results but not\n // others, mildly boost the matching entities (×1.08). This helps queries\n // like \"blog VPS deployment\" surface blog-vps observations over api-relay\n // observations stored in the same project bucket.\n // Gates:\n // - standard or heavy tier only (fast tier is single-word, too noisy)\n // - only fires when some but not all entity names match the query\n // - top-8 and within the 20% window of the top score\n // - cannot reverse a meaningful score gap (amplitude ×1.08)\n if ((tier === 'standard' || tier === 'heavy') && intermediate.length > 1 && hasQuery) {\n const affTokens = originalQuery!\n .toLowerCase()\n .split(/\\s+/)\n .map(t => t.replace(/[_-]/g, ''))\n .filter(t => t.length >= 4);\n\n if (affTokens.length > 0) {\n const entityNames = [...new Set(intermediate.map(e => e.entityName).filter((n): n is string => !!n))];\n const matchedEntities = new Set(\n entityNames.filter(name => {\n const norm = name.toLowerCase().replace(/[_-]/g, '');\n return affTokens.some(t => norm.includes(t));\n }),\n );\n\n if (matchedEntities.size > 0 && matchedEntities.size < entityNames.length) {\n const AFF_TOP_K = 8;\n const AFF_WINDOW = 0.20;\n const AFF_BOOST = 1.08;\n const topScore = intermediate[0]?.score ?? 0;\n const threshold = topScore * (1 - AFF_WINDOW);\n let affChanged = false;\n for (let i = 0; i < Math.min(AFF_TOP_K, intermediate.length); i++) {\n const entry = intermediate[i];\n if (entry.score < threshold) break;\n if (matchedEntities.has(entry.entityName ?? '')) {\n intermediate[i] = { ...entry, score: entry.score * AFF_BOOST };\n affChanged = true;\n }\n }\n if (affChanged) intermediate.sort((a, b) => b.score - a.score);\n }\n }\n }\n\n // ── LLM Reranking (heavy-tier only) ────────────────────────────\n // Only triggered for heavy-tier queries with ambiguous top results.\n // Non-thorough profiles, fast, and standard tiers skip entirely.\n // Ambiguity check: top-2 scores within 30% → results are uncertain.\n const shouldRerank = quality === 'thorough'\n && tier === 'heavy'\n && hasQuery\n && intermediate.length > 2\n && (() => {\n const top = intermediate[0]?.score ?? 0;\n const second = intermediate[1]?.score ?? 0;\n return top > 0 && second / top > 0.7; // top-2 within 30% = ambiguous\n })();\n\n if (shouldRerank) {\n try {\n const { rerankResults } = await import('../llm/quality.js');\n const narrativeMap = new Map<string, string>();\n for (const hit of results.hits) {\n const doc = hit.document as unknown as MemorixDocument;\n narrativeMap.set(makeEntryKey(doc.projectId, doc.observationId), doc.narrative);\n }\n // Rerank only top-5 (was 10) to save LLM tokens and latency\n const RERANK_TOP_K = 5;\n const toRerank = intermediate.slice(0, RERANK_TOP_K);\n const candidates = toRerank.map((e, index) => ({\n id: `r${index + 1}`,\n title: e.title,\n type: e.type,\n score: e.score,\n narrative: narrativeMap.get(makeEntryKey(e.projectId, e.id)),\n }));\n \n // LLM rerank timeout: configurable via MEMORIX_RERANK_TIMEOUT_MS, default 5s\n const _parsedRerank = parseInt(process.env.MEMORIX_RERANK_TIMEOUT_MS || '', 10);\n const RERANK_TIMEOUT_MS = Number.isFinite(_parsedRerank) && _parsedRerank > 0 ? _parsedRerank : 5000;\n const { reranked, usedLLM } = await withTimeout(\n rerankResults(originalQuery!, candidates),\n RERANK_TIMEOUT_MS,\n 'LLM rerank',\n );\n mark(`rerank(usedLLM=${usedLLM})`);\n \n if (usedLLM) {\n lastSearchModeByProject.set(modeKey, (lastSearchModeByProject.get(modeKey) ?? 'fulltext') + ' + LLM rerank');\n const candidateMap = new Map(candidates.map((candidate, index) => [candidate.id, toRerank[index]]));\n const rerankedTop = reranked\n .map(r => candidateMap.get(r.id))\n .filter((e): e is NonNullable<typeof e> => e != null);\n if (rerankedTop.length > 0) {\n intermediate = [...rerankedTop, ...intermediate.slice(RERANK_TOP_K)];\n }\n }\n } catch (error) {\n // Reranking is best-effort: fall back to original order on timeout or error\n console.error('[memorix] LLM rerank failed or timed out, using original order');\n }\n } else {\n mark(`rerank(skipped,tier=${tier})`);\n }\n\n // Build IndexEntry with optional match explanation\n let entries: IndexEntry[] = intermediate.map(({ rawTime: _, _isCommandLog: _c, ...rest }: any) => rest);\n\n for (const hit of results.hits) {\n const doc = hit.document as unknown as MemorixDocument;\n if (canReadObservation(doc, options.reader)) rememberObservationDoc(doc);\n }\n\n // Explainable recall: annotate entries with match reasons (O(1) lookup via Map)\n if (hasQuery && originalQuery) {\n const queryLower = originalQuery.toLowerCase();\n const queryTokens = queryLower.split(/\\s+/).filter(t => t.length > 1);\n const entryMap = new Map(entries.map(e => [makeEntryKey(e.projectId, e.id), e]));\n for (const hit of results.hits) {\n const doc = hit.document as unknown as MemorixDocument;\n const entry = entryMap.get(makeEntryKey(doc.projectId, doc.observationId));\n if (!entry) continue;\n\n const reasons: string[] = [];\n const fields: [string, string][] = [\n ['title', doc.title], ['entity', doc.entityName], ['concept', doc.concepts],\n ['narrative', doc.narrative], ['fact', doc.facts], ['file', doc.filesModified],\n ];\n for (const [name, value] of fields) {\n const valueLower = value.toLowerCase();\n if (queryTokens.some(t => valueLower.includes(t))) reasons.push(name);\n }\n if (reasons.length === 0) reasons.push('fuzzy');\n\n // Prepend a single evidence-type tag (max 1) ahead of field-match labels.\n // Priority: git evidence > synthesized > core core\n // This surfaces WHY this result is notable beyond the query match.\n const isGitEvidence = doc.sourceDetail === 'git-ingest' || doc.source === 'git';\n const isSynthesized = doc.sourceDetail === 'explicit' &&\n // Note: relatedCommits not in MemorixDocument; flag is best-effort from sourceDetail alone.\n // Full synthesized detection is handled in the detail/timeline path where we have the full obs.\n false; // reserved — set explicitly if MemorixDocument gains relatedCommits in future\n const isCore = doc.valueCategory === 'core';\n\n if (isGitEvidence) {\n entry.matchedFields = ['git evidence', ...reasons];\n } else if (isSynthesized) {\n entry.matchedFields = ['synthesized', ...reasons];\n } else if (isCore) {\n entry.matchedFields = ['core core', ...reasons];\n } else {\n entry.matchedFields = reasons;\n }\n }\n }\n\n // Apply token budget if specified (inspired by MemCP)\n if (options.maxTokens && options.maxTokens > 0) {\n entries = applyTokenBudget(entries, options.maxTokens);\n }\n\n // Record access for returned results (fire-and-forget, non-blocking).\n if (options.trackAccess !== false) {\n const returnedKeys = new Set(entries.map((entry) => makeEntryKey(entry.projectId, entry.id)));\n const hitDocs = results.hits\n .map((hit) => ({ id: hit.id, doc: hit.document as unknown as MemorixDocument }))\n .filter(({ doc }) => returnedKeys.has(makeEntryKey(doc.projectId, doc.observationId)));\n recordAccessBatch(hitDocs).catch(() => {});\n }\n\n return entries;\n}\n\n/**\n * Get full observation documents by their observation IDs.\n *\n * Progressive Disclosure Layer 3 — adopted from claude-mem.\n */\nexport async function getObservationsByIds(\n ids: number[],\n projectId?: string,\n): Promise<MemorixDocument[]> {\n const database = await getDb();\n\n // Search for each ID individually and collect results\n const results: MemorixDocument[] = [];\n\n for (const id of ids) {\n if (projectId) {\n const cached = docByObservationKey.get(makeEntryKey(projectId, id));\n if (cached) {\n results.push(cached);\n continue;\n }\n }\n\n const searchResult = await search(database, {\n term: '',\n includeVectors: true,\n where: {\n observationId: { eq: id },\n ...(projectId ? { projectId } : {}),\n },\n limit: 1,\n });\n\n if (searchResult.hits.length > 0) {\n results.push(rememberObservationDoc(searchResult.hits[0].document as unknown as MemorixDocument));\n }\n }\n\n return results;\n}\n\n/**\n * Get observations around an anchor for timeline context.\n *\n * Progressive Disclosure Layer 2 — adopted from claude-mem.\n */\nexport async function getTimeline(\n anchorId: number,\n projectId?: string,\n depthBefore = 3,\n depthAfter = 3,\n reader?: ObservationReader,\n): Promise<{ before: IndexEntry[]; anchor: IndexEntry | null; after: IndexEntry[] }> {\n // Use in-memory observations for reliable lookup\n // (Orama search with empty term is unreliable — same fix as compactDetail)\n const { withFreshIndex } = await import('../memory/freshness.js');\n const { getAllObservations } = await import('../memory/observations.js');\n const rawObs = await withFreshIndex(() => getAllObservations());\n\n // Filter by project if specified — prevents cross-project context leaking\n const allObs = (projectId\n ? rawObs.filter((o) => o.projectId === projectId)\n : rawObs).filter((observation) => canReadObservation(observation, reader));\n\n // Sort by creation time\n const sorted = allObs.sort((a, b) => a.createdAt.localeCompare(b.createdAt));\n\n const anchorIndex = sorted.findIndex((o) => o.id === anchorId);\n if (anchorIndex === -1) {\n return { before: [], anchor: null, after: [] };\n }\n\n const toIndexEntry = (obs: {\n id: number; type: string; title: string; tokens: number; createdAt: string;\n source?: string; sourceDetail?: string; valueCategory?: string; admissionState?: string; visibility?: string;\n }): IndexEntry => {\n const obsType = obs.type as ObservationType;\n return {\n id: obs.id,\n time: formatTime(obs.createdAt),\n type: obsType,\n icon: OBSERVATION_ICONS[obsType] ?? '[UNKNOWN]',\n title: obs.title,\n tokens: obs.tokens,\n source: (obs.source as IndexEntry['source']) || undefined,\n sourceDetail: (obs.sourceDetail as IndexEntry['sourceDetail']) || undefined,\n valueCategory: (obs.valueCategory as IndexEntry['valueCategory']) || undefined,\n admissionState: (obs.admissionState as IndexEntry['admissionState']) || undefined,\n visibility: (obs.visibility as IndexEntry['visibility']) || undefined,\n };\n };\n\n const before = sorted\n .slice(Math.max(0, anchorIndex - depthBefore), anchorIndex)\n .map(toIndexEntry);\n\n const after = sorted\n .slice(anchorIndex + 1, anchorIndex + 1 + depthAfter)\n .map(toIndexEntry);\n\n return {\n before,\n anchor: toIndexEntry(sorted[anchorIndex]),\n after,\n };\n}\n\n/**\n * Record access for observations returned in search results.\n * Increments accessCount and updates lastAccessedAt.\n * Inspired by mcp-memory-service's record_access() pattern.\n */\nasync function recordAccessBatch(hitDocs: { id: string; doc: MemorixDocument }[]): Promise<void> {\n const database = await getDb();\n const now = new Date().toISOString();\n\n for (const { id, doc } of hitDocs) {\n try {\n // Use update() directly — no need to re-search since we already have the doc\n await update(database, id, {\n ...doc,\n accessCount: (doc.accessCount ?? 0) + 1,\n lastAccessedAt: now,\n });\n } catch {\n // Best-effort — don't break search if access tracking fails\n }\n }\n}\n\n/**\n * Trim search results to fit within a token budget.\n * Inspired by MemCP's _apply_token_budget() pattern.\n */\nfunction applyTokenBudget(entries: IndexEntry[], maxTokens: number): IndexEntry[] {\n const budgeted: IndexEntry[] = [];\n let tokensUsed = 0;\n\n for (const entry of entries) {\n if (tokensUsed + entry.tokens > maxTokens && budgeted.length > 0) {\n break;\n }\n budgeted.push(entry);\n tokensUsed += entry.tokens;\n }\n\n return budgeted;\n}\n\n/**\n * Get total observation count, optionally filtered by project.\n */\nexport async function getObservationCount(projectId?: string): Promise<number> {\n const database = await getDb();\n if (!projectId) {\n return await count(database);\n }\n const results = await search(database, {\n term: '',\n where: { projectId },\n limit: 0,\n });\n return results.count;\n}\n\n/**\n * Format ISO date string to compact time display.\n */\nfunction formatTime(isoDate: string): string {\n try {\n const date = new Date(isoDate);\n return date.toLocaleTimeString('en-US', {\n hour: 'numeric',\n minute: '2-digit',\n hour12: true,\n });\n } catch {\n return isoDate;\n }\n}\n","/**\n * Entity Extractor\n *\n * Regex-based entity extraction from observation content.\n * Inspired by MemCP's RegexEntityExtractor (MAGMA paper).\n *\n * Extracts: file paths, module paths, URLs, @mentions, CamelCase identifiers.\n * Also detects causal patterns for automatic edge typing.\n */\n\nconst ENTITY_PATTERNS: Array<{ kind: string; pattern: RegExp }> = [\n // File paths (e.g. src/auth/jwt.ts, ./config.json)\n { kind: 'file', pattern: /(?:^|[\\s\"'(])([.\\w/-]+\\.\\w{1,10})(?:[\\s\"'),]|$)/g },\n // Module/package paths (e.g. @orama/orama, memcp.core.graph)\n { kind: 'module', pattern: /(?:^|[\\s\"'(,])(@[\\w-]+\\/[\\w.-]+)|\\b([a-zA-Z_]\\w*(?:\\.[a-zA-Z_]\\w*){2,})\\b/g },\n // URLs\n { kind: 'url', pattern: /https?:\\/\\/[^\\s\"'<>)]+/g },\n // @mentions\n { kind: 'mention', pattern: /@([a-zA-Z_]\\w+)/g },\n // CamelCase identifiers (likely class/type names)\n { kind: 'identifier', pattern: /\\b([A-Z][a-z]+(?:[A-Z][a-z]+)+)\\b/g },\n // Chinese identifiers: quoted Chinese terms or backtick-wrapped Chinese (e.g. 「认证模块」, `数据库连接`)\n { kind: 'identifier', pattern: /[「『【]([一-鿿㐀-䶿]{2,}(?:[一-鿿㐀-䶿a-zA-Z0-9_-]*[一-鿿㐀-䶿])?)[」』】]/g },\n { kind: 'identifier', pattern: /`([一-鿿㐀-䶿]{2,}[一-鿿㐀-䶿a-zA-Z0-9_-]*)`/g },\n];\n\n/**\n * Patterns that indicate causal relationships.\n * Used to auto-detect causal edge types in Knowledge Graph.\n */\nconst CAUSAL_PATTERN = /\\b(?:because|therefore|due to|caused by|as a result|decided to|chosen because|so that|in order to|leads to|results in|fixed by|resolved by)\\b|(?:因为|所以|由于|导致|造成|结果|因此|为了|解决|修复|修正|决定|选择|采用)/i;\n\nexport interface ExtractedEntities {\n files: string[];\n modules: string[];\n urls: string[];\n mentions: string[];\n identifiers: string[];\n hasCausalLanguage: boolean;\n}\n\n/**\n * Extract entities from text content.\n * Returns deduplicated lists of each entity type.\n */\nexport function extractEntities(content: string): ExtractedEntities {\n const result: ExtractedEntities = {\n files: [],\n modules: [],\n urls: [],\n mentions: [],\n identifiers: [],\n hasCausalLanguage: false,\n };\n\n const seen = new Set<string>();\n\n for (const { kind, pattern } of ENTITY_PATTERNS) {\n // Reset lastIndex for global regexes\n pattern.lastIndex = 0;\n let match: RegExpExecArray | null;\n while ((match = pattern.exec(content)) !== null) {\n const entity = (match[1] ?? match[2] ?? match[0]).trim().replace(/^[\"'(]+|[\"'),]+$/g, '');\n if (entity.length < 3 || (kind === 'file' && entity.length < 5)) continue;\n\n const key = `${kind}:${entity.toLowerCase()}`;\n if (seen.has(key)) continue;\n seen.add(key);\n\n switch (kind) {\n case 'file':\n // Filter out property chains (e.g. config.llm.apiKey, process.env.FOO)\n // Real files have path separators or known extensions\n // Inline logic to prevent tree-shaking\n const isLikelyFilePath = (() => {\n // Has path separator → likely a file path\n if (entity.includes('/') || entity.includes('\\\\')) return true;\n // Starts with ./ or ../ → relative path\n if (entity.startsWith('./') || entity.startsWith('../')) return true;\n // Blocked property chains\n if (/^(?:process\\.env|config\\.|options\\.|params\\.|props\\.|this\\.|self\\.|module\\.|exports\\.|require\\.|import\\.)/i.test(entity)) return false;\n // Multiple dots without path separator → likely property chain\n const dotCount = (entity.match(/\\./g) || []).length;\n if (dotCount >= 2) return false;\n // Single dot: check if extension is a known file extension\n const ext = entity.split('.').pop()?.toLowerCase() ?? '';\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']);\n return FILE_EXTENSIONS.has(ext);\n })();\n if (isLikelyFilePath) {\n result.files.push(entity);\n }\n break;\n case 'module':\n result.modules.push(entity);\n break;\n case 'url':\n result.urls.push(entity);\n break;\n case 'mention':\n result.mentions.push(entity);\n break;\n case 'identifier':\n result.identifiers.push(entity);\n break;\n }\n }\n }\n\n result.hasCausalLanguage = CAUSAL_PATTERN.test(content);\n\n return result;\n}\n\n/** Known file extensions that indicate a real file path */\nconst FILE_EXTENSIONS = new Set([\n 'ts', 'js', 'tsx', 'jsx', 'mts', 'mjs', 'cjs',\n 'json', 'yaml', 'yml', 'toml', 'xml', 'csv',\n 'py', 'rb', 'go', 'rs', 'java', 'kt', 'swift', 'c', 'cpp', 'h',\n 'html', 'css', 'scss', 'less', 'vue', 'svelte',\n 'sh', 'bash', 'zsh', 'ps1', 'cmd', 'bat',\n 'md', 'txt', 'rst', 'log',\n 'sql', 'graphql', 'prisma',\n 'env', 'gitignore', 'dockerignore', 'dockerfile',\n 'lock', 'config',\n]);\n\n/** Property-chain patterns that are NOT file paths */\nconst PROPERTY_CHAIN_BLOCKLIST = /^(?:process\\.env|config\\.|options\\.|params\\.|props\\.|this\\.|self\\.|module\\.|exports\\.|require\\.|import\\.)/i;\n\n/**\n * Determine if a matched string is likely a real file path vs a property chain.\n * \n * Examples:\n * \"src/config.ts\" → true (has path separator + known extension)\n * \"config.llm.apiKey\" → false (property chain, no path separator)\n * \"./package.json\" → true (relative path)\n * \"process.env.FOO\" → false (property chain)\n */\nfunction isLikelyFilePath(candidate: string): boolean {\n // Has path separator → likely a file path\n if (candidate.includes('/') || candidate.includes('\\\\')) return true;\n\n // Starts with ./ or ../ → relative path\n if (candidate.startsWith('./') || candidate.startsWith('../')) return true;\n\n // Blocked property chains\n if (PROPERTY_CHAIN_BLOCKLIST.test(candidate)) return false;\n\n // Multiple dots without path separator → likely property chain (e.g. config.llm.apiKey)\n const dotCount = (candidate.match(/\\./g) || []).length;\n if (dotCount >= 2) return false;\n\n // Single dot: check if extension is a known file extension\n const ext = candidate.split('.').pop()?.toLowerCase() ?? '';\n return FILE_EXTENSIONS.has(ext);\n}\n\n/**\n * Auto-generate concepts from extracted entities.\n * Merges with any user-provided concepts.\n */\nexport function enrichConcepts(\n userConcepts: string[],\n extracted: ExtractedEntities,\n): string[] {\n const all = new Set(userConcepts.map((c) => c.toLowerCase()));\n const enriched = [...userConcepts];\n\n // Add file names (without path) as concepts\n for (const f of extracted.files) {\n const name = f.split('/').pop()?.replace(/\\.\\w+$/, '') ?? '';\n if (name.length >= 3 && !all.has(name.toLowerCase())) {\n all.add(name.toLowerCase());\n enriched.push(name);\n }\n }\n\n // Add module names as concepts\n for (const m of extracted.modules) {\n const short = m.split(/[./]/).pop() ?? '';\n if (short.length >= 3 && !all.has(short.toLowerCase())) {\n all.add(short.toLowerCase());\n enriched.push(short);\n }\n }\n\n // Add CamelCase identifiers as concepts\n for (const id of extracted.identifiers) {\n if (!all.has(id.toLowerCase())) {\n all.add(id.toLowerCase());\n enriched.push(id);\n }\n }\n\n return enriched;\n}\n","/**\n * Secret Filter\n *\n * Conservative credential detection and redaction for Memorix memory content.\n * Designed for low false-positive risk: only matches explicit credential\n * assignments (key=value / key: value), not generic discussion of auth concepts.\n *\n * sanitizeCredentials() — store-time: called inside storeObservation() before write\n * redactCredentials() — retrieval-time: called in format/output paths for legacy safety\n * containsCredential() — predicate used for testing and optional logging\n *\n * Both sanitize and redact share the same pattern logic. They are kept as\n * separate named exports so call-site semantics remain clear.\n */\n\n/**\n * Replaces the VALUE portion of matched credential patterns with [REDACTED].\n * The credential key name is preserved so context is not lost.\n *\n * Pattern categories:\n * 1. key=value / key: value forms — password, token, api_key, secret, etc.\n * Requires a real value (6+ non-whitespace chars) to avoid matching\n * discussion text like \"password must be 8 chars\".\n * 2. Bearer authorization header tokens (20+ chars)\n * 3. Structured token prefixes: GitHub (ghp_/ghs_/gho_), OpenAI (sk-), JWT (eyJ)\n */\nfunction applyRedaction(text: string): string {\n if (!text) return text;\n let out = text;\n\n // key=value / key: \"value\" / key='value' — preserve key, redact value\n out = out.replace(\n /((?:password|passwd|pwd|secret|token|api[_-]?key|auth[_-]?key|access[_-]?key|private[_-]?key|client[_-]?secret)\\s*[:=]\\s*[\"']?)([^\\s\"',;\\n]{6,})/gi,\n '$1[REDACTED]',\n );\n\n // Bearer <token> — preserve \"Bearer \", redact token\n out = out.replace(\n /(Bearer\\s+)([A-Za-z0-9._\\-/+]{20,})/g,\n '$1[REDACTED]',\n );\n\n // GitHub tokens (ghp_, ghs_, gho_, github_pat_)\n out = out.replace(/\\b(?:ghp|ghs|gho|github_pat)_[A-Za-z0-9]{36,}\\b/g, '[REDACTED]');\n\n // OpenAI / similar keys (sk-...)\n out = out.replace(/\\bsk-[A-Za-z0-9T-]{20,}\\b/g, '[REDACTED]');\n\n // JWT tokens (base64url header eyJ...)\n out = out.replace(/\\beyJ[A-Za-z0-9._-]{40,}\\b/g, '[REDACTED]');\n\n return out;\n}\n\n/**\n * Store-time sanitization: strips credential values before any durable write.\n * Called inside storeObservation() / upsertObservation() so that every write\n * path (hooks, git-ingest, CLI, reasoning, compact-on-write) is covered.\n */\nexport function sanitizeCredentials(text: string): string {\n return applyRedaction(text);\n}\n\n/**\n * Retrieval-time redaction: masks credential values in display output.\n * Applied in all output formatters (detail, index table, timeline, session context)\n * as a safety net for legacy observations stored before sanitization was in place.\n */\nexport function redactCredentials(text: string): string {\n return applyRedaction(text);\n}\n\n/**\n * Returns true if the text contains an obvious credential pattern.\n * Used for testing and optional diagnostic logging.\n */\nexport function containsCredential(text: string): boolean {\n return applyRedaction(text) !== text;\n}\n","import { randomUUID } from 'node:crypto';\n\nimport { getDatabase } from '../store/sqlite-db.js';\nimport { sanitizeCredentials } from '../memory/secret-filter.js';\n\nexport const MAINTENANCE_JOB_KINDS = [\n 'vector-backfill',\n 'retention-archive',\n 'consolidation',\n 'codegraph-refresh',\n 'observation-qualify',\n 'claim-derive',\n 'claim-requalification',\n 'knowledge-compile',\n 'knowledge-lint',\n 'workflow-index',\n] as const;\n\nexport type MaintenanceJobKind = typeof MAINTENANCE_JOB_KINDS[number];\nexport type MaintenanceJobStatus = 'pending' | 'running' | 'retry' | 'completed' | 'failed';\n\nexport interface MaintenanceJob {\n id: string;\n projectId: string;\n kind: MaintenanceJobKind;\n dedupeKey: string;\n payload: Record<string, unknown>;\n status: MaintenanceJobStatus;\n attempts: number;\n maxAttempts: number;\n runAfter: number;\n leaseOwner?: string;\n leaseExpiresAt?: number;\n lastError?: string;\n createdAt: number;\n updatedAt: number;\n completedAt?: number;\n}\n\nexport interface EnqueueMaintenanceJobInput {\n projectId: string;\n kind: MaintenanceJobKind;\n dedupeKey?: string;\n payload?: Record<string, unknown>;\n maxAttempts?: number;\n runAfter?: number;\n now?: number;\n}\n\nexport interface ClaimMaintenanceJobOptions {\n workerId: string;\n projectId?: string;\n /** Limit this worker to compatible job kinds without claiming other work. */\n kinds?: readonly MaintenanceJobKind[];\n leaseMs?: number;\n now?: number;\n}\n\nexport interface MaintenanceJobSummary {\n total: number;\n pending: number;\n running: number;\n retrying: number;\n completed: number;\n failed: number;\n}\n\nexport type MaintenanceJobRunResult =\n | { action: 'complete' }\n | { action: 'reschedule'; delayMs: number; resetAttempts?: boolean; payload?: Record<string, unknown> };\n\nexport type MaintenanceJobHandler = (\n job: MaintenanceJob,\n) => Promise<MaintenanceJobRunResult | void>;\n\nconst DEFAULT_MAX_ATTEMPTS = 8;\nconst DEFAULT_LEASE_MS = 30_000;\nconst DEFAULT_POLL_INTERVAL_MS = 2_000;\nconst MAX_ERROR_LENGTH = 1_000;\nconst DEFAULT_COMPLETED_HISTORY_RETENTION_MS = 7 * 24 * 60 * 60 * 1_000;\n\nfunction parsePayload(raw: unknown): Record<string, unknown> {\n if (typeof raw !== 'string' || !raw) return {};\n try {\n const parsed = JSON.parse(raw);\n return parsed && typeof parsed === 'object' && !Array.isArray(parsed)\n ? parsed as Record<string, unknown>\n : {};\n } catch {\n return {};\n }\n}\n\nfunction rowToJob(row: any): MaintenanceJob {\n return {\n id: row.id,\n projectId: row.project_id,\n kind: row.kind as MaintenanceJobKind,\n dedupeKey: row.dedupe_key,\n payload: parsePayload(row.payload_json),\n status: row.status as MaintenanceJobStatus,\n attempts: Number(row.attempts),\n maxAttempts: Number(row.max_attempts),\n runAfter: Number(row.run_after),\n ...(row.lease_owner ? { leaseOwner: row.lease_owner } : {}),\n ...(row.lease_expires_at != null ? { leaseExpiresAt: Number(row.lease_expires_at) } : {}),\n ...(row.last_error ? { lastError: row.last_error } : {}),\n createdAt: Number(row.created_at),\n updatedAt: Number(row.updated_at),\n ...(row.completed_at != null ? { completedAt: Number(row.completed_at) } : {}),\n };\n}\n\nfunction clampPositiveInteger(value: number | undefined, fallback: number): number {\n if (!Number.isFinite(value) || value == null) return fallback;\n return Math.max(1, Math.floor(value));\n}\n\nfunction errorText(error: unknown): string {\n const text = error instanceof Error ? error.message : String(error);\n return sanitizeCredentials(text).slice(0, MAX_ERROR_LENGTH);\n}\n\nfunction normalizedKinds(kinds: readonly MaintenanceJobKind[] | undefined): MaintenanceJobKind[] | undefined {\n if (!kinds) return undefined;\n return [...new Set(kinds.filter((kind) => MAINTENANCE_JOB_KINDS.includes(kind)))];\n}\n\n/** Retry delay grows slowly enough for a local control plane but never spins. */\nexport function getMaintenanceRetryDelayMs(attempts: number): number {\n return Math.min(60_000, 1_000 * (2 ** Math.max(0, attempts - 1)));\n}\n\n/**\n * Persistent queue for work that must never run inside an MCP tool handler.\n * SQLite leases make recovery deterministic when a process exits mid-job.\n */\nexport class MaintenanceJobStore {\n private readonly db: any;\n\n constructor(dataDir: string) {\n this.db = getDatabase(dataDir);\n }\n\n enqueue(input: EnqueueMaintenanceJobInput): MaintenanceJob {\n const now = input.now ?? Date.now();\n const dedupeKey = input.dedupeKey ?? input.kind;\n const runAfter = input.runAfter ?? now;\n const maxAttempts = clampPositiveInteger(input.maxAttempts, DEFAULT_MAX_ATTEMPTS);\n const payloadJson = JSON.stringify(input.payload ?? {});\n\n this.begin();\n try {\n this.pruneCompletedHistory({ now });\n const existing = this.db.prepare(`\n SELECT * FROM maintenance_jobs\n WHERE project_id = ? AND kind = ? AND dedupe_key = ?\n AND status IN ('pending', 'running', 'retry')\n LIMIT 1\n `).get(input.projectId, input.kind, dedupeKey);\n\n if (existing) {\n const nextRunAfter = Math.min(Number(existing.run_after), runAfter);\n this.db.prepare(`\n UPDATE maintenance_jobs\n SET payload_json = ?, run_after = ?, updated_at = ?\n WHERE id = ?\n `).run(payloadJson, nextRunAfter, now, existing.id);\n const updated = this.getRow(existing.id)!;\n this.commit();\n return rowToJob(updated);\n }\n\n const id = randomUUID();\n this.db.prepare(`\n INSERT INTO maintenance_jobs (\n id, project_id, kind, dedupe_key, payload_json, status, attempts,\n max_attempts, run_after, created_at, updated_at\n ) VALUES (?, ?, ?, ?, ?, 'pending', 0, ?, ?, ?, ?)\n `).run(id, input.projectId, input.kind, dedupeKey, payloadJson, maxAttempts, runAfter, now, now);\n const created = this.getRow(id)!;\n this.commit();\n return rowToJob(created);\n } catch (error) {\n this.rollback();\n throw error;\n }\n }\n\n get(id: string): MaintenanceJob | undefined {\n const row = this.getRow(id);\n return row ? rowToJob(row) : undefined;\n }\n\n list(options: { projectId?: string; status?: MaintenanceJobStatus; limit?: number } = {}): MaintenanceJob[] {\n const limit = Math.min(500, clampPositiveInteger(options.limit, 100));\n const clauses: string[] = [];\n const values: unknown[] = [];\n if (options.projectId) {\n clauses.push('project_id = ?');\n values.push(options.projectId);\n }\n if (options.status) {\n clauses.push('status = ?');\n values.push(options.status);\n }\n const where = clauses.length > 0 ? `WHERE ${clauses.join(' AND ')}` : '';\n const rows = this.db.prepare(`\n SELECT * FROM maintenance_jobs\n ${where}\n ORDER BY run_after ASC, created_at ASC\n LIMIT ?\n `).all(...values, limit);\n return rows.map(rowToJob);\n }\n\n summary(projectId?: string): MaintenanceJobSummary {\n const row = projectId\n ? this.db.prepare(`\n SELECT\n COUNT(*) AS total,\n SUM(status = 'pending') AS pending,\n SUM(status = 'running') AS running,\n SUM(status = 'retry') AS retrying,\n SUM(status = 'completed') AS completed,\n SUM(status = 'failed') AS failed\n FROM maintenance_jobs WHERE project_id = ?\n `).get(projectId)\n : this.db.prepare(`\n SELECT\n COUNT(*) AS total,\n SUM(status = 'pending') AS pending,\n SUM(status = 'running') AS running,\n SUM(status = 'retry') AS retrying,\n SUM(status = 'completed') AS completed,\n SUM(status = 'failed') AS failed\n FROM maintenance_jobs\n `).get();\n return {\n total: Number(row?.total ?? 0),\n pending: Number(row?.pending ?? 0),\n running: Number(row?.running ?? 0),\n retrying: Number(row?.retrying ?? 0),\n completed: Number(row?.completed ?? 0),\n failed: Number(row?.failed ?? 0),\n };\n }\n\n /**\n * Completed jobs are useful recent operator history, not permanent data.\n * Failed jobs stay available for diagnosis until an operator explicitly\n * resolves them or clears the database.\n */\n pruneCompletedHistory(options: { now?: number; maxAgeMs?: number } = {}): number {\n const now = options.now ?? Date.now();\n const maxAgeMs = Number.isFinite(options.maxAgeMs)\n ? Math.max(0, Math.floor(options.maxAgeMs!))\n : DEFAULT_COMPLETED_HISTORY_RETENTION_MS;\n const result = this.db.prepare(`\n DELETE FROM maintenance_jobs\n WHERE status = 'completed'\n AND completed_at IS NOT NULL\n AND completed_at < ?\n `).run(now - maxAgeMs);\n return Number(result.changes ?? 0);\n }\n\n claimNext(options: ClaimMaintenanceJobOptions): MaintenanceJob | undefined {\n const now = options.now ?? Date.now();\n const leaseMs = clampPositiveInteger(options.leaseMs, DEFAULT_LEASE_MS);\n const kinds = normalizedKinds(options.kinds);\n\n this.begin();\n try {\n // A dead worker leaves a leased row behind. Make it retryable before\n // selecting the next candidate, while respecting its retry budget.\n this.db.prepare(`\n UPDATE maintenance_jobs\n SET\n status = CASE WHEN attempts >= max_attempts THEN 'failed' ELSE 'retry' END,\n run_after = CASE WHEN attempts >= max_attempts THEN run_after ELSE ? END,\n lease_owner = NULL,\n lease_expires_at = NULL,\n last_error = COALESCE(last_error, 'worker lease expired'),\n updated_at = ?\n WHERE status = 'running' AND lease_expires_at IS NOT NULL AND lease_expires_at <= ?\n `).run(now, now, now);\n this.db.prepare(`\n UPDATE maintenance_jobs\n SET status = 'failed', updated_at = ?\n WHERE status IN ('pending', 'retry') AND attempts >= max_attempts\n `).run(now);\n\n if (options.kinds && kinds?.length === 0) {\n this.commit();\n return undefined;\n }\n const projectClause = options.projectId ? 'AND project_id = ?' : '';\n const kindClause = kinds?.length\n ? `AND kind IN (${kinds.map(() => '?').join(', ')})`\n : '';\n const values = [\n now,\n ...(kinds ?? []),\n ...(options.projectId ? [options.projectId] : []),\n ];\n const candidate = this.db.prepare(`\n SELECT * FROM maintenance_jobs\n WHERE status IN ('pending', 'retry') AND run_after <= ?\n ${kindClause}\n ${projectClause}\n ORDER BY run_after ASC, created_at ASC\n LIMIT 1\n `).get(...values);\n\n if (!candidate) {\n this.commit();\n return undefined;\n }\n\n const leaseExpiresAt = now + leaseMs;\n this.db.prepare(`\n UPDATE maintenance_jobs\n SET status = 'running', attempts = attempts + 1, lease_owner = ?,\n lease_expires_at = ?, updated_at = ?\n WHERE id = ?\n `).run(options.workerId, leaseExpiresAt, now, candidate.id);\n const claimed = this.getRow(candidate.id)!;\n this.commit();\n return rowToJob(claimed);\n } catch (error) {\n this.rollback();\n throw error;\n }\n }\n\n /**\n * Extend a running job's lease. A worker may only renew its own lease, so a\n * stale worker cannot reclaim work that was already recovered elsewhere.\n */\n renewLease(id: string, workerId: string, leaseMs = DEFAULT_LEASE_MS, now = Date.now()): boolean {\n const expiresAt = now + clampPositiveInteger(leaseMs, DEFAULT_LEASE_MS);\n const result = this.db.prepare(`\n UPDATE maintenance_jobs\n SET lease_expires_at = ?, updated_at = ?\n WHERE id = ? AND status = 'running' AND lease_owner = ?\n `).run(expiresAt, now, id, workerId);\n return Number(result.changes) > 0;\n }\n\n complete(id: string, workerId: string, now = Date.now()): MaintenanceJob | undefined {\n this.db.prepare(`\n UPDATE maintenance_jobs\n SET status = 'completed', lease_owner = NULL, lease_expires_at = NULL,\n completed_at = ?, updated_at = ?\n WHERE id = ? AND status = 'running' AND lease_owner = ?\n `).run(now, now, id, workerId);\n return this.get(id);\n }\n\n reschedule(\n id: string,\n workerId: string,\n options: { delayMs: number; resetAttempts?: boolean; payload?: Record<string, unknown>; now?: number },\n ): MaintenanceJob | undefined {\n const now = options.now ?? Date.now();\n const delayMs = Number.isFinite(options.delayMs) ? Math.max(0, Math.floor(options.delayMs)) : 0;\n const payloadJson = options.payload === undefined ? null : JSON.stringify(options.payload);\n this.db.prepare(`\n UPDATE maintenance_jobs\n SET status = 'pending', run_after = ?, attempts = CASE WHEN ? THEN 0 ELSE attempts END,\n payload_json = COALESCE(?, payload_json),\n lease_owner = NULL, lease_expires_at = NULL, updated_at = ?\n WHERE id = ? AND status = 'running' AND lease_owner = ?\n `).run(now + delayMs, options.resetAttempts ? 1 : 0, payloadJson, now, id, workerId);\n return this.get(id);\n }\n\n fail(id: string, workerId: string, error: unknown, now = Date.now()): MaintenanceJob | undefined {\n this.begin();\n try {\n const current = this.db.prepare(`\n SELECT * FROM maintenance_jobs\n WHERE id = ? AND status = 'running' AND lease_owner = ?\n `).get(id, workerId);\n if (!current) {\n this.commit();\n return undefined;\n }\n\n const attempts = Number(current.attempts);\n const exhausted = attempts >= Number(current.max_attempts);\n const status: MaintenanceJobStatus = exhausted ? 'failed' : 'retry';\n const runAfter = exhausted ? Number(current.run_after) : now + getMaintenanceRetryDelayMs(attempts);\n this.db.prepare(`\n UPDATE maintenance_jobs\n SET status = ?, run_after = ?, lease_owner = NULL, lease_expires_at = NULL,\n last_error = ?, updated_at = ?\n WHERE id = ?\n `).run(status, runAfter, errorText(error), now, id);\n const updated = this.getRow(id)!;\n this.commit();\n return rowToJob(updated);\n } catch (caught) {\n this.rollback();\n throw caught;\n }\n }\n\n private getRow(id: string): any {\n return this.db.prepare(`SELECT * FROM maintenance_jobs WHERE id = ?`).get(id);\n }\n\n private begin(): void {\n this.db.prepare('BEGIN IMMEDIATE').run();\n }\n\n private commit(): void {\n this.db.prepare('COMMIT').run();\n }\n\n private rollback(): void {\n try { this.db.prepare('ROLLBACK').run(); } catch { /* transaction already closed */ }\n }\n}\n\nexport class MaintenanceJobWorker {\n private readonly workerId: string;\n private readonly leaseMs: number;\n private readonly pollIntervalMs: number;\n private readonly projectId?: string;\n private readonly kinds?: readonly MaintenanceJobKind[];\n private timer: ReturnType<typeof setInterval> | null = null;\n private running = false;\n\n constructor(\n private readonly store: MaintenanceJobStore,\n private readonly handler: MaintenanceJobHandler,\n options: {\n workerId?: string;\n leaseMs?: number;\n pollIntervalMs?: number;\n projectId?: string;\n kinds?: readonly MaintenanceJobKind[];\n } = {},\n ) {\n this.workerId = options.workerId ?? `memorix-${process.pid}-${randomUUID().slice(0, 8)}`;\n this.leaseMs = clampPositiveInteger(options.leaseMs, DEFAULT_LEASE_MS);\n this.pollIntervalMs = clampPositiveInteger(options.pollIntervalMs, DEFAULT_POLL_INTERVAL_MS);\n this.projectId = options.projectId;\n this.kinds = options.kinds;\n }\n\n async runOnce(now = Date.now()): Promise<{ state: 'idle' | 'busy' | 'completed' | 'rescheduled' | 'failed'; job?: MaintenanceJob }> {\n if (this.running) return { state: 'busy' };\n this.running = true;\n try {\n const job = this.store.claimNext({\n workerId: this.workerId,\n projectId: this.projectId,\n kinds: this.kinds,\n now,\n leaseMs: this.leaseMs,\n });\n if (!job) return { state: 'idle' };\n\n const heartbeatMs = Math.max(10, Math.floor(this.leaseMs / 3));\n let leaseLost = false;\n const heartbeat = setInterval(() => {\n try {\n leaseLost = !this.store.renewLease(job.id, this.workerId, this.leaseMs);\n } catch {\n // The next heartbeat can recover from a transient SQLite error. The\n // job itself still has its prior lease until it expires.\n }\n }, heartbeatMs);\n heartbeat.unref?.();\n\n try {\n const result = await this.handler(job);\n if (leaseLost) {\n return { state: 'failed', job: this.store.get(job.id) };\n }\n if (result?.action === 'reschedule') {\n const updated = this.store.reschedule(job.id, this.workerId, {\n delayMs: result.delayMs,\n resetAttempts: result.resetAttempts,\n payload: result.payload,\n now,\n });\n return { state: 'rescheduled', job: updated };\n }\n const updated = this.store.complete(job.id, this.workerId, now);\n return { state: 'completed', job: updated };\n } catch (error) {\n const updated = this.store.fail(job.id, this.workerId, error, now);\n return { state: 'failed', job: updated };\n } finally {\n clearInterval(heartbeat);\n }\n } finally {\n this.running = false;\n }\n }\n\n start(): void {\n if (this.timer) return;\n void this.runOnce().catch(() => {});\n this.timer = setInterval(() => { void this.runOnce().catch(() => {}); }, this.pollIntervalMs);\n this.timer.unref?.();\n }\n\n stop(): void {\n if (!this.timer) return;\n clearInterval(this.timer);\n this.timer = null;\n }\n}\n","import { MaintenanceJobStore } from './maintenance-jobs.js';\n\nexport type MaintenanceQueue = Pick<MaintenanceJobStore, 'enqueue'>;\n\nfunction queueFor(input: { dataDir: string; queue?: MaintenanceQueue }): MaintenanceQueue {\n return input.queue ?? new MaintenanceJobStore(input.dataDir);\n}\n\n/**\n * Coalesce every trigger for a project's next Code Memory scan. The newest\n * event replaces the payload while one durable job remains pending.\n */\nexport function enqueueCodegraphRefresh(input: {\n dataDir: string;\n projectId: string;\n source: string;\n maxFiles?: number;\n queue?: MaintenanceQueue;\n}): void {\n queueFor(input).enqueue({\n projectId: input.projectId,\n kind: 'codegraph-refresh',\n dedupeKey: 'codegraph-refresh',\n payload: {\n source: input.source,\n ...(input.maxFiles ? { maxFiles: input.maxFiles } : {}),\n },\n });\n}\n\n/**\n * Requalification is owned by one job per project, never by an individual\n * snapshot. A newer refresh replaces the snapshot metadata before it runs.\n */\nexport function enqueueClaimRequalification(input: {\n dataDir: string;\n projectId: string;\n source: string;\n snapshotId?: string;\n queue?: MaintenanceQueue;\n}): void {\n queueFor(input).enqueue({\n projectId: input.projectId,\n kind: 'claim-requalification',\n dedupeKey: 'claim-requalification',\n payload: {\n source: input.source,\n ...(input.snapshotId ? { snapshotId: input.snapshotId } : {}),\n },\n });\n}\n\n/** A stored explicit/Git observation earns a recoverable claim derivation. */\nexport function enqueueClaimDerivation(input: {\n dataDir: string;\n projectId: string;\n observationId: number;\n queue?: MaintenanceQueue;\n}): void {\n queueFor(input).enqueue({\n projectId: input.projectId,\n kind: 'claim-derive',\n dedupeKey: 'claim-derive:' + input.observationId,\n payload: { observationId: input.observationId },\n });\n}\n\n/**\n * Automatic captures are initially only candidates. Qualification runs in the\n * durable maintenance lane after Code Memory has a chance to refresh.\n */\nexport function enqueueObservationQualification(input: {\n dataDir: string;\n projectId: string;\n source: string;\n queue?: MaintenanceQueue;\n}): void {\n queueFor(input).enqueue({\n projectId: input.projectId,\n kind: 'observation-qualify',\n dedupeKey: 'observation-qualify',\n payload: { source: input.source, limit: 100 },\n });\n}\n\n/**\n * The follow-up jobs operate on the same workspace the Workset reads: a\n * versioned workspace when present, otherwise the local workspace.\n */\nexport function enqueueKnowledgeFollowups(input: {\n dataDir: string;\n projectId: string;\n source: string;\n includeCompile?: boolean;\n workspaceMode?: 'local' | 'versioned';\n allowVersionedWrite?: boolean;\n queue?: MaintenanceQueue;\n}): void {\n const queue = queueFor(input);\n const payload = {\n source: input.source,\n ...(input.workspaceMode ? { workspaceMode: input.workspaceMode } : {}),\n ...(input.allowVersionedWrite ? { allowVersionedWrite: true } : {}),\n };\n if (input.includeCompile) {\n queue.enqueue({\n projectId: input.projectId,\n kind: 'knowledge-compile',\n dedupeKey: 'knowledge-compile',\n payload,\n });\n }\n queue.enqueue({\n projectId: input.projectId,\n kind: 'knowledge-lint',\n dedupeKey: 'knowledge-lint',\n payload,\n });\n queue.enqueue({\n projectId: input.projectId,\n kind: 'workflow-index',\n dedupeKey: 'workflow-index',\n payload,\n });\n}\n","import { createHash } from 'node:crypto';\n\nfunction digest(input: string): string {\n return createHash('sha256').update(input).digest('hex').slice(0, 16);\n}\n\nexport function normalizeCodePath(path: string): string {\n return path.replace(/\\\\/g, '/').replace(/^\\.\\//, '').replace(/\\/+/g, '/');\n}\n\nexport function makeCodeFileId(projectId: string, path: string): string {\n return `file:${digest(`${projectId}\\n${normalizeCodePath(path)}`)}`;\n}\n\nexport function makeCodeSymbolId(input: {\n projectId: string;\n path: string;\n qualifiedName: string;\n kind: string;\n}): string {\n return `symbol:${digest([\n input.projectId,\n normalizeCodePath(input.path),\n input.qualifiedName,\n input.kind,\n ].join('\\n'))}`;\n}\n\nexport function makeCodeEdgeId(projectId: string, from: string, type: string, to: string): string {\n return `edge:${digest([projectId, from, type, to].join('\\n'))}`;\n}\n\nexport function makeObservationCodeRefId(projectId: string, observationId: number, fileId?: string, symbolId?: string): string {\n return `coderef:${digest([projectId, String(observationId), fileId ?? '', symbolId ?? ''].join('\\n'))}`;\n}\n","import { randomUUID } from 'node:crypto';\nimport { getDatabase } from '../store/sqlite-db.js';\nimport type {\n CodeEdge,\n CodeFile,\n CodeGraphStatus,\n CodeStateScanCompleteness,\n CodeStateSnapshot,\n CodeStateSnapshotInput,\n CodeSymbol,\n ObservationCodeRef,\n} from './types.js';\nimport { normalizeCodePath } from './ids.js';\n\nexport interface CodeGraphFileDelta {\n file: CodeFile;\n symbols: CodeSymbol[];\n edges: CodeEdge[];\n}\n\nfunction rowToFile(row: any): CodeFile {\n return {\n id: row.id,\n projectId: row.projectId,\n path: row.path,\n ...(row.language ? { language: row.language } : {}),\n contentHash: row.contentHash,\n ...(row.mtimeMs != null ? { mtimeMs: row.mtimeMs } : {}),\n ...(row.sizeBytes != null ? { sizeBytes: row.sizeBytes } : {}),\n indexedAt: row.indexedAt,\n ...(row.gitCommit ? { gitCommit: row.gitCommit } : {}),\n ...(row.snapshotId ? { snapshotId: row.snapshotId } : {}),\n ...(row.sourceEpoch != null ? { sourceEpoch: Number(row.sourceEpoch) } : {}),\n };\n}\n\nfunction rowToSymbol(row: any): CodeSymbol {\n return {\n id: row.id,\n projectId: row.projectId,\n fileId: row.fileId,\n path: row.path,\n name: row.name,\n qualifiedName: row.qualifiedName,\n kind: row.kind,\n ...(row.startLine != null ? { startLine: row.startLine } : {}),\n ...(row.endLine != null ? { endLine: row.endLine } : {}),\n ...(row.signature ? { signature: row.signature } : {}),\n ...(row.contentHash ? { contentHash: row.contentHash } : {}),\n indexedAt: row.indexedAt,\n stale: !!row.stale,\n ...(row.snapshotId ? { snapshotId: row.snapshotId } : {}),\n ...(row.sourceEpoch != null ? { sourceEpoch: Number(row.sourceEpoch) } : {}),\n } as CodeSymbol;\n}\n\nfunction rowToEdge(row: any): CodeEdge {\n return {\n id: row.id,\n projectId: row.projectId,\n ...(row.fromSymbolId ? { fromSymbolId: row.fromSymbolId } : {}),\n ...(row.toSymbolId ? { toSymbolId: row.toSymbolId } : {}),\n ...(row.fromFileId ? { fromFileId: row.fromFileId } : {}),\n ...(row.toFileId ? { toFileId: row.toFileId } : {}),\n type: row.type,\n confidence: row.confidence,\n ...(row.evidence ? { evidence: row.evidence } : {}),\n indexedAt: row.indexedAt,\n ...(row.snapshotId ? { snapshotId: row.snapshotId } : {}),\n ...(row.sourceEpoch != null ? { sourceEpoch: Number(row.sourceEpoch) } : {}),\n } as CodeEdge;\n}\n\nfunction rowToRef(row: any): ObservationCodeRef {\n return {\n id: row.id,\n projectId: row.projectId,\n observationId: row.observationId,\n ...(row.fileId ? { fileId: row.fileId } : {}),\n ...(row.symbolId ? { symbolId: row.symbolId } : {}),\n ...(row.capturedFileHash ? { capturedFileHash: row.capturedFileHash } : {}),\n ...(row.capturedSymbolHash ? { capturedSymbolHash: row.capturedSymbolHash } : {}),\n status: row.status,\n ...(row.reason ? { reason: row.reason } : {}),\n createdAt: row.createdAt,\n ...(row.updatedAt ? { updatedAt: row.updatedAt } : {}),\n ...(row.snapshotId ? { snapshotId: row.snapshotId } : {}),\n } as ObservationCodeRef;\n}\n\nfunction parseCompleteness(raw: unknown): CodeStateScanCompleteness {\n try {\n const parsed = typeof raw === 'string' ? JSON.parse(raw) : raw;\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) throw new Error('invalid completeness');\n return {\n scannedFiles: Number((parsed as any).scannedFiles) || 0,\n maxFiles: Number((parsed as any).maxFiles) || 0,\n changedFiles: Number((parsed as any).changedFiles) || 0,\n unchangedFiles: Number((parsed as any).unchangedFiles) || 0,\n metadataOnlyFiles: Number((parsed as any).metadataOnlyFiles) || 0,\n removedFiles: Number((parsed as any).removedFiles) || 0,\n skippedOversizedFiles: Number((parsed as any).skippedOversizedFiles) || 0,\n unreadableFiles: Number((parsed as any).unreadableFiles) || 0,\n removalScanDeferred: Boolean((parsed as any).removalScanDeferred),\n };\n } catch {\n return {\n scannedFiles: 0,\n maxFiles: 0,\n changedFiles: 0,\n unchangedFiles: 0,\n metadataOnlyFiles: 0,\n removedFiles: 0,\n skippedOversizedFiles: 0,\n unreadableFiles: 0,\n removalScanDeferred: false,\n };\n }\n}\n\nfunction rowToSnapshot(row: any): CodeStateSnapshot {\n return {\n id: row.id,\n projectId: row.projectId,\n provider: row.provider,\n ...(row.baseRevision ? { baseRevision: row.baseRevision } : {}),\n worktreeFingerprint: row.worktreeFingerprint,\n worktreeState: row.worktreeState,\n changedPathCount: Number(row.changedPathCount),\n indexedAt: row.indexedAt,\n sourceEpoch: Number(row.sourceEpoch),\n completeness: parseCompleteness(row.completenessJson),\n ...(row.previousSnapshotId ? { previousSnapshotId: row.previousSnapshotId } : {}),\n } as CodeStateSnapshot;\n}\n\nexport class CodeGraphStore {\n private db: any = null;\n private dataDir: string | null = null;\n\n async init(dataDir: string): Promise<void> {\n this.dataDir = dataDir;\n this.db = getDatabase(dataDir);\n }\n\n /** Data directory shared with the rest of the local project evidence stores. */\n getDataDir(): string {\n if (!this.dataDir) throw new Error('CodeGraphStore is not initialized');\n return this.dataDir;\n }\n\n upsertFiles(files: CodeFile[]): void {\n if (files.length === 0) return;\n const stmt = this.db.prepare(`\n INSERT OR REPLACE INTO code_files\n (id, projectId, path, language, contentHash, mtimeMs, sizeBytes, indexedAt, gitCommit)\n VALUES\n (@id, @projectId, @path, @language, @contentHash, @mtimeMs, @sizeBytes, @indexedAt, @gitCommit)\n `);\n const tx = this.db.transaction((items: CodeFile[]) => {\n for (const file of items) {\n stmt.run({\n id: file.id,\n projectId: file.projectId,\n path: normalizeCodePath(file.path),\n language: file.language ?? null,\n contentHash: file.contentHash,\n mtimeMs: file.mtimeMs ?? null,\n sizeBytes: file.sizeBytes ?? null,\n indexedAt: file.indexedAt,\n gitCommit: file.gitCommit ?? null,\n });\n }\n });\n tx(files);\n }\n\n upsertSymbols(symbols: CodeSymbol[]): void {\n if (symbols.length === 0) return;\n const stmt = this.db.prepare(`\n INSERT OR REPLACE INTO code_symbols\n (id, projectId, fileId, path, name, qualifiedName, kind, startLine, endLine, signature, contentHash, indexedAt, stale)\n VALUES\n (@id, @projectId, @fileId, @path, @name, @qualifiedName, @kind, @startLine, @endLine, @signature, @contentHash, @indexedAt, @stale)\n `);\n const tx = this.db.transaction((items: CodeSymbol[]) => {\n for (const symbol of items) {\n stmt.run({\n id: symbol.id,\n projectId: symbol.projectId,\n fileId: symbol.fileId,\n path: normalizeCodePath(symbol.path),\n name: symbol.name,\n qualifiedName: symbol.qualifiedName,\n kind: symbol.kind,\n startLine: symbol.startLine ?? null,\n endLine: symbol.endLine ?? null,\n signature: symbol.signature ?? null,\n contentHash: symbol.contentHash ?? null,\n indexedAt: symbol.indexedAt,\n stale: symbol.stale ? 1 : 0,\n });\n }\n });\n tx(symbols);\n }\n\n upsertEdges(edges: CodeEdge[]): void {\n if (edges.length === 0) return;\n const stmt = this.db.prepare(`\n INSERT OR REPLACE INTO code_edges\n (id, projectId, fromSymbolId, toSymbolId, fromFileId, toFileId, type, confidence, evidence, indexedAt)\n VALUES\n (@id, @projectId, @fromSymbolId, @toSymbolId, @fromFileId, @toFileId, @type, @confidence, @evidence, @indexedAt)\n `);\n const tx = this.db.transaction((items: CodeEdge[]) => {\n for (const edge of items) {\n stmt.run({\n id: edge.id,\n projectId: edge.projectId,\n fromSymbolId: edge.fromSymbolId ?? null,\n toSymbolId: edge.toSymbolId ?? null,\n fromFileId: edge.fromFileId ?? null,\n toFileId: edge.toFileId ?? null,\n type: edge.type,\n confidence: edge.confidence,\n evidence: edge.evidence ?? null,\n indexedAt: edge.indexedAt,\n });\n }\n });\n tx(edges);\n }\n\n replaceProjectIndex(\n projectId: string,\n index: { files: CodeFile[]; symbols: CodeSymbol[]; edges: CodeEdge[] },\n ): void {\n const deleteEdges = this.db.prepare(`DELETE FROM code_edges WHERE projectId = ?`);\n const staleSymbols = this.db.prepare(`UPDATE code_symbols SET stale = 1 WHERE projectId = ?`);\n const deleteFiles = this.db.prepare(`DELETE FROM code_files WHERE projectId = ?`);\n const insertFile = this.db.prepare(`\n INSERT OR REPLACE INTO code_files\n (id, projectId, path, language, contentHash, mtimeMs, sizeBytes, indexedAt, gitCommit)\n VALUES\n (@id, @projectId, @path, @language, @contentHash, @mtimeMs, @sizeBytes, @indexedAt, @gitCommit)\n `);\n const insertSymbol = this.db.prepare(`\n INSERT OR REPLACE INTO code_symbols\n (id, projectId, fileId, path, name, qualifiedName, kind, startLine, endLine, signature, contentHash, indexedAt, stale)\n VALUES\n (@id, @projectId, @fileId, @path, @name, @qualifiedName, @kind, @startLine, @endLine, @signature, @contentHash, @indexedAt, @stale)\n `);\n const insertEdge = this.db.prepare(`\n INSERT OR REPLACE INTO code_edges\n (id, projectId, fromSymbolId, toSymbolId, fromFileId, toFileId, type, confidence, evidence, indexedAt)\n VALUES\n (@id, @projectId, @fromSymbolId, @toSymbolId, @fromFileId, @toFileId, @type, @confidence, @evidence, @indexedAt)\n `);\n\n const tx = this.db.transaction(() => {\n deleteEdges.run(projectId);\n staleSymbols.run(projectId);\n deleteFiles.run(projectId);\n\n for (const file of index.files) {\n insertFile.run({\n id: file.id,\n projectId: file.projectId,\n path: normalizeCodePath(file.path),\n language: file.language ?? null,\n contentHash: file.contentHash,\n mtimeMs: file.mtimeMs ?? null,\n sizeBytes: file.sizeBytes ?? null,\n indexedAt: file.indexedAt,\n gitCommit: file.gitCommit ?? null,\n });\n }\n\n for (const symbol of index.symbols) {\n insertSymbol.run({\n id: symbol.id,\n projectId: symbol.projectId,\n fileId: symbol.fileId,\n path: normalizeCodePath(symbol.path),\n name: symbol.name,\n qualifiedName: symbol.qualifiedName,\n kind: symbol.kind,\n startLine: symbol.startLine ?? null,\n endLine: symbol.endLine ?? null,\n signature: symbol.signature ?? null,\n contentHash: symbol.contentHash ?? null,\n indexedAt: symbol.indexedAt,\n stale: 0,\n });\n }\n\n for (const edge of index.edges) {\n insertEdge.run({\n id: edge.id,\n projectId: edge.projectId,\n fromSymbolId: edge.fromSymbolId ?? null,\n toSymbolId: edge.toSymbolId ?? null,\n fromFileId: edge.fromFileId ?? null,\n toFileId: edge.toFileId ?? null,\n type: edge.type,\n confidence: edge.confidence,\n evidence: edge.evidence ?? null,\n indexedAt: edge.indexedAt,\n });\n }\n });\n\n tx();\n }\n\n /**\n * Reconcile only files whose source changed plus files that disappeared.\n * Refs tied to replaced sources become stale instead of being silently kept.\n */\n applyFileDeltas(\n projectId: string,\n input: {\n changed: CodeGraphFileDelta[];\n metadataOnly?: CodeFile[];\n removedFileIds?: string[];\n },\n ): void {\n const changed = input.changed.filter((delta) => delta.file.projectId === projectId);\n const metadataOnly = (input.metadataOnly ?? []).filter((file) => file.projectId === projectId);\n const removedFileIds = input.removedFileIds ?? [];\n if (changed.length === 0 && metadataOnly.length === 0 && removedFileIds.length === 0) return;\n\n const staleRefsForFile = this.db.prepare(`\n UPDATE observation_code_refs\n SET status = 'stale', updatedAt = ?\n WHERE projectId = ? AND (\n fileId = ? OR symbolId IN (\n SELECT id FROM code_symbols WHERE projectId = ? AND fileId = ?\n )\n )\n `);\n const deleteEdgesForFile = this.db.prepare(`\n DELETE FROM code_edges\n WHERE projectId = ? AND (fromFileId = ? OR toFileId = ?)\n `);\n const deleteSymbolsForFile = this.db.prepare(`DELETE FROM code_symbols WHERE projectId = ? AND fileId = ?`);\n const deleteFile = this.db.prepare(`DELETE FROM code_files WHERE projectId = ? AND id = ?`);\n const upsertFile = this.db.prepare(`\n INSERT OR REPLACE INTO code_files\n (id, projectId, path, language, contentHash, mtimeMs, sizeBytes, indexedAt, gitCommit)\n VALUES\n (@id, @projectId, @path, @language, @contentHash, @mtimeMs, @sizeBytes, @indexedAt, @gitCommit)\n `);\n const upsertSymbol = this.db.prepare(`\n INSERT OR REPLACE INTO code_symbols\n (id, projectId, fileId, path, name, qualifiedName, kind, startLine, endLine, signature, contentHash, indexedAt, stale)\n VALUES\n (@id, @projectId, @fileId, @path, @name, @qualifiedName, @kind, @startLine, @endLine, @signature, @contentHash, @indexedAt, @stale)\n `);\n const upsertEdge = this.db.prepare(`\n INSERT OR REPLACE INTO code_edges\n (id, projectId, fromSymbolId, toSymbolId, fromFileId, toFileId, type, confidence, evidence, indexedAt)\n VALUES\n (@id, @projectId, @fromSymbolId, @toSymbolId, @fromFileId, @toFileId, @type, @confidence, @evidence, @indexedAt)\n `);\n const writeFile = (file: CodeFile) => upsertFile.run({\n id: file.id,\n projectId: file.projectId,\n path: normalizeCodePath(file.path),\n language: file.language ?? null,\n contentHash: file.contentHash,\n mtimeMs: file.mtimeMs ?? null,\n sizeBytes: file.sizeBytes ?? null,\n indexedAt: file.indexedAt,\n gitCommit: file.gitCommit ?? null,\n });\n\n const tx = this.db.transaction(() => {\n const staleAt = new Date().toISOString();\n for (const fileId of removedFileIds) {\n staleRefsForFile.run(staleAt, projectId, fileId, projectId, fileId);\n deleteEdgesForFile.run(projectId, fileId, fileId);\n deleteSymbolsForFile.run(projectId, fileId);\n deleteFile.run(projectId, fileId);\n }\n\n for (const delta of changed) {\n const fileId = delta.file.id;\n staleRefsForFile.run(staleAt, projectId, fileId, projectId, fileId);\n deleteEdgesForFile.run(projectId, fileId, fileId);\n deleteSymbolsForFile.run(projectId, fileId);\n writeFile(delta.file);\n\n for (const symbol of delta.symbols) {\n upsertSymbol.run({\n id: symbol.id,\n projectId: symbol.projectId,\n fileId: symbol.fileId,\n path: normalizeCodePath(symbol.path),\n name: symbol.name,\n qualifiedName: symbol.qualifiedName,\n kind: symbol.kind,\n startLine: symbol.startLine ?? null,\n endLine: symbol.endLine ?? null,\n signature: symbol.signature ?? null,\n contentHash: symbol.contentHash ?? null,\n indexedAt: symbol.indexedAt,\n stale: symbol.stale ? 1 : 0,\n });\n }\n\n for (const edge of delta.edges) {\n upsertEdge.run({\n id: edge.id,\n projectId: edge.projectId,\n fromSymbolId: edge.fromSymbolId ?? null,\n toSymbolId: edge.toSymbolId ?? null,\n fromFileId: edge.fromFileId ?? null,\n toFileId: edge.toFileId ?? null,\n type: edge.type,\n confidence: edge.confidence,\n evidence: edge.evidence ?? null,\n indexedAt: edge.indexedAt,\n });\n }\n }\n\n for (const file of metadataOnly) writeFile(file);\n });\n tx();\n }\n\n upsertObservationRefs(refs: ObservationCodeRef[]): void {\n if (refs.length === 0) return;\n const stmt = this.db.prepare(`\n INSERT OR REPLACE INTO observation_code_refs\n (id, projectId, observationId, fileId, symbolId, capturedFileHash, capturedSymbolHash, status, reason, createdAt, updatedAt, snapshotId)\n VALUES\n (@id, @projectId, @observationId, @fileId, @symbolId, @capturedFileHash, @capturedSymbolHash, @status, @reason, @createdAt, @updatedAt, @snapshotId)\n `);\n const tx = this.db.transaction((items: ObservationCodeRef[]) => {\n for (const ref of items) {\n stmt.run({\n id: ref.id,\n projectId: ref.projectId,\n observationId: ref.observationId,\n fileId: ref.fileId ?? null,\n symbolId: ref.symbolId ?? null,\n capturedFileHash: ref.capturedFileHash ?? null,\n capturedSymbolHash: ref.capturedSymbolHash ?? null,\n status: ref.status,\n reason: ref.reason ?? null,\n createdAt: ref.createdAt,\n updatedAt: ref.updatedAt ?? null,\n snapshotId: ref.snapshotId ?? this.latestSnapshot(ref.projectId)?.id ?? null,\n });\n }\n });\n tx(refs);\n }\n\n replaceObservationRefs(projectId: string, observationId: number, refs: ObservationCodeRef[]): void {\n const deleteRefs = this.db.prepare(`\n DELETE FROM observation_code_refs\n WHERE projectId = ? AND observationId = ?\n `);\n const insertRef = this.db.prepare(`\n INSERT OR REPLACE INTO observation_code_refs\n (id, projectId, observationId, fileId, symbolId, capturedFileHash, capturedSymbolHash, status, reason, createdAt, updatedAt, snapshotId)\n VALUES\n (@id, @projectId, @observationId, @fileId, @symbolId, @capturedFileHash, @capturedSymbolHash, @status, @reason, @createdAt, @updatedAt, @snapshotId)\n `);\n const tx = this.db.transaction(() => {\n deleteRefs.run(projectId, observationId);\n for (const ref of refs) {\n insertRef.run({\n id: ref.id,\n projectId: ref.projectId,\n observationId: ref.observationId,\n fileId: ref.fileId ?? null,\n symbolId: ref.symbolId ?? null,\n capturedFileHash: ref.capturedFileHash ?? null,\n capturedSymbolHash: ref.capturedSymbolHash ?? null,\n status: ref.status,\n reason: ref.reason ?? null,\n createdAt: ref.createdAt,\n updatedAt: ref.updatedAt ?? null,\n snapshotId: ref.snapshotId ?? this.latestSnapshot(ref.projectId)?.id ?? null,\n });\n }\n });\n tx();\n }\n\n getFile(projectId: string, path: string): CodeFile | null {\n const row = this.db.prepare(`SELECT * FROM code_files WHERE projectId = ? AND path = ?`).get(projectId, normalizeCodePath(path));\n return row ? rowToFile(row) : null;\n }\n\n listFiles(projectId: string): CodeFile[] {\n return this.db.prepare(`SELECT * FROM code_files WHERE projectId = ? ORDER BY path`).all(projectId).map(rowToFile);\n }\n\n findSymbols(projectId: string, query: string, limit = 20): CodeSymbol[] {\n const like = `%${query.trim()}%`;\n return this.db.prepare(`\n SELECT * FROM code_symbols\n WHERE projectId = ? AND stale = 0 AND (name LIKE ? OR qualifiedName LIKE ? OR path LIKE ?)\n ORDER BY path, startLine\n LIMIT ?\n `).all(projectId, like, like, like, limit).map(rowToSymbol);\n }\n\n listSymbols(projectId: string): CodeSymbol[] {\n return this.db.prepare(`\n SELECT * FROM code_symbols\n WHERE projectId = ? AND stale = 0\n ORDER BY path, startLine\n `).all(projectId).map(rowToSymbol);\n }\n\n findSymbolsByNames(projectId: string, names: string[], fileIds: string[] = []): CodeSymbol[] {\n const candidates = [...new Set(names.map(name => name.trim()).filter(Boolean))];\n if (candidates.length === 0) return [];\n const candidateJson = JSON.stringify(candidates);\n const hintedFiles = [...new Set(fileIds.map(fileId => fileId.trim()).filter(Boolean))];\n if (hintedFiles.length > 0) {\n return this.db.prepare(`\n SELECT * FROM code_symbols\n WHERE projectId = ?\n AND stale = 0\n AND name IN (SELECT value FROM json_each(?))\n AND fileId IN (SELECT value FROM json_each(?))\n ORDER BY path, startLine\n `).all(projectId, candidateJson, JSON.stringify(hintedFiles)).map(rowToSymbol);\n }\n\n return this.db.prepare(`\n SELECT symbols.*\n FROM code_symbols AS symbols\n INNER JOIN (\n SELECT name\n FROM code_symbols\n WHERE projectId = ?\n AND stale = 0\n AND name IN (SELECT value FROM json_each(?))\n GROUP BY name\n HAVING COUNT(*) = 1\n ) AS unambiguous ON unambiguous.name = symbols.name\n WHERE symbols.projectId = ? AND symbols.stale = 0\n ORDER BY symbols.path, symbols.startLine\n `).all(projectId, candidateJson, projectId).map(rowToSymbol);\n }\n\n listSymbolsForFile(fileId: string): CodeSymbol[] {\n return this.db.prepare(`SELECT * FROM code_symbols WHERE fileId = ? AND stale = 0 ORDER BY startLine`).all(fileId).map(rowToSymbol);\n }\n\n listEdges(projectId: string): CodeEdge[] {\n return this.db.prepare(`SELECT * FROM code_edges WHERE projectId = ? ORDER BY type, id`).all(projectId).map(rowToEdge);\n }\n\n listObservationRefs(projectId: string, observationId: number): ObservationCodeRef[] {\n return this.db.prepare(`\n SELECT * FROM observation_code_refs\n WHERE projectId = ? AND observationId = ?\n ORDER BY status, id\n `).all(projectId, observationId).map(rowToRef);\n }\n\n listProjectObservationRefs(projectId: string): ObservationCodeRef[] {\n return this.db.prepare(`\n SELECT * FROM observation_code_refs\n WHERE projectId = ?\n ORDER BY observationId, status, id\n `).all(projectId).map(rowToRef);\n }\n\n listReferencedSymbols(projectId: string): CodeSymbol[] {\n return this.db.prepare(`\n SELECT DISTINCT symbols.*\n FROM code_symbols AS symbols\n INNER JOIN observation_code_refs AS refs ON refs.symbolId = symbols.id\n WHERE refs.projectId = ? AND symbols.projectId = ? AND symbols.stale = 0\n ORDER BY symbols.path, symbols.startLine\n `).all(projectId, projectId).map(rowToSymbol);\n }\n\n latestSnapshot(projectId: string): CodeStateSnapshot | undefined {\n const row = this.db.prepare(\n 'SELECT * FROM code_state_snapshots WHERE projectId = ? ORDER BY sourceEpoch DESC LIMIT 1',\n ).get(projectId);\n return row ? rowToSnapshot(row) : undefined;\n }\n\n listSnapshots(projectId: string, limit = 20): CodeStateSnapshot[] {\n const safeLimit = Number.isFinite(limit) ? Math.max(1, Math.min(200, Math.floor(limit))) : 20;\n return this.db.prepare(\n 'SELECT * FROM code_state_snapshots WHERE projectId = ? ORDER BY sourceEpoch DESC LIMIT ?',\n ).all(projectId, safeLimit).map(rowToSnapshot);\n }\n\n /**\n * Record a completed scan and mark all current structural facts with its\n * epoch. The snapshot is written only after refresh reconciliation succeeds,\n * so an interrupted scan cannot be advertised as complete.\n */\n recordCodeStateSnapshot(input: CodeStateSnapshotInput): CodeStateSnapshot {\n const id = randomUUID();\n let snapshot: CodeStateSnapshot | undefined;\n const tx = this.db.transaction(() => {\n const previous = this.db.prepare(\n 'SELECT id, sourceEpoch FROM code_state_snapshots WHERE projectId = ? ORDER BY sourceEpoch DESC LIMIT 1',\n ).get(input.projectId);\n const sourceEpoch = Number(previous?.sourceEpoch ?? 0) + 1;\n const previousSnapshotId = previous?.id as string | undefined;\n this.db.prepare(\n 'INSERT INTO code_state_snapshots (id, projectId, provider, baseRevision, worktreeFingerprint, worktreeState, changedPathCount, indexedAt, sourceEpoch, completenessJson, previousSnapshotId) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)',\n ).run(\n id,\n input.projectId,\n input.provider,\n input.baseRevision ?? null,\n input.worktreeFingerprint,\n input.worktreeState,\n input.changedPathCount,\n input.indexedAt,\n sourceEpoch,\n JSON.stringify(input.completeness),\n previousSnapshotId ?? null,\n );\n this.db.prepare(\n 'UPDATE code_files SET snapshotId = ?, sourceEpoch = ?, gitCommit = COALESCE(?, gitCommit) WHERE projectId = ?',\n ).run(id, sourceEpoch, input.baseRevision ?? null, input.projectId);\n this.db.prepare(\n 'UPDATE code_symbols SET snapshotId = ?, sourceEpoch = ? WHERE projectId = ? AND stale = 0',\n ).run(id, sourceEpoch, input.projectId);\n this.db.prepare(\n 'UPDATE code_edges SET snapshotId = ?, sourceEpoch = ? WHERE projectId = ?',\n ).run(id, sourceEpoch, input.projectId);\n this.db.prepare(\n \"UPDATE observation_code_refs SET snapshotId = ? WHERE projectId = ? AND status = 'current'\",\n ).run(id, input.projectId);\n snapshot = {\n ...input,\n id,\n sourceEpoch,\n ...(previousSnapshotId ? { previousSnapshotId } : {}),\n };\n });\n tx();\n return snapshot!;\n }\n\n status(projectId: string): CodeGraphStatus {\n const files = this.db.prepare(`SELECT COUNT(*) AS count FROM code_files WHERE projectId = ?`).get(projectId).count;\n const symbols = this.db.prepare(`SELECT COUNT(*) AS count FROM code_symbols WHERE projectId = ? AND stale = 0`).get(projectId).count;\n const edges = this.db.prepare(`SELECT COUNT(*) AS count FROM code_edges WHERE projectId = ?`).get(projectId).count;\n const refs = this.db.prepare(`SELECT COUNT(*) AS count FROM observation_code_refs WHERE projectId = ?`).get(projectId).count;\n const latest = this.db.prepare(`SELECT MAX(indexedAt) AS indexedAt FROM code_files WHERE projectId = ?`).get(projectId);\n const latestSnapshot = this.latestSnapshot(projectId);\n return {\n provider: 'lite',\n files,\n symbols,\n edges,\n refs,\n ...(latest?.indexedAt ? { indexedAt: latest.indexedAt } : {}),\n ...(latestSnapshot ? { latestSnapshot } : {}),\n };\n }\n}\n","import type { CodeFile, CodeSymbol, ObservationCodeRef } from './types.js';\nimport { makeObservationCodeRefId, normalizeCodePath } from './ids.js';\nimport type { CodeGraphStore } from './store.js';\n\nexport interface BindableObservation {\n id: number;\n projectId: string;\n title: string;\n narrative: string;\n facts?: string[];\n filesModified?: string[];\n createdAt: string;\n}\n\nexport interface CodeRefBackfillResult {\n observationsScanned: number;\n observationsBackfilled: number;\n refsBackfilled: number;\n}\n\nfunction observationText(obs: BindableObservation): string {\n return [obs.title, obs.narrative, ...(obs.facts ?? [])].join('\\n');\n}\n\nfunction mentionsSymbol(text: string, symbol: CodeSymbol): boolean {\n const name = symbol.name.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n return new RegExp(`(^|[^\\\\w$])${name}([^\\\\w$]|$)`).test(text);\n}\n\nfunction identifierCandidates(text: string): string[] {\n return [...new Set(text.match(/[A-Za-z_$][\\w$]*(?:::[A-Za-z_$][\\w$]*)*[!?=]?/g) ?? [])];\n}\n\nfunction codeIdentifierCandidates(text: string): string[] {\n const explicit = new Set<string>();\n for (const match of text.matchAll(/`([A-Za-z_$][\\w$]*(?:::[A-Za-z_$][\\w$]*)*[!?=]?)`/g)) explicit.add(match[1]);\n for (const match of text.matchAll(/\\b([A-Za-z_$][\\w$]*(?:::[A-Za-z_$][\\w$]*)*[!?=]?)\\s*\\(/g)) explicit.add(match[1]);\n return identifierCandidates(text).filter(candidate =>\n explicit.has(candidate) ||\n candidate.includes('::') ||\n /[!?=]$/.test(candidate) ||\n /^[A-Z]/.test(candidate) ||\n /[_$]/.test(candidate) ||\n /[a-z0-9][A-Z]/.test(candidate) ||\n /[A-Z]{2}/.test(candidate));\n}\n\nfunction fileRef(projectId: string, obs: BindableObservation, file: CodeFile): ObservationCodeRef {\n return {\n id: makeObservationCodeRefId(projectId, obs.id, file.id),\n projectId,\n observationId: obs.id,\n fileId: file.id,\n capturedFileHash: file.contentHash,\n status: 'current',\n reason: 'bound by file path',\n createdAt: obs.createdAt,\n };\n}\n\nfunction symbolRef(projectId: string, obs: BindableObservation, file: CodeFile, symbol: CodeSymbol): ObservationCodeRef {\n return {\n id: makeObservationCodeRefId(projectId, obs.id, file.id, symbol.id),\n projectId,\n observationId: obs.id,\n fileId: file.id,\n symbolId: symbol.id,\n capturedFileHash: file.contentHash,\n ...(symbol.contentHash ? { capturedSymbolHash: symbol.contentHash } : {}),\n status: 'current',\n reason: 'bound by symbol mention',\n createdAt: obs.createdAt,\n };\n}\n\ninterface CodeBindingLookup {\n findFile(path: string): CodeFile | undefined;\n findSymbols(names: string[], hintedFileIds: string[]): CodeSymbol[];\n}\n\nfunction resolveObservationCodeRefs(\n obs: BindableObservation,\n lookup: CodeBindingLookup,\n): ObservationCodeRef[] {\n const refs = new Map<string, ObservationCodeRef>();\n const text = observationText(obs);\n const candidateFiles = new Map<string, CodeFile>();\n\n for (const rawPath of obs.filesModified ?? []) {\n const file = lookup.findFile(normalizeCodePath(rawPath));\n if (!file) continue;\n candidateFiles.set(file.id, file);\n const ref = fileRef(obs.projectId, obs, file);\n refs.set(ref.id, ref);\n }\n\n const hintedFileIds = new Set(candidateFiles.keys());\n const symbolNames = hintedFileIds.size > 0 ? identifierCandidates(text) : codeIdentifierCandidates(text);\n const symbols = lookup.findSymbols(symbolNames, [...hintedFileIds]);\n const symbolsByName = new Map<string, CodeSymbol[]>();\n for (const symbol of symbols) {\n const group = symbolsByName.get(symbol.name) ?? [];\n group.push(symbol);\n symbolsByName.set(symbol.name, group);\n }\n\n for (const group of symbolsByName.values()) {\n const candidates = group.length === 1 ? group : [];\n for (const symbol of candidates) {\n if (!mentionsSymbol(text, symbol)) continue;\n const file = candidateFiles.get(symbol.fileId) ?? lookup.findFile(symbol.path);\n if (!file) continue;\n candidateFiles.set(file.id, file);\n const ref = symbolRef(obs.projectId, obs, file, symbol);\n refs.set(ref.id, ref);\n }\n }\n\n return [...refs.values()];\n}\n\nfunction createStoreLookup(store: CodeGraphStore, projectId: string): CodeBindingLookup {\n return {\n findFile: path => store.getFile(projectId, path) ?? undefined,\n findSymbols: (names, hintedFileIds) => store.findSymbolsByNames(projectId, names, hintedFileIds),\n };\n}\n\nfunction createSnapshotLookup(files: CodeFile[], symbols: CodeSymbol[]): CodeBindingLookup {\n const filesByPath = new Map(files.map(file => [normalizeCodePath(file.path), file]));\n const symbolsByName = new Map<string, CodeSymbol[]>();\n for (const symbol of symbols) {\n const group = symbolsByName.get(symbol.name) ?? [];\n group.push(symbol);\n symbolsByName.set(symbol.name, group);\n }\n\n return {\n findFile: path => filesByPath.get(normalizeCodePath(path)),\n findSymbols: (names, hintedFileIds) => {\n const hinted = new Set(hintedFileIds);\n const found: CodeSymbol[] = [];\n for (const name of names) {\n const candidates = symbolsByName.get(name) ?? [];\n found.push(...(hinted.size > 0 ? candidates.filter(symbol => hinted.has(symbol.fileId)) : candidates));\n }\n return found;\n },\n };\n}\n\nexport async function bindObservationToCode(\n store: CodeGraphStore,\n obs: BindableObservation,\n): Promise<ObservationCodeRef[]> {\n const refs = resolveObservationCodeRefs(obs, createStoreLookup(store, obs.projectId));\n store.replaceObservationRefs(obs.projectId, obs.id, refs);\n return refs;\n}\n\nexport async function backfillMissingObservationCodeRefs(\n store: CodeGraphStore,\n observations: BindableObservation[],\n): Promise<CodeRefBackfillResult> {\n let observationsBackfilled = 0;\n let refsBackfilled = 0;\n const boundObservationIdsByProject = new Map<string, Set<number>>();\n const lookupByProject = new Map<string, CodeBindingLookup>();\n\n for (const projectId of new Set(observations.map(observation => observation.projectId))) {\n boundObservationIdsByProject.set(\n projectId,\n new Set(store.listProjectObservationRefs(projectId).map(ref => ref.observationId)),\n );\n lookupByProject.set(\n projectId,\n createSnapshotLookup(store.listFiles(projectId), store.listSymbols(projectId)),\n );\n }\n\n const refsToInsert: ObservationCodeRef[] = [];\n for (const observation of observations) {\n if (boundObservationIdsByProject.get(observation.projectId)?.has(observation.id)) continue;\n if ((observation.filesModified?.length ?? 0) === 0 && codeIdentifierCandidates(observationText(observation)).length === 0) {\n continue;\n }\n const lookup = lookupByProject.get(observation.projectId);\n if (!lookup) continue;\n const refs = resolveObservationCodeRefs(observation, lookup);\n if (refs.length === 0) continue;\n observationsBackfilled += 1;\n refsBackfilled += refs.length;\n refsToInsert.push(...refs);\n }\n store.upsertObservationRefs(refsToInsert);\n\n return {\n observationsScanned: observations.length,\n observationsBackfilled,\n refsBackfilled,\n };\n}\n","/**\n * Observations Manager\n *\n * Manages rich observation records with auto-classification and token counting.\n * Source: claude-mem's observation data model with structured fields.\n *\n * Each observation is stored both in the knowledge graph (as entity observation)\n * and in the Orama search index (for full-text + vector search).\n */\n\nimport type {\n Observation,\n ObservationAdmissionState,\n ObservationReader,\n ObservationVisibility,\n ObservationType,\n ObservationStatus,\n MemorixDocument,\n ProgressInfo,\n} from '../types.js';\nimport { TOPIC_KEY_FAMILIES } from '../types.js';\nimport {\n insertObservation,\n removeObservation,\n resetDb,\n generateEmbedding,\n batchGenerateEmbeddings,\n getDb,\n getDeferredCachedVectorHydration,\n getVectorDimensions,\n hydrateIndexForStartup,\n hasObservationVector,\n isEmbeddingEnabled,\n makeOramaObservationId,\n getLastSearchMode,\n searchObservations,\n updateObservationMetadata,\n} from '../store/orama-store.js';\nimport { getObservationStore, initObservationStore } from '../store/obs-store.js';\nimport { countTextTokens } from '../compact/token-budget.js';\nimport { extractEntities, enrichConcepts } from './entity-extractor.js';\nimport { getEmbeddingProvider, isEmbeddingExplicitlyDisabled } from '../embedding/provider.js';\nimport { sanitizeCredentials } from './secret-filter.js';\nimport { enqueueClaimDerivation, enqueueObservationQualification } from '../runtime/lifecycle.js';\nimport { canManageObservation, resolveObservationVisibility } from './visibility.js';\n\n/** In-memory observation list (loaded from persistence on init) */\nlet observations: Observation[] = [];\nlet nextId = 1;\nlet projectDir: string | null = null;\nlet searchIndexPrepared = false;\n\n// ── Vector-missing tracking ──────────────────────────────────────\n// Tracks observation IDs whose async embedding write failed or was skipped.\n// Enables observability (\"how many memories lack vectors?\") and backfill.\nconst vectorMissingIds = new Set<number>();\nlet vectorBackfillRunning = false;\nlet vectorSchemaUpgradePromise: Promise<boolean> | null = null;\nlet lastVectorBackfill: {\n attempted: number;\n succeeded: number;\n failed: number;\n lastError?: string;\n finishedAt: string;\n} | null = null;\nconst embeddingFailureLogTimestamps = new Map<string, number>();\nconst EMBEDDING_FAILURE_LOG_COOLDOWN_MS = 30_000;\n\nfunction logEmbeddingFailureOnce(key: string, message: string): void {\n const now = Date.now();\n const last = embeddingFailureLogTimestamps.get(key) ?? 0;\n if (now - last < EMBEDDING_FAILURE_LOG_COOLDOWN_MS) return;\n embeddingFailureLogTimestamps.set(key, now);\n console.error(message);\n}\n\nfunction normalizeEmbeddingFailure(error: unknown): { key: string; message: string } {\n const raw = error instanceof Error ? error.message : String(error);\n\n if (\n /embedding api error \\(401\\)/i.test(raw) ||\n /invalid_api_key/i.test(raw) ||\n /incorrect api key/i.test(raw) ||\n /unauthorized/i.test(raw)\n ) {\n return {\n key: 'embedding-auth',\n message: 'Embedding API returned an invalid API key response; using BM25 until embedding recovers',\n };\n }\n\n if (/embedding api timeout/i.test(raw)) {\n return {\n key: 'embedding-timeout',\n message: 'Embedding API timed out; using BM25 until embedding recovers',\n };\n }\n\n return {\n key: raw,\n message: raw,\n };\n}\n\nfunction queueVectorBackfill(projectId: string): void {\n const dataDir = projectDir;\n if (!dataDir) return;\n void import('../runtime/maintenance-jobs.js')\n .then(({ MaintenanceJobStore }) => {\n new MaintenanceJobStore(dataDir).enqueue({\n projectId,\n kind: 'vector-backfill',\n dedupeKey: 'vector-backfill',\n payload: { limit: 12 },\n });\n })\n .catch(() => {\n // Memory writes remain durable even when the optional maintenance queue is unavailable.\n });\n}\n\nasync function bindObservationCodeRefsBestEffort(observation: Observation): Promise<void> {\n if (!projectDir) return;\n try {\n const { CodeGraphStore } = await import('../codegraph/store.js');\n const { bindObservationToCode } = await import('../codegraph/binder.js');\n const codeStore = new CodeGraphStore();\n await codeStore.init(projectDir);\n await bindObservationToCode(codeStore, observation);\n } catch {\n // Code refs enrich memory retrieval, but memory writes must remain durable without them.\n }\n}\n\nfunction queueClaimDerivation(observation: Observation): void {\n const dataDir = projectDir;\n const isExplicit = observation.sourceDetail === 'explicit';\n const isGit = observation.source === 'git' || observation.sourceDetail === 'git-ingest';\n if (!dataDir || (!isExplicit && !isGit)) return;\n try {\n enqueueClaimDerivation({\n dataDir,\n projectId: observation.projectId,\n observationId: observation.id,\n });\n } catch {\n // The observation remains durable; a later scan can recover its claim.\n }\n}\n\nfunction queueObservationQualification(observation: Observation): void {\n const dataDir = projectDir;\n if (!dataDir || observation.admissionState !== 'candidate') return;\n try {\n enqueueObservationQualification({\n dataDir,\n projectId: observation.projectId,\n source: 'automatic-capture:' + observation.id,\n });\n } catch {\n // Candidate evidence remains available for a later qualification scan.\n }\n}\n\nfunction isVectorCompatibleWithCurrentIndex(embedding: number[] | null): boolean {\n if (!embedding) return false;\n const vectorDimensions = getVectorDimensions();\n return vectorDimensions !== null &&\n embedding.length === vectorDimensions &&\n embedding.every(Number.isFinite);\n}\n\n/**\n * A cache-less API startup deliberately creates a lexical index so MCP can\n * answer immediately. Once the background lane obtains its first vector, the\n * in-memory index must be rebuilt with a vector field in this same process.\n */\nasync function upgradeVectorSchemaAfterFirstEmbedding(embedding: number[]): Promise<boolean> {\n if (isVectorCompatibleWithCurrentIndex(embedding)) return true;\n if (getVectorDimensions() !== null || !embedding.every(Number.isFinite)) return false;\n\n const targetProjectDir = projectDir;\n if (!vectorSchemaUpgradePromise) {\n vectorSchemaUpgradePromise = reindexObservations()\n .then(() => projectDir === targetProjectDir && isVectorCompatibleWithCurrentIndex(embedding))\n .catch(() => false)\n .finally(() => {\n vectorSchemaUpgradePromise = null;\n });\n }\n return vectorSchemaUpgradePromise;\n}\n\n/**\n * Initialize the observations manager with a project directory.\n * Auto-initializes the ObservationStore if not already set.\n */\nexport async function initObservations(dir: string): Promise<void> {\n if (projectDir === dir) return;\n await initObservationStore(dir);\n const store = getObservationStore();\n observations = await store.loadAll();\n nextId = await store.loadIdCounter();\n projectDir = dir;\n searchIndexPrepared = false;\n vectorSchemaUpgradePromise = null;\n}\n\n/**\n * Check cross-process freshness and reload if another process has written.\n *\n * Call this at every read boundary (MCP tool handler, dashboard API, etc.)\n * BEFORE reading observations[] via getObservation / getAllObservations /\n * getProjectObservations / getObservationCount.\n *\n * When the SQLite storage_generation has advanced beyond our local snapshot:\n * 1. Reloads observations[] from the store\n * 2. Updates nextId from the store\n * 3. Rebuilds the Orama search index (so vector + BM25 search stay in sync)\n *\n * For DegradedBackend this is a no-op (always returns false).\n */\nexport async function ensureFreshObservations(): Promise<boolean> {\n if (!projectDir) return false;\n try {\n const store = getObservationStore();\n const wasStale = await store.ensureFresh();\n if (wasStale) {\n observations = await store.loadAll();\n nextId = await store.loadIdCounter();\n await reindexObservations();\n searchIndexPrepared = true;\n return true;\n }\n } catch {\n // Best-effort — don't crash the read path on freshness failure\n }\n return false;\n}\n\n/**\n * @internal Observation-only freshness gate.\n *\n * Public callers should use `withFreshIndex()` from freshness.ts instead,\n * which also covers mini-skills. This function remains for internal use\n * by the freshness module and legacy test code only.\n */\nexport async function withFreshObservations<T>(fn: () => T | Promise<T>): Promise<T> {\n await ensureFreshObservations();\n return fn();\n}\n\n/**\n * Store a new observation.\n *\n * This is the primary write API — called by the `memorix_store` MCP tool.\n * Automatically:\n * 1. Assigns an incremental ID\n * 2. Counts tokens for the observation content\n * 3. Inserts into Orama for full-text search\n * 4. Persists to disk\n */\nexport async function storeObservation(input: {\n entityName: string;\n type: ObservationType;\n title: string;\n narrative: string;\n facts?: string[];\n filesModified?: string[];\n concepts?: string[];\n projectId: string;\n topicKey?: string;\n sessionId?: string;\n progress?: ProgressInfo;\n source?: 'agent' | 'git' | 'manual';\n commitHash?: string;\n relatedCommits?: string[];\n relatedEntities?: string[];\n sourceDetail?: 'explicit' | 'hook' | 'git-ingest';\n valueCategory?: 'core' | 'contextual' | 'ephemeral';\n admissionState?: ObservationAdmissionState;\n admissionReason?: string;\n visibility?: ObservationVisibility;\n sharedWithAgentIds?: string[];\n createdByAgentId?: string;\n /** Optional caller-bound write scope for topic-key upserts. */\n visibilityReader?: ObservationReader;\n}): Promise<{ observation: Observation; upserted: boolean }> {\n const now = new Date().toISOString();\n\n // ── Central secret sanitization — strip credential values before any persistence ──\n // Covers all write paths: hooks, git-ingest, CLI, reasoning, compact-on-write, etc.\n input = { ...input, title: sanitizeCredentials(input.title), narrative: sanitizeCredentials(input.narrative), facts: input.facts?.map(sanitizeCredentials) };\n\n // Sync the local cache before using it as the topicKey fast path. This costs a\n // generation read in the normal case and only reloads when another process wrote.\n await ensureFreshObservations();\n\n // Topic key upsert: fast-path check in-memory (optimistic, may be stale).\n // A second authoritative check happens inside the file lock to prevent TOCTOU races\n // where two concurrent calls with the same topicKey both miss this check.\n if (input.topicKey) {\n const existing = observations.find(\n o => o.topicKey === input.topicKey && o.projectId === input.projectId,\n );\n if (existing) {\n if (input.visibilityReader && !canManageObservation(existing, input.visibilityReader)) {\n throw new Error('Cannot update a memory outside this session\\'s write scope.');\n }\n return { observation: await upsertObservation(existing, input, now), upserted: true };\n }\n }\n\n // ── Pre-compute enrichments (pure, no side-effects) ──\n const contentForExtraction = [input.title, input.narrative, ...(input.facts ?? [])].join(' ');\n const extracted = extractEntities(contentForExtraction);\n const enrichedConcepts = enrichConcepts(input.concepts ?? [], extracted);\n const userFiles = new Set((input.filesModified ?? []).map((f) => f.toLowerCase()));\n const enrichedFiles = [...(input.filesModified ?? [])];\n for (const f of extracted.files) {\n if (!userFiles.has(f.toLowerCase())) {\n enrichedFiles.push(f);\n }\n }\n const fullText = [\n input.title, input.narrative,\n ...(input.facts ?? []), ...enrichedFiles, ...enrichedConcepts,\n ].join(' ');\n const tokens = countTextTokens(fullText);\n\n // ── Atomic write: ID allocation + persist + in-memory push inside lock ──\n // This prevents concurrent calls from getting duplicate IDs or silently\n // losing observations due to stale in-memory state.\n let observation!: Observation;\n let doc!: MemorixDocument;\n\n let upsertedInsideLock = false;\n let reloadCacheAfterCommit = false;\n const assignAndPersist = async () => {\n if (projectDir) {\n const store = getObservationStore();\n const cachedGeneration = store.getGeneration();\n await store.atomic(async (tx) => {\n const transactionGeneration = await tx.getGeneration();\n const diskNextId = await tx.loadIdCounter();\n\n // A different writer committed after the cache freshness check but before\n // this transaction acquired its lock. Keep the cache coherent after commit.\n reloadCacheAfterCommit = transactionGeneration !== cachedGeneration;\n\n // ── Atomic topicKey re-check inside lock (prevents TOCTOU race) ──\n // Two concurrent calls with the same topicKey may both pass the fast-path\n // check above, but here we re-check against the authoritative disk state.\n if (input.topicKey) {\n const diskExisting = await tx.findByTopicKey(input.projectId, input.topicKey);\n if (diskExisting) {\n if (input.visibilityReader && !canManageObservation(diskExisting, input.visibilityReader)) {\n throw new Error('Cannot update a memory outside this session\\'s write scope.');\n }\n // Switch to upsert path — update the existing observation after this\n // short transaction has released its lock.\n upsertedInsideLock = true;\n observation = diskExisting;\n return; // Exit atomic — upsert will be handled after assignAndPersist\n }\n }\n\n // Use the higher of in-memory vs disk counter (handles multi-process)\n const id = Math.max(nextId, diskNextId);\n\n observation = {\n id,\n entityName: input.entityName,\n type: input.type,\n title: input.title,\n narrative: input.narrative,\n facts: input.facts ?? [],\n filesModified: enrichedFiles,\n concepts: enrichedConcepts,\n tokens,\n createdAt: now,\n projectId: input.projectId,\n hasCausalLanguage: extracted.hasCausalLanguage,\n topicKey: input.topicKey,\n revisionCount: 1,\n sessionId: input.sessionId,\n status: 'active',\n progress: input.progress,\n source: input.source,\n commitHash: input.commitHash,\n relatedCommits: input.relatedCommits,\n relatedEntities: input.relatedEntities,\n sourceDetail: input.sourceDetail,\n valueCategory: input.valueCategory,\n admissionState: input.admissionState,\n admissionReason: input.admissionReason ? sanitizeCredentials(input.admissionReason) : undefined,\n visibility: input.visibility ?? 'project',\n sharedWithAgentIds: input.sharedWithAgentIds,\n createdByAgentId: input.createdByAgentId,\n // Predict the generation that atomic() will commit after this callback.\n // bumpGeneration() runs after fn(tx) returns, incrementing by 1.\n writeGeneration: transactionGeneration + 1,\n };\n\n await tx.insert(observation);\n await tx.saveIdCounter(id + 1);\n });\n\n // Phase 4a: confirm writeGeneration matches actual post-bump value\n observation.writeGeneration = store.getGeneration();\n\n if (upsertedInsideLock || reloadCacheAfterCommit) {\n observations = await store.loadAll();\n nextId = await store.loadIdCounter();\n if (upsertedInsideLock) {\n observation = observations.find((candidate) => candidate.id === observation.id)\n ?? observation;\n }\n } else {\n observations.push(observation);\n nextId = observation.id + 1;\n }\n\n // If the atomic block detected a topicKey duplicate, skip Orama insert — upsert handles it\n if (upsertedInsideLock) return;\n } else {\n // No projectDir (e.g., tests) — just use in-memory counter\n const id = nextId++;\n observation = {\n id,\n entityName: input.entityName,\n type: input.type,\n title: input.title,\n narrative: input.narrative,\n facts: input.facts ?? [],\n filesModified: enrichedFiles,\n concepts: enrichedConcepts,\n tokens,\n createdAt: now,\n projectId: input.projectId,\n hasCausalLanguage: extracted.hasCausalLanguage,\n topicKey: input.topicKey,\n revisionCount: 1,\n sessionId: input.sessionId,\n status: 'active',\n progress: input.progress,\n source: input.source,\n commitHash: input.commitHash,\n relatedCommits: input.relatedCommits,\n relatedEntities: input.relatedEntities,\n sourceDetail: input.sourceDetail,\n valueCategory: input.valueCategory,\n admissionState: input.admissionState,\n admissionReason: input.admissionReason ? sanitizeCredentials(input.admissionReason) : undefined,\n visibility: input.visibility ?? 'project',\n sharedWithAgentIds: input.sharedWithAgentIds,\n createdByAgentId: input.createdByAgentId,\n writeGeneration: 0,\n };\n observations.push(observation);\n }\n\n // Build Orama doc AFTER id is assigned\n doc = {\n id: makeOramaObservationId(input.projectId, observation.id),\n observationId: observation.id,\n entityName: input.entityName,\n type: input.type,\n title: input.title,\n narrative: input.narrative,\n facts: (input.facts ?? []).join('\\n'),\n filesModified: enrichedFiles.join('\\n'),\n concepts: enrichedConcepts.map(c => c.replace(/-/g, ' ')).join(', '),\n tokens,\n createdAt: now,\n projectId: input.projectId,\n accessCount: 0,\n lastAccessedAt: '',\n status: 'active',\n source: input.source ?? 'agent',\n sourceDetail: input.sourceDetail ?? '',\n valueCategory: input.valueCategory ?? '',\n admissionState: input.admissionState ?? '',\n admissionReason: input.admissionReason ? sanitizeCredentials(input.admissionReason) : '',\n visibility: input.visibility ?? 'project',\n createdByAgentId: input.createdByAgentId ?? '',\n sharedWithAgentIds: JSON.stringify(input.sharedWithAgentIds ?? []),\n };\n\n await insertObservation(doc);\n };\n\n await assignAndPersist();\n\n // If the lock discovered a topicKey duplicate on disk, delegate to upsert\n if (upsertedInsideLock) {\n return { observation: await upsertObservation(observation, input, now), upserted: true };\n }\n\n await bindObservationCodeRefsBestEffort(observation);\n queueObservationQualification(observation);\n if (resolveObservationVisibility(observation) === 'project') {\n queueClaimDerivation(observation);\n }\n\n // Generate embedding async (fire-and-forget) — never blocks MCP response\n // Track in vectorMissingIds until embedding is successfully written.\n const obsId = observation.id;\n vectorMissingIds.add(obsId);\n const searchableText = [input.title, input.narrative, ...(input.facts ?? [])].join(' ');\n generateEmbedding(searchableText).then(async (embedding) => {\n if (embedding) {\n if (!isVectorCompatibleWithCurrentIndex(embedding)) {\n await upgradeVectorSchemaAfterFirstEmbedding(embedding);\n }\n if (!isVectorCompatibleWithCurrentIndex(embedding)) {\n const vectorDimensions = getVectorDimensions();\n console.error(\n `[memorix] Embedding dimension mismatch for obs-${obsId}: provider returned ${embedding.length}d, index expects ${vectorDimensions ?? 'unknown'}d (kept in backfill queue)`,\n );\n queueVectorBackfill(input.projectId);\n return;\n }\n try {\n const { removeObservation: removeObs } = await import('../store/orama-store.js');\n await removeObs(makeOramaObservationId(input.projectId, obsId));\n await insertObservation(Object.assign({}, doc, { embedding }));\n vectorMissingIds.delete(obsId);\n } catch {\n console.error(`[memorix] Embedding index update failed for obs-${obsId} (kept in backfill queue)`);\n queueVectorBackfill(input.projectId);\n }\n } else if (isEmbeddingExplicitlyDisabled()) {\n vectorMissingIds.delete(obsId);\n } else {\n queueVectorBackfill(input.projectId);\n logEmbeddingFailureOnce(\n 'provider-unavailable',\n `[memorix] Embedding provider unavailable (using BM25 until embedding recovers; queued obs-${obsId} for retry)`,\n );\n }\n }).catch((err) => {\n queueVectorBackfill(input.projectId);\n const failure = normalizeEmbeddingFailure(err);\n logEmbeddingFailureOnce(\n failure.key,\n `[memorix] Async embedding failed (using BM25 until embedding recovers; queued obs-${obsId} for retry): ${failure.message}`,\n );\n });\n\n return { observation, upserted: false };\n}\n\n/**\n * Update an existing observation via topic key upsert.\n * Replaces content but preserves the original ID and createdAt.\n */\nasync function upsertObservation(\n existing: Observation,\n input: {\n entityName: string;\n type: ObservationType;\n title: string;\n narrative: string;\n facts?: string[];\n filesModified?: string[];\n concepts?: string[];\n projectId: string;\n topicKey?: string;\n sessionId?: string;\n progress?: ProgressInfo;\n sourceDetail?: 'explicit' | 'hook' | 'git-ingest';\n valueCategory?: 'core' | 'contextual' | 'ephemeral';\n admissionState?: ObservationAdmissionState;\n admissionReason?: string;\n visibility?: ObservationVisibility;\n sharedWithAgentIds?: string[];\n },\n now: string,\n): Promise<Observation> {\n // ── Central secret sanitization ──\n input = { ...input, title: sanitizeCredentials(input.title), narrative: sanitizeCredentials(input.narrative), facts: input.facts?.map(sanitizeCredentials) };\n\n // Auto-extract and enrich (same as storeObservation)\n const contentForExtraction = [input.title, input.narrative, ...(input.facts ?? [])].join(' ');\n const extracted = extractEntities(contentForExtraction);\n const enrichedConcepts = enrichConcepts(input.concepts ?? [], extracted);\n const userFiles = new Set((input.filesModified ?? []).map((f) => f.toLowerCase()));\n const enrichedFiles = [...(input.filesModified ?? [])];\n for (const f of extracted.files) {\n if (!userFiles.has(f.toLowerCase())) enrichedFiles.push(f);\n }\n const fullText = [input.title, input.narrative, ...(input.facts ?? []), ...enrichedFiles, ...enrichedConcepts].join(' ');\n const tokens = countTextTokens(fullText);\n\n // Mark old observation as resolved (superseded by new version)\n // Note: topicKey upsert replaces in-place, so we just bump revision\n\n // Update in-place\n existing.entityName = input.entityName;\n existing.type = input.type;\n existing.title = input.title;\n existing.narrative = input.narrative;\n existing.facts = input.facts ?? [];\n existing.filesModified = enrichedFiles;\n existing.concepts = enrichedConcepts;\n existing.tokens = tokens;\n existing.updatedAt = now;\n existing.hasCausalLanguage = extracted.hasCausalLanguage;\n existing.revisionCount = (existing.revisionCount ?? 1) + 1;\n existing.status = 'active';\n if (input.sessionId) existing.sessionId = input.sessionId;\n if (input.progress) existing.progress = input.progress;\n if (input.sourceDetail !== undefined) existing.sourceDetail = input.sourceDetail;\n if (input.valueCategory !== undefined) existing.valueCategory = input.valueCategory;\n if (input.admissionState !== undefined) existing.admissionState = input.admissionState;\n if (input.admissionReason !== undefined) existing.admissionReason = sanitizeCredentials(input.admissionReason);\n if (input.visibility !== undefined) existing.visibility = input.visibility;\n if (input.sharedWithAgentIds !== undefined) existing.sharedWithAgentIds = input.sharedWithAgentIds;\n\n // Re-index in Orama WITHOUT embedding first (non-blocking)\n const doc: MemorixDocument = {\n id: makeOramaObservationId(existing.projectId, existing.id),\n observationId: existing.id,\n entityName: existing.entityName,\n type: existing.type,\n title: existing.title,\n narrative: existing.narrative,\n facts: existing.facts.join('\\n'),\n filesModified: enrichedFiles.join('\\n'),\n concepts: enrichedConcepts.map(c => c.replace(/-/g, ' ')).join(', '),\n tokens,\n createdAt: existing.createdAt,\n projectId: existing.projectId,\n accessCount: 0,\n lastAccessedAt: '',\n status: 'active',\n source: existing.source ?? 'agent',\n sourceDetail: existing.sourceDetail ?? '',\n valueCategory: existing.valueCategory ?? '',\n admissionState: existing.admissionState ?? '',\n admissionReason: existing.admissionReason ?? '',\n visibility: existing.visibility ?? 'project',\n createdByAgentId: existing.createdByAgentId ?? '',\n sharedWithAgentIds: JSON.stringify(existing.sharedWithAgentIds ?? []),\n };\n\n // Remove old doc and insert updated one (with retry for concurrent upsert race)\n const oramaId = makeOramaObservationId(existing.projectId, existing.id);\n try {\n const { removeObservation } = await import('../store/orama-store.js');\n await removeObservation(oramaId);\n } catch { /* may not exist in index */ }\n try {\n await insertObservation(doc);\n } catch {\n // Concurrent upsert may have already re-inserted — retry remove+insert once\n try {\n const { removeObservation: removeObs } = await import('../store/orama-store.js');\n await removeObs(oramaId);\n await insertObservation(doc);\n } catch { /* best effort — file persistence is the source of truth */ }\n }\n\n // Persist via ObservationStore\n if (projectDir) {\n const store = getObservationStore();\n await store.update(existing);\n }\n\n await bindObservationCodeRefsBestEffort(existing);\n queueObservationQualification(existing);\n if (resolveObservationVisibility(existing) === 'project') {\n queueClaimDerivation(existing);\n }\n\n // Generate embedding async (fire-and-forget) — never blocks MCP response\n const searchableText = [input.title, input.narrative, ...(input.facts ?? [])].join(' ');\n const obsId = existing.id;\n vectorMissingIds.add(obsId);\n generateEmbedding(searchableText).then(async (embedding) => {\n if (embedding) {\n if (!isVectorCompatibleWithCurrentIndex(embedding)) {\n await upgradeVectorSchemaAfterFirstEmbedding(embedding);\n }\n if (!isVectorCompatibleWithCurrentIndex(embedding)) {\n queueVectorBackfill(existing.projectId);\n return;\n }\n try {\n const { removeObservation: removeObs } = await import('../store/orama-store.js');\n await removeObs(makeOramaObservationId(existing.projectId, obsId));\n await insertObservation(Object.assign({}, doc, { embedding }));\n vectorMissingIds.delete(obsId);\n } catch {\n // Embedding index update failed — observation still persisted without vector\n queueVectorBackfill(existing.projectId);\n }\n } else if (isEmbeddingExplicitlyDisabled()) {\n vectorMissingIds.delete(obsId);\n } else {\n queueVectorBackfill(existing.projectId);\n }\n }).catch((err) => {\n queueVectorBackfill(existing.projectId);\n const failure = normalizeEmbeddingFailure(err);\n logEmbeddingFailureOnce(\n failure.key,\n `[memorix] Async embedding failed (using BM25 until embedding recovers; queued obs-${obsId} for retry): ${failure.message}`,\n );\n });\n\n return existing;\n}\n\n/**\n * Get an observation by ID.\n */\nexport function getObservation(id: number, projectId?: string): Observation | undefined {\n return observations.find((o) => o.id === id && (projectId ? o.projectId === projectId : true));\n}\n\n/**\n * Promote or demote an automatic observation without changing its content.\n * The expected-state guard keeps concurrent maintenance workers from\n * resurrecting an observation that another writer has already changed.\n */\nexport async function updateObservationAdmission(input: {\n observationId: number;\n projectId?: string;\n expectedState?: ObservationAdmissionState;\n admissionState: ObservationAdmissionState;\n admissionReason: string;\n visibility?: ObservationVisibility;\n}): Promise<Observation | undefined> {\n await ensureFreshObservations();\n const cached = observations.find((observation) =>\n observation.id === input.observationId &&\n (!input.projectId || observation.projectId === input.projectId),\n );\n if (!cached) return undefined;\n\n const now = new Date().toISOString();\n const admissionReason = sanitizeCredentials(input.admissionReason).slice(0, 240);\n const apply = (current: Observation): Observation | undefined => {\n if (input.projectId && current.projectId !== input.projectId) return undefined;\n if (input.expectedState && current.admissionState !== input.expectedState) return undefined;\n return {\n ...current,\n admissionState: input.admissionState,\n admissionReason,\n ...(input.visibility !== undefined ? { visibility: input.visibility } : {}),\n updatedAt: now,\n };\n };\n\n let updated: Observation | undefined;\n if (projectDir) {\n const store = getObservationStore();\n await store.atomic(async (tx) => {\n const current = await tx.getById(input.observationId);\n if (!current) return;\n const next = apply(current);\n if (!next) return;\n await tx.update(next);\n updated = next;\n });\n } else {\n updated = apply(cached);\n }\n\n if (!updated) return undefined;\n observations = observations.map((observation) =>\n observation.id === updated!.id && observation.projectId === updated!.projectId\n ? updated!\n : observation,\n );\n\n try {\n await updateObservationMetadata(updated.projectId, updated.id, {\n admissionState: updated.admissionState,\n admissionReason: updated.admissionReason,\n ...(updated.visibility !== undefined ? { visibility: updated.visibility } : {}),\n });\n } catch {\n // SQLite is canonical. The next index hydration repairs a missed update.\n }\n\n if (updated.admissionState === 'qualified' && resolveObservationVisibility(updated) === 'project') {\n queueClaimDerivation(updated);\n }\n\n return updated;\n}\n\n/**\n * Resolve observations — mark them as resolved (completed/no longer active).\n * This prevents resolved memories from appearing in default search results.\n */\nexport async function resolveObservations(\n ids: number[],\n status: ObservationStatus = 'resolved',\n): Promise<{ resolved: number[]; notFound: number[] }> {\n const resolved: number[] = [];\n const notFound: number[] = [];\n const changed: Observation[] = [];\n const now = new Date().toISOString();\n\n for (const id of ids) {\n const obs = observations.find(o => o.id === id);\n if (!obs) {\n notFound.push(id);\n continue;\n }\n obs.status = status;\n obs.updatedAt = now;\n if (obs.progress) {\n obs.progress.status = status === 'resolved' ? 'completed' : obs.progress.status;\n }\n resolved.push(id);\n changed.push(obs);\n\n // Update Orama index (without blocking on embedding)\n try {\n const { removeObservation: removeObs } = await import('../store/orama-store.js');\n await removeObs(makeOramaObservationId(obs.projectId, id));\n const doc: MemorixDocument = {\n id: makeOramaObservationId(obs.projectId, obs.id),\n observationId: obs.id,\n entityName: obs.entityName,\n type: obs.type,\n title: obs.title,\n narrative: obs.narrative,\n facts: obs.facts.join('\\n'),\n filesModified: obs.filesModified.join('\\n'),\n concepts: obs.concepts.map(c => c.replace(/-/g, ' ')).join(', '),\n tokens: obs.tokens,\n createdAt: obs.createdAt,\n projectId: obs.projectId,\n accessCount: 0,\n lastAccessedAt: '',\n status,\n source: obs.source ?? 'agent',\n sourceDetail: obs.sourceDetail ?? '',\n valueCategory: obs.valueCategory ?? '',\n admissionState: obs.admissionState ?? '',\n admissionReason: obs.admissionReason ?? '',\n visibility: obs.visibility ?? 'project',\n createdByAgentId: obs.createdByAgentId ?? '',\n sharedWithAgentIds: JSON.stringify(obs.sharedWithAgentIds ?? []),\n };\n await insertObservation(doc);\n // Async embedding update (fire-and-forget)\n const obsId = obs.id;\n generateEmbedding([obs.title, obs.narrative, ...obs.facts].join(' ')).then(async (embedding) => {\n if (embedding) {\n try {\n await removeObs(`obs-${obsId}`);\n await insertObservation(Object.assign({}, doc, { embedding }));\n } catch { /* best effort */ }\n }\n }).catch(() => {});\n } catch { /* best effort */ }\n }\n\n // Persist via ObservationStore\n if (projectDir && resolved.length > 0) {\n const store = getObservationStore();\n await store.atomic(async (tx) => {\n await Promise.all(changed.map((observation) => tx.update(observation)));\n });\n }\n\n return { resolved, notFound };\n}\n\n/**\n * Get all observations for a project.\n * Supports alias expansion: if projectIds is an array, matches any of them.\n */\nexport function getProjectObservations(projectId: string | string[]): Observation[] {\n if (Array.isArray(projectId)) {\n const idSet = new Set(projectId);\n return observations.filter((o) => idSet.has(o.projectId));\n }\n return observations.filter((o) => o.projectId === projectId);\n}\n\n/**\n * Migrate observations from non-canonical project IDs to the canonical ID.\n *\n * Called once during server startup after alias registration.\n * Rewrites in-memory observations and persists changes to disk.\n *\n * @param aliasIds - All known alias IDs for this project (including canonical)\n * @param canonicalId - The canonical project ID to normalize to\n * @returns Number of observations migrated\n */\nexport async function migrateProjectIds(\n aliasIds: string[],\n canonicalId: string,\n): Promise<number> {\n const nonCanonical = new Set(aliasIds.filter(id => id !== canonicalId));\n if (nonCanonical.size === 0) return 0;\n\n let migrated = 0;\n const changed: Observation[] = [];\n for (const obs of observations) {\n if (nonCanonical.has(obs.projectId)) {\n obs.projectId = canonicalId;\n migrated++;\n changed.push(obs);\n }\n }\n\n if (migrated > 0 && projectDir) {\n const store = getObservationStore();\n await store.atomic(async (tx) => {\n await Promise.all(changed.map((observation) => tx.update(observation)));\n });\n }\n\n return migrated;\n}\n\n/**\n * Get all observations (in-memory copy).\n * Used by timeline and retention to avoid unreliable Orama empty-term queries.\n */\nexport function getAllObservations(): Observation[] {\n return [...observations];\n}\n\n/**\n * Get the total number of stored observations.\n */\nexport function getObservationCount(): number {\n return observations.length;\n}\n\n/**\n * Suggest a stable topic key from type + title.\n * Uses family heuristics (architecture/*, bug/*, decision/*, etc.)\n * Inspired by Engram's mem_suggest_topic_key.\n */\nexport function suggestTopicKey(type: string, title: string): string {\n // Determine family from type\n let family = 'general';\n const typeLower = type.toLowerCase();\n for (const [fam, keywords] of Object.entries(TOPIC_KEY_FAMILIES)) {\n if (keywords.some(k => typeLower.includes(k))) {\n family = fam;\n break;\n }\n }\n\n // Normalize title to slug\n const slug = title\n .toLowerCase()\n .replace(/[^a-z0-9\\u4e00-\\u9fff\\s-]/g, '') // keep letters, digits, CJK, spaces, hyphens\n .trim()\n .replace(/\\s+/g, '-')\n .slice(0, 60);\n\n if (!slug) return '';\n return `${family}/${slug}`;\n}\n\n/**\n * Reload observations into the Orama index with full corpus embeddings.\n * Intended for explicit heavy rebuilds, not normal MCP startup.\n *\n * Optimization: uses batch embedding (ONNX processes 64 texts at a time)\n * instead of individual embed calls. This reduces startup CPU from minutes\n * to seconds for large observation sets (500+).\n */\nexport async function reindexObservations(): Promise<number> {\n if (observations.length === 0) return 0;\n\n // Reset the Orama index to ensure clean reindex (idempotent)\n await resetDb();\n searchIndexPrepared = false;\n vectorMissingIds.clear();\n\n // Prefer already-persisted vectors for remote providers. This restores semantic\n // recall after a restart without waiting on the network; cache misses remain\n // in the existing bounded background recovery lane.\n let embeddings: (number[] | null)[] = observations.map(() => null);\n const provider = await getEmbeddingProvider();\n const canBatchEmbedAtStartup = provider !== null && !provider.name.startsWith('api-');\n\n // This is an explicit rebuild path. Establish the current Orama schema before\n // accepting cached vectors so a stale cache entry cannot make an observation\n // disappear from the lexical index on insert.\n await getDb();\n\n const texts = observations.map(obs =>\n [obs.title, obs.narrative, ...obs.facts].join(' '),\n );\n\n if (provider?.getCachedEmbeddings) {\n try {\n embeddings = await provider.getCachedEmbeddings(texts);\n } catch {\n // Cache lookup is optional; remote cache misses continue to background recovery.\n }\n }\n\n if (provider && !canBatchEmbedAtStartup) {\n console.error('[memorix] Startup reindex: restored cached API embeddings; uncached vectors stay in background recovery');\n }\n\n if (canBatchEmbedAtStartup) {\n try {\n embeddings = await batchGenerateEmbeddings(texts);\n // Batch embedding failed — fall back to no embeddings\n } catch {\n // Batch embedding failed; fall back to no embeddings.\n }\n }\n\n let count = 0;\n for (let i = 0; i < observations.length; i++) {\n const obs = observations[i];\n try {\n const embedding = embeddings[i] ?? null;\n const compatibleEmbedding = isVectorCompatibleWithCurrentIndex(embedding) ? embedding : null;\n if (embedding && !compatibleEmbedding) {\n const vectorDimensions = getVectorDimensions();\n console.error(\n `[memorix] Startup reindex embedding mismatch for obs-${obs.id}: provider returned ${embedding.length}d, index expects ${vectorDimensions ?? 'unknown'}d (queued for backfill)`,\n );\n }\n const docId = makeOramaObservationId(obs.projectId, obs.id);\n const doc: MemorixDocument = {\n id: docId,\n observationId: obs.id,\n entityName: obs.entityName,\n type: obs.type,\n title: obs.title,\n narrative: obs.narrative,\n facts: obs.facts.join('\\n'),\n filesModified: obs.filesModified.join('\\n'),\n concepts: obs.concepts.map((c: string) => c.replace(/-/g, ' ')).join(', '),\n tokens: obs.tokens,\n createdAt: obs.createdAt,\n projectId: obs.projectId,\n accessCount: 0,\n lastAccessedAt: '',\n status: obs.status ?? 'active',\n source: obs.source ?? 'agent',\n sourceDetail: obs.sourceDetail ?? '',\n valueCategory: obs.valueCategory ?? '',\n admissionState: obs.admissionState ?? '',\n admissionReason: obs.admissionReason ?? '',\n visibility: obs.visibility ?? 'project',\n createdByAgentId: obs.createdByAgentId ?? '',\n sharedWithAgentIds: JSON.stringify(obs.sharedWithAgentIds ?? []),\n ...(compatibleEmbedding ? { embedding: compatibleEmbedding } : {}),\n };\n await insertObservation(doc);\n if (!compatibleEmbedding && !isEmbeddingExplicitlyDisabled()) {\n vectorMissingIds.add(obs.id);\n }\n count++;\n } catch (err) {\n console.error(`[memorix] Failed to reindex observation #${obs.id}: ${err}`);\n }\n }\n searchIndexPrepared = true;\n return count;\n}\n\n/**\n * Prepare the search index for startup and hot-reload without blocking on\n * corpus-wide embedding generation.\n *\n * This hydrates the lexical/BM25 index immediately so MCP availability is not\n * coupled to embedding provider throughput. Missing vectors are queued for the\n * existing background backfill cycle.\n */\nexport async function prepareSearchIndex(): Promise<number> {\n if (searchIndexPrepared) return 0;\n\n const count = await hydrateIndexForStartup(observations as unknown as any[]);\n if (count === 0) {\n searchIndexPrepared = true;\n return 0;\n }\n\n const hydratedProjectDir = projectDir;\n const queueMissingVectors = () => {\n if (projectDir !== hydratedProjectDir) return;\n vectorMissingIds.clear();\n if (!isEmbeddingExplicitlyDisabled()) {\n const projectsWithMissingVectors = new Set<string>();\n for (const obs of observations) {\n // Queue ALL statuses for vector backfill — status filtering happens at query time,\n // not at index time. Omitting non-active observations here would permanently\n // exclude resolved/archived memories from hybrid search after restart.\n if (!hasObservationVector(obs.projectId, obs.id)) {\n vectorMissingIds.add(obs.id);\n projectsWithMissingVectors.add(obs.projectId);\n }\n }\n for (const projectId of projectsWithMissingVectors) queueVectorBackfill(projectId);\n }\n };\n\n const cacheHydration = getDeferredCachedVectorHydration();\n if (cacheHydration) {\n // Let the disk cache finish outside the interactive startup path. Misses are\n // queued only after it has had a chance to restore compatible vectors.\n void cacheHydration.finally(queueMissingVectors);\n } else {\n queueMissingVectors();\n }\n\n searchIndexPrepared = true;\n return count;\n}\n\n// ── Vector-missing observability & backfill ─────────────────────────\n\n/**\n * Get the current set of observation IDs that are missing vector embeddings.\n * Useful for dashboards, health checks, and monitoring search quality degradation.\n */\nexport function getVectorMissingIds(projectId?: string): number[] {\n if (!projectId) return [...vectorMissingIds];\n const observationById = new Map(observations.map((observation) => [observation.id, observation]));\n return [...vectorMissingIds].filter((id) => observationById.get(id)?.projectId === projectId);\n}\n\n/**\n * Get a summary of vector embedding status.\n * Returns total observations, how many have vectors, and how many are missing.\n */\nexport function getVectorStatus(projectId?: string): {\n total: number;\n missing: number;\n missingIds: number[];\n backfillRunning: boolean;\n lastBackfill: typeof lastVectorBackfill;\n} {\n const missingIds = getVectorMissingIds(projectId);\n return {\n total: projectId ? observations.filter((observation) => observation.projectId === projectId).length : observations.length,\n missing: missingIds.length,\n missingIds,\n backfillRunning: vectorBackfillRunning,\n lastBackfill: lastVectorBackfill,\n };\n}\n\n/**\n * Return search-index state from the same module graph that owns the hydrated\n * Orama instance. This avoids split singleton state when tools load Memorix\n * TypeScript sources through runtime loaders.\n */\nexport function getSearchIndexStatus(projectId?: string): {\n embeddingEnabled: boolean;\n vectorDimensions: number | null;\n lastSearchMode: string;\n prepared: boolean;\n} {\n return {\n embeddingEnabled: isEmbeddingEnabled(),\n vectorDimensions: getVectorDimensions(),\n lastSearchMode: getLastSearchMode(projectId),\n prepared: searchIndexPrepared,\n };\n}\n\n/**\n * Observability-only semantic probe. It intentionally disables access tracking\n * so status checks do not mutate retention/access metadata.\n */\nexport async function probeSearchIndex(projectId: string): Promise<string> {\n await searchObservations({\n query: 'semantic memory retrieval status',\n projectId,\n reader: { projectId },\n limit: 1,\n status: 'all',\n trackAccess: false,\n });\n return getLastSearchMode(projectId);\n}\n\n/**\n * Attempt to backfill missing vector embeddings.\n * Re-generates embeddings for observations in vectorMissingIds.\n * Returns the number successfully backfilled.\n *\n * Safe to call concurrently — only one backfill runs at a time.\n */\nexport async function backfillVectorEmbeddings(options: {\n projectId?: string;\n limit?: number;\n} = {}): Promise<{\n attempted: number;\n succeeded: number;\n failed: number;\n}> {\n if (vectorBackfillRunning) {\n return { attempted: 0, succeeded: 0, failed: 0 };\n }\n vectorBackfillRunning = true;\n\n const observationById = new Map(observations.map((observation) => [observation.id, observation]));\n const limit = Number.isFinite(options.limit)\n ? Math.max(1, Math.floor(options.limit!))\n : Number.POSITIVE_INFINITY;\n const ids = [...vectorMissingIds]\n .filter((id) => !options.projectId || observationById.get(id)?.projectId === options.projectId)\n .slice(0, limit);\n let succeeded = 0;\n let failed = 0;\n let lastFailure: string | undefined;\n\n try {\n for (const id of ids) {\n const obs = observationById.get(id);\n if (!obs) {\n vectorMissingIds.delete(id);\n continue;\n }\n\n const text = [obs.title, obs.narrative, ...obs.facts].join(' ');\n try {\n const embedding = await generateEmbedding(text);\n if (embedding) {\n if (!isVectorCompatibleWithCurrentIndex(embedding)) {\n await upgradeVectorSchemaAfterFirstEmbedding(embedding);\n }\n if (!isVectorCompatibleWithCurrentIndex(embedding)) {\n const vectorDimensions = getVectorDimensions();\n console.error(\n `[memorix] Backfill embedding mismatch for obs-${id}: provider returned ${embedding.length}d, index expects ${vectorDimensions ?? 'unknown'}d (kept in queue)`,\n );\n lastFailure = `dimension mismatch: provider returned ${embedding.length}d, index expects ${vectorDimensions ?? 'unknown'}d`;\n failed++;\n continue;\n }\n const oramaId = makeOramaObservationId(obs.projectId, obs.id);\n try {\n const { removeObservation: removeObs } = await import('../store/orama-store.js');\n await removeObs(oramaId);\n } catch { /* may not exist */ }\n const doc: MemorixDocument = {\n id: oramaId,\n observationId: obs.id,\n entityName: obs.entityName,\n type: obs.type,\n title: obs.title,\n narrative: obs.narrative,\n facts: obs.facts.join('\\n'),\n filesModified: obs.filesModified.join('\\n'),\n concepts: obs.concepts.map(c => c.replace(/-/g, ' ')).join(', '),\n tokens: obs.tokens,\n createdAt: obs.createdAt,\n projectId: obs.projectId,\n accessCount: 0,\n lastAccessedAt: '',\n status: obs.status ?? 'active',\n source: obs.source ?? 'agent',\n sourceDetail: obs.sourceDetail ?? '',\n valueCategory: obs.valueCategory ?? '',\n admissionState: obs.admissionState ?? '',\n admissionReason: obs.admissionReason ?? '',\n visibility: obs.visibility ?? 'project',\n createdByAgentId: obs.createdByAgentId ?? '',\n sharedWithAgentIds: JSON.stringify(obs.sharedWithAgentIds ?? []),\n embedding,\n };\n await insertObservation(doc);\n vectorMissingIds.delete(id);\n succeeded++;\n } else if (isEmbeddingExplicitlyDisabled()) {\n // Embedding explicitly off — nothing to backfill from\n vectorMissingIds.delete(id);\n } else {\n // Provider temporarily unavailable — keep in queue for next backfill cycle\n lastFailure = 'embedding provider unavailable';\n failed++;\n }\n } catch (err) {\n lastFailure = err instanceof Error ? err.message : String(err);\n failed++;\n }\n }\n } finally {\n vectorBackfillRunning = false;\n lastVectorBackfill = {\n attempted: ids.length,\n succeeded,\n failed,\n ...(lastFailure ? { lastError: lastFailure } : {}),\n finishedAt: new Date().toISOString(),\n };\n }\n\n return { attempted: ids.length, succeeded, failed };\n}\n","import { randomUUID } from 'node:crypto';\nimport { getDatabase } from '../store/sqlite-db.js';\nimport type {\n KnowledgePageRecord,\n KnowledgeProposal,\n KnowledgeWorkspace,\n KnowledgeWorkspaceMode,\n KnowledgeWorkspaceStatus,\n} from './workspace-types.js';\n\nfunction arrayValue(raw: unknown): string[] {\n if (typeof raw !== 'string' || !raw) return [];\n try {\n const parsed = JSON.parse(raw);\n return Array.isArray(parsed) ? parsed.filter((item): item is string => typeof item === 'string') : [];\n } catch {\n return [];\n }\n}\n\nfunction optionalText(value: unknown): string | undefined {\n return typeof value === 'string' && value ? value : undefined;\n}\n\nfunction rowToWorkspace(row: any): KnowledgeWorkspace {\n return {\n id: row.id,\n projectId: row.projectId,\n mode: row.mode,\n rootPath: row.rootPath,\n ...(optionalText(row.projectRoot) ? { projectRoot: row.projectRoot } : {}),\n status: row.status,\n createdAt: row.createdAt,\n updatedAt: row.updatedAt,\n ...(optionalText(row.lastCompiledAt) ? { lastCompiledAt: row.lastCompiledAt } : {}),\n ...(optionalText(row.lastLintedAt) ? { lastLintedAt: row.lastLintedAt } : {}),\n };\n}\n\nfunction rowToPage(row: any): KnowledgePageRecord {\n return {\n id: row.id,\n workspaceId: row.workspaceId,\n relativePath: row.relativePath,\n title: row.title,\n kind: row.kind,\n status: row.status,\n reviewState: row.reviewState,\n contentHash: row.contentHash,\n sourceHash: row.sourceHash,\n claimIds: arrayValue(row.claimIdsJson),\n ...(optionalText(row.snapshotId) ? { snapshotId: row.snapshotId } : {}),\n tags: arrayValue(row.tagsJson),\n generatedAt: row.generatedAt,\n updatedAt: row.updatedAt,\n ...(optionalText(row.lastLintedAt) ? { lastLintedAt: row.lastLintedAt } : {}),\n ...(optionalText(row.manualContentHash) ? { manualContentHash: row.manualContentHash } : {}),\n };\n}\n\nfunction rowToProposal(row: any): KnowledgeProposal {\n return {\n id: row.id,\n workspaceId: row.workspaceId,\n pageId: row.pageId,\n targetPath: row.targetPath,\n proposalPath: row.proposalPath,\n ...(optionalText(row.baseContentHash) ? { baseContentHash: row.baseContentHash } : {}),\n sourceHash: row.sourceHash,\n reason: row.reason,\n status: row.status,\n createdAt: row.createdAt,\n ...(optionalText(row.appliedAt) ? { appliedAt: row.appliedAt } : {}),\n };\n}\n\n/**\n * Operational metadata for Markdown workspaces. The Markdown files remain the\n * human-readable source; this store tracks provenance and safe proposal state.\n */\nexport class KnowledgeWorkspaceStore {\n private db: any = null;\n\n async init(dataDir: string): Promise<void> {\n this.db = getDatabase(dataDir);\n }\n\n upsertWorkspace(input: Omit<KnowledgeWorkspace, 'createdAt' | 'updatedAt'> & {\n createdAt?: string;\n updatedAt?: string;\n }): KnowledgeWorkspace {\n const now = input.updatedAt ?? new Date().toISOString();\n const createdAt = input.createdAt ?? now;\n this.db.prepare(\n 'INSERT INTO knowledge_workspaces (id, projectId, mode, rootPath, projectRoot, status, createdAt, updatedAt, lastCompiledAt, lastLintedAt) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT(id) DO UPDATE SET mode = excluded.mode, rootPath = excluded.rootPath, projectRoot = excluded.projectRoot, status = excluded.status, updatedAt = excluded.updatedAt, lastCompiledAt = excluded.lastCompiledAt, lastLintedAt = excluded.lastLintedAt',\n ).run(\n input.id,\n input.projectId,\n input.mode,\n input.rootPath,\n input.projectRoot ?? null,\n input.status,\n createdAt,\n now,\n input.lastCompiledAt ?? null,\n input.lastLintedAt ?? null,\n );\n return this.getWorkspace(input.id)!;\n }\n\n getWorkspace(id: string): KnowledgeWorkspace | undefined {\n const row = this.db.prepare('SELECT * FROM knowledge_workspaces WHERE id = ?').get(id);\n return row ? rowToWorkspace(row) : undefined;\n }\n\n findWorkspace(projectId: string, mode: KnowledgeWorkspaceMode): KnowledgeWorkspace | undefined {\n const row = this.db.prepare('SELECT * FROM knowledge_workspaces WHERE projectId = ? AND mode = ? ORDER BY updatedAt DESC LIMIT 1').get(projectId, mode);\n return row ? rowToWorkspace(row) : undefined;\n }\n\n upsertPage(page: KnowledgePageRecord): void {\n this.db.prepare(\n 'INSERT INTO knowledge_pages (id, workspaceId, relativePath, title, kind, status, reviewState, contentHash, sourceHash, claimIdsJson, snapshotId, tagsJson, generatedAt, updatedAt, lastLintedAt, manualContentHash) VALUES (@id, @workspaceId, @relativePath, @title, @kind, @status, @reviewState, @contentHash, @sourceHash, @claimIdsJson, @snapshotId, @tagsJson, @generatedAt, @updatedAt, @lastLintedAt, @manualContentHash) ON CONFLICT(workspaceId, relativePath) DO UPDATE SET id = excluded.id, title = excluded.title, kind = excluded.kind, status = excluded.status, reviewState = excluded.reviewState, contentHash = excluded.contentHash, sourceHash = excluded.sourceHash, claimIdsJson = excluded.claimIdsJson, snapshotId = excluded.snapshotId, tagsJson = excluded.tagsJson, generatedAt = excluded.generatedAt, updatedAt = excluded.updatedAt, lastLintedAt = excluded.lastLintedAt, manualContentHash = excluded.manualContentHash',\n ).run({\n ...page,\n claimIdsJson: JSON.stringify(page.claimIds),\n snapshotId: page.snapshotId ?? null,\n tagsJson: JSON.stringify(page.tags),\n lastLintedAt: page.lastLintedAt ?? null,\n manualContentHash: page.manualContentHash ?? null,\n });\n }\n\n getPage(workspaceId: string, relativePath: string): KnowledgePageRecord | undefined {\n const row = this.db.prepare('SELECT * FROM knowledge_pages WHERE workspaceId = ? AND relativePath = ?').get(workspaceId, relativePath);\n return row ? rowToPage(row) : undefined;\n }\n\n getPageById(id: string): KnowledgePageRecord | undefined {\n const row = this.db.prepare('SELECT * FROM knowledge_pages WHERE id = ?').get(id);\n return row ? rowToPage(row) : undefined;\n }\n\n listPages(workspaceId: string): KnowledgePageRecord[] {\n return this.db.prepare('SELECT * FROM knowledge_pages WHERE workspaceId = ? ORDER BY relativePath').all(workspaceId).map(rowToPage);\n }\n\n replacePageClaims(pageId: string, claimIds: string[]): void {\n const remove = this.db.prepare('DELETE FROM knowledge_page_claims WHERE pageId = ?');\n const insert = this.db.prepare(\"INSERT OR IGNORE INTO knowledge_page_claims (pageId, claimId, role) VALUES (?, ?, 'primary')\");\n this.db.transaction(() => {\n remove.run(pageId);\n for (const claimId of [...new Set(claimIds)]) insert.run(pageId, claimId);\n })();\n }\n\n replacePageLinks(pageId: string, targets: string[]): void {\n const remove = this.db.prepare('DELETE FROM knowledge_page_links WHERE sourcePageId = ?');\n const insert = this.db.prepare('INSERT OR IGNORE INTO knowledge_page_links (sourcePageId, targetPath) VALUES (?, ?)');\n this.db.transaction(() => {\n remove.run(pageId);\n for (const target of [...new Set(targets)]) insert.run(pageId, target);\n })();\n }\n\n createProposal(input: Omit<KnowledgeProposal, 'id' | 'createdAt' | 'status'> & {\n id?: string;\n createdAt?: string;\n status?: KnowledgeProposal['status'];\n }): KnowledgeProposal {\n const proposal: KnowledgeProposal = {\n id: input.id ?? randomUUID(),\n ...input,\n status: input.status ?? 'pending',\n createdAt: input.createdAt ?? new Date().toISOString(),\n };\n this.db.prepare(\n 'INSERT INTO knowledge_proposals (id, workspaceId, pageId, targetPath, proposalPath, baseContentHash, sourceHash, reason, status, createdAt, appliedAt) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT(workspaceId, proposalPath) DO UPDATE SET pageId = excluded.pageId, targetPath = excluded.targetPath, baseContentHash = excluded.baseContentHash, sourceHash = excluded.sourceHash, reason = excluded.reason, status = excluded.status, createdAt = excluded.createdAt, appliedAt = excluded.appliedAt',\n ).run(\n proposal.id,\n proposal.workspaceId,\n proposal.pageId,\n proposal.targetPath,\n proposal.proposalPath,\n proposal.baseContentHash ?? null,\n proposal.sourceHash,\n proposal.reason,\n proposal.status,\n proposal.createdAt,\n proposal.appliedAt ?? null,\n );\n const row = this.db.prepare('SELECT * FROM knowledge_proposals WHERE workspaceId = ? AND proposalPath = ?').get(proposal.workspaceId, proposal.proposalPath);\n return rowToProposal(row);\n }\n\n getProposal(id: string): KnowledgeProposal | undefined {\n const row = this.db.prepare('SELECT * FROM knowledge_proposals WHERE id = ?').get(id);\n return row ? rowToProposal(row) : undefined;\n }\n\n listProposals(workspaceId: string, status?: KnowledgeProposal['status']): KnowledgeProposal[] {\n const rows = status\n ? this.db.prepare('SELECT * FROM knowledge_proposals WHERE workspaceId = ? AND status = ? ORDER BY createdAt DESC, id').all(workspaceId, status)\n : this.db.prepare('SELECT * FROM knowledge_proposals WHERE workspaceId = ? ORDER BY createdAt DESC, id').all(workspaceId);\n return rows.map(rowToProposal);\n }\n\n markProposalApplied(id: string, appliedAt = new Date().toISOString()): KnowledgeProposal {\n this.db.prepare(\"UPDATE knowledge_proposals SET status = 'applied', appliedAt = ? WHERE id = ?\").run(appliedAt, id);\n return this.getProposal(id)!;\n }\n\n markWorkspaceCompiled(id: string, at = new Date().toISOString()): void {\n this.db.prepare('UPDATE knowledge_workspaces SET lastCompiledAt = ?, updatedAt = ? WHERE id = ?').run(at, at, id);\n }\n\n markWorkspaceLinted(id: string, status: KnowledgeWorkspaceStatus, at = new Date().toISOString()): void {\n this.db.prepare('UPDATE knowledge_workspaces SET status = ?, lastLintedAt = ?, updatedAt = ? WHERE id = ?').run(status, at, at, id);\n }\n}\n","import { createHash } from 'node:crypto';\nimport { execFile } from 'node:child_process';\nimport { promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport { promisify } from 'node:util';\nimport { atomicWriteFile, withFileLock } from '../store/file-lock.js';\nimport { KnowledgeWorkspaceStore } from './workspace-store.js';\nimport type { KnowledgeWorkspace, KnowledgeWorkspaceMode } from './workspace-types.js';\n\nconst execFileAsync = promisify(execFile);\n\nexport interface KnowledgeWorkspacePaths {\n root: string;\n pages: string;\n proposals: string;\n workflows: string;\n index: string;\n log: string;\n schema: string;\n}\n\nexport interface InitializeKnowledgeWorkspaceInput {\n projectId: string;\n dataDir: string;\n mode: KnowledgeWorkspaceMode;\n projectRoot?: string;\n rootPath?: string;\n}\n\nfunction hash(value: string): string {\n return createHash('sha256').update(value).digest('hex');\n}\n\nfunction workspaceId(projectId: string, mode: KnowledgeWorkspaceMode): string {\n return 'workspace:' + hash(projectId + ':' + mode).slice(0, 24);\n}\n\nfunction localWorkspacePath(dataDir: string, projectId: string): string {\n return path.join(path.resolve(dataDir), 'knowledge-workspaces', hash(projectId).slice(0, 24));\n}\n\nfunction isWithin(root: string, candidate: string): boolean {\n const relative = path.relative(root, candidate);\n return relative !== '' && !relative.startsWith('..' + path.sep) && relative !== '..' && !path.isAbsolute(relative);\n}\n\nfunction ensureVersionedPath(projectRoot: string, rootPath: string): string {\n if (!path.isAbsolute(rootPath)) {\n throw new Error('A versioned knowledge workspace requires an explicit absolute path');\n }\n const resolvedProject = path.resolve(projectRoot);\n const resolvedWorkspace = path.resolve(rootPath);\n if (!isWithin(resolvedProject, resolvedWorkspace)) {\n throw new Error('A versioned knowledge workspace must live inside the Git project');\n }\n const segments = path.relative(resolvedProject, resolvedWorkspace).split(path.sep);\n if (segments.includes('.git') || segments.includes('node_modules') || segments.includes('dist')) {\n throw new Error('The selected knowledge workspace path is not safe for project artifacts');\n }\n return resolvedWorkspace;\n}\n\nasync function isIgnoredByGit(projectRoot: string, workspaceRoot: string): Promise<boolean> {\n const relative = path.relative(projectRoot, workspaceRoot).split(path.sep).join('/');\n const probes = [relative, relative.replace(/\\/+$/, '') + '/.memorix-workspace-probe'];\n for (const probe of probes) {\n try {\n await execFileAsync('git', ['-C', projectRoot, 'check-ignore', '--quiet', '--no-index', '--', probe], {\n timeout: 3_000,\n windowsHide: true,\n });\n return true;\n } catch (error) {\n const code = error && typeof error === 'object' && 'code' in error\n ? (error as { code?: number | string }).code\n : undefined;\n if (code === 1 || code === '1') continue;\n return false;\n }\n }\n return false;\n}\n\nasync function assertNoSymlinkEscape(projectRoot: string, workspaceRoot: string): Promise<void> {\n const [realProject, realWorkspace] = await Promise.all([\n fs.realpath(projectRoot),\n fs.realpath(workspaceRoot),\n ]);\n if (!isWithin(realProject, realWorkspace)) {\n throw new Error('The selected knowledge workspace resolves outside the Git project');\n }\n}\n\nexport function getKnowledgeWorkspacePaths(workspace: Pick<KnowledgeWorkspace, 'rootPath'>): KnowledgeWorkspacePaths {\n const root = path.resolve(workspace.rootPath);\n return {\n root,\n pages: path.join(root, 'pages'),\n proposals: path.join(root, 'proposals'),\n workflows: path.join(root, 'workflows'),\n index: path.join(root, 'index.md'),\n log: path.join(root, 'log.md'),\n schema: path.join(root, 'schema.md'),\n };\n}\n\nexport function resolveKnowledgeWorkspaceFile(workspace: Pick<KnowledgeWorkspace, 'rootPath'>, relativePath: string): string {\n if (!relativePath || path.isAbsolute(relativePath)) {\n throw new Error('Knowledge workspace paths must be relative');\n }\n const root = path.resolve(workspace.rootPath);\n const candidate = path.resolve(root, relativePath);\n if (candidate === root || !isWithin(root, candidate)) {\n throw new Error('Knowledge workspace path escapes its root');\n }\n return candidate;\n}\n\nasync function writeIfMissing(filePath: string, content: string): Promise<void> {\n try {\n await fs.access(filePath);\n } catch {\n await atomicWriteFile(filePath, content);\n }\n}\n\nfunction schemaContent(): string {\n return [\n '# Memorix Knowledge Workspace',\n '',\n 'This workspace is compiled from source-qualified Memorix claims.',\n 'Topic pages are proposal-first: review and apply a proposal before relying',\n 'on it as a published project knowledge page.',\n '',\n 'Do not remove claim ids, evidence references, source hashes, or snapshot',\n 'references from page frontmatter. Manual body edits are preserved and cause',\n 'later compiler output to remain a proposal.',\n '',\n ].join('\\n');\n}\n\nfunction indexContent(): string {\n return [\n '# Knowledge Workspace',\n '',\n '## Published pages',\n '',\n 'No published pages yet.',\n '',\n '## Review queue',\n '',\n 'No pending proposals.',\n '',\n ].join('\\n');\n}\n\nfunction logContent(): string {\n return '# Knowledge log\\n\\n';\n}\n\nexport async function initializeKnowledgeWorkspace(input: InitializeKnowledgeWorkspaceInput): Promise<KnowledgeWorkspace> {\n if (!input.projectId.trim()) throw new Error('Knowledge workspace project id is required');\n if (!input.dataDir.trim()) throw new Error('Knowledge workspace data directory is required');\n\n let rootPath: string;\n let projectRoot: string | undefined;\n if (input.mode === 'local') {\n rootPath = localWorkspacePath(input.dataDir, input.projectId);\n } else {\n if (!input.projectRoot || !input.rootPath) {\n throw new Error('A versioned knowledge workspace requires projectRoot and rootPath');\n }\n projectRoot = path.resolve(input.projectRoot);\n rootPath = ensureVersionedPath(projectRoot, input.rootPath);\n if (await isIgnoredByGit(projectRoot, rootPath)) {\n throw new Error('The selected versioned knowledge workspace is ignored by Git');\n }\n }\n\n const paths = getKnowledgeWorkspacePaths({ rootPath });\n await fs.mkdir(paths.pages, { recursive: true });\n await Promise.all([\n fs.mkdir(paths.proposals, { recursive: true }),\n fs.mkdir(paths.workflows, { recursive: true }),\n ]);\n if (projectRoot) await assertNoSymlinkEscape(projectRoot, paths.root);\n\n const workspace: KnowledgeWorkspace = {\n id: workspaceId(input.projectId, input.mode),\n projectId: input.projectId,\n dataDir: path.resolve(input.dataDir),\n mode: input.mode,\n rootPath: paths.root,\n ...(projectRoot ? { projectRoot } : {}),\n status: 'ready',\n createdAt: new Date().toISOString(),\n updatedAt: new Date().toISOString(),\n };\n\n await withFileLock(paths.root, async () => {\n await writeIfMissing(paths.schema, schemaContent());\n await writeIfMissing(paths.index, indexContent());\n await writeIfMissing(paths.log, logContent());\n });\n\n const store = new KnowledgeWorkspaceStore();\n await store.init(input.dataDir);\n return { ...store.upsertWorkspace(workspace), dataDir: workspace.dataDir };\n}\n\nexport async function loadKnowledgeWorkspace(input: {\n projectId: string;\n dataDir: string;\n mode?: KnowledgeWorkspaceMode;\n}): Promise<KnowledgeWorkspace | undefined> {\n const store = new KnowledgeWorkspaceStore();\n await store.init(input.dataDir);\n const workspace = store.findWorkspace(input.projectId, input.mode ?? 'local');\n return workspace ? { ...workspace, dataDir: path.resolve(input.dataDir) } : undefined;\n}\n","import type { Observation, ObservationAdmissionState, ObservationType } from '../types.js';\nimport { resolveObservationVisibility } from './visibility.js';\n\nconst DURABLE_AUTOMATIC_TYPES = new Set<ObservationType>([\n 'decision',\n 'gotcha',\n 'problem-solution',\n 'trade-off',\n 'why-it-exists',\n]);\n\n/**\n * Legacy observations predate admission metadata and retain their existing\n * delivery behavior. New automatic captures must explicitly earn delivery.\n */\nexport function isEligibleForAutomaticDelivery(observation: Pick<Observation, 'admissionState'>): boolean {\n return observation.admissionState !== 'ephemeral' && observation.admissionState !== 'candidate';\n}\n\nexport function isCandidateObservation(observation: Pick<Observation, 'admissionState'>): boolean {\n return observation.admissionState === 'candidate';\n}\n\nexport function isEligibleForKnowledgePromotion(\n observation: Pick<Observation, 'admissionState' | 'valueCategory' | 'visibility'>,\n): boolean {\n return isEligibleForAutomaticDelivery(observation)\n && observation.valueCategory !== 'ephemeral'\n && resolveObservationVisibility(observation) === 'project';\n}\n\nexport interface CandidateQualification {\n admissionState: ObservationAdmissionState;\n admissionReason: string;\n}\n\n/**\n * Automatic hook records can become default-deliverable only after a current\n * Code Memory link backs a non-ephemeral candidate. This deliberately does\n * not create a claim: claims keep their explicit/Git source boundary.\n */\nexport function qualifyCandidateFromCurrentCode(input: {\n observation: Pick<Observation, 'admissionState' | 'valueCategory' | 'type'>;\n currentCodeReferenceCount: number;\n}): CandidateQualification | undefined {\n if (!isCandidateObservation(input.observation)) return undefined;\n if (input.observation.valueCategory === 'ephemeral') return undefined;\n if (input.currentCodeReferenceCount <= 0) return undefined;\n\n const typeLabel = DURABLE_AUTOMATIC_TYPES.has(input.observation.type)\n ? 'high-value automatic record'\n : 'automatic record';\n return {\n admissionState: 'qualified',\n admissionReason: `${typeLabel} qualified against ${input.currentCodeReferenceCount} current Code Memory reference(s)`,\n };\n}\n","/**\n * Memory Consolidation Engine\n *\n * Merges similar observations into consolidated summaries to prevent data bloat.\n * Uses text similarity (Jaccard on token n-grams) to find clusters of related\n * observations, then merges them into a single observation preserving key facts.\n *\n * Strategy:\n * 1. Group observations by entity + type\n * 2. Within each group, compute pairwise similarity\n * 3. Cluster observations above a similarity threshold\n * 4. Merge each cluster into a consolidated observation\n * 5. Remove originals, keep the merged result\n *\n * Inspired by Engram's duplicate_count and MemCP's MAGMA consolidation.\n */\n\nimport type { Observation } from '../types.js';\nimport { getObservationStore } from '../store/obs-store.js';\nimport { isEligibleForAutomaticDelivery } from './admission.js';\nimport { resolveObservationVisibility } from './visibility.js';\n\n/** Default similarity threshold for merging (0.0-1.0) */\nconst DEFAULT_SIMILARITY_THRESHOLD = 0.45;\n\n/** Higher threshold for high-value types — only near-duplicates should merge */\nconst HIGH_VALUE_SIMILARITY_THRESHOLD = 0.85;\n\n/** Types that require much higher similarity to merge (carry unique implementation detail) */\nconst HIGH_VALUE_TYPES = new Set(['gotcha', 'decision', 'trade-off', 'reasoning', 'problem-solution']);\n\n/** Minimum cluster size to trigger consolidation */\nconst MIN_CLUSTER_SIZE = 2;\n\n/** Maximum observations to process in one consolidation run */\nconst MAX_BATCH_SIZE = 500;\n\n/**\n * Tokenize text into word-level tokens for similarity comparison.\n */\nfunction tokenize(text: string): Set<string> {\n return new Set(\n text\n .toLowerCase()\n .replace(/[^a-z0-9\\u4e00-\\u9fff\\s-]/g, ' ')\n .split(/\\s+/)\n .filter(t => t.length > 1),\n );\n}\n\n/**\n * Compute Jaccard similarity between two sets of tokens.\n */\nfunction jaccardSimilarity(a: Set<string>, b: Set<string>): number {\n if (a.size === 0 && b.size === 0) return 1;\n let intersection = 0;\n for (const token of a) {\n if (b.has(token)) intersection++;\n }\n const union = a.size + b.size - intersection;\n return union === 0 ? 0 : intersection / union;\n}\n\n/**\n * Build a text fingerprint from an observation for similarity matching.\n */\nfunction observationFingerprint(obs: Observation): string {\n return [obs.title, obs.narrative, ...obs.facts, ...obs.concepts].join(' ');\n}\n\n/** A cluster of similar observations to be merged */\nexport interface ConsolidationCluster {\n /** IDs of observations in this cluster */\n ids: number[];\n /** Titles of observations in this cluster */\n titles: string[];\n /** Average pairwise similarity */\n similarity: number;\n /** The entity these belong to */\n entityName: string;\n /** The observation type */\n type: string;\n}\n\n/** Result of a consolidation run */\nexport interface ConsolidationResult {\n /** Number of clusters found */\n clustersFound: number;\n /** Number of observations merged */\n observationsMerged: number;\n /** Number of observations after consolidation */\n observationsAfter: number;\n /** Number of active project observations inspected in this bounded pass. */\n scanned: number;\n /** Present when another bounded pass is needed to cover this project. */\n nextCursor?: number;\n /** Details of each merge */\n merges: Array<{\n clusterId: number;\n mergedIds: number[];\n resultTitle: string;\n factCount: number;\n }>;\n}\n\ninterface ConsolidationPage {\n observations: Observation[];\n nextCursor?: number;\n}\n\nfunction clampBatchSize(limit: number | undefined): number {\n if (!Number.isFinite(limit)) return MAX_BATCH_SIZE;\n return Math.min(MAX_BATCH_SIZE, Math.max(1, Math.floor(limit!)));\n}\n\nfunction clampCursor(afterId: number | undefined): number {\n if (!Number.isFinite(afterId)) return 0;\n return Math.max(0, Math.floor(afterId!));\n}\n\nasync function loadConsolidationPage(\n projectId: string,\n options: { limit?: number; afterId?: number },\n): Promise<ConsolidationPage> {\n const limit = clampBatchSize(options.limit);\n const page = await getObservationStore().loadByProject(projectId, {\n status: 'active',\n afterId: clampCursor(options.afterId),\n limit: limit + 1,\n });\n const hasMore = page.length > limit;\n const observations = hasMore ? page.slice(0, limit) : page;\n return hasMore && observations.length > 0\n ? { observations, nextCursor: observations[observations.length - 1].id }\n : { observations };\n}\n\nfunction findClusters(observations: Observation[], threshold: number): ConsolidationCluster[] {\n // Pending automatic evidence must stay individually inspectable until its\n // source-backed qualification step completes. Consolidating it first would\n // erase the evidence grain the control plane still needs to audit.\n // Consolidation is a project-level maintenance action. Personal notes and\n // targeted handoffs must remain individually inspectable and are never\n // merged by a background job or another agent's manual cleanup.\n const eligible = observations\n .filter(isEligibleForAutomaticDelivery)\n .filter((observation) => resolveObservationVisibility(observation) === 'project');\n if (eligible.length < MIN_CLUSTER_SIZE) return [];\n\n const groups = new Map<string, Observation[]>();\n for (const obs of eligible) {\n const key = `${obs.entityName}::${obs.type}`;\n const group = groups.get(key) ?? [];\n group.push(obs);\n groups.set(key, group);\n }\n\n const clusters: ConsolidationCluster[] = [];\n for (const group of groups.values()) {\n if (group.length < MIN_CLUSTER_SIZE) continue;\n\n const groupType = group[0].type;\n const effectiveThreshold = HIGH_VALUE_TYPES.has(groupType)\n ? Math.max(threshold, HIGH_VALUE_SIMILARITY_THRESHOLD)\n : threshold;\n const fingerprints = group.map(obs => ({ obs, tokens: tokenize(observationFingerprint(obs)) }));\n const clustered = new Set<number>();\n\n for (let i = 0; i < fingerprints.length; i++) {\n if (clustered.has(fingerprints[i].obs.id)) continue;\n\n const cluster: Observation[] = [fingerprints[i].obs];\n let totalSim = 0;\n let simCount = 0;\n for (let j = i + 1; j < fingerprints.length; j++) {\n if (clustered.has(fingerprints[j].obs.id)) continue;\n const sim = jaccardSimilarity(fingerprints[i].tokens, fingerprints[j].tokens);\n if (sim >= effectiveThreshold) {\n cluster.push(fingerprints[j].obs);\n totalSim += sim;\n simCount++;\n }\n }\n\n if (cluster.length >= MIN_CLUSTER_SIZE) {\n for (const obs of cluster) clustered.add(obs.id);\n clusters.push({\n ids: cluster.map(o => o.id),\n titles: cluster.map(o => o.title),\n similarity: simCount > 0 ? totalSim / simCount : 0,\n entityName: cluster[0].entityName,\n type: cluster[0].type,\n });\n }\n }\n }\n\n return clusters;\n}\n\n/**\n * Find clusters of similar observations that could be consolidated.\n * Does NOT modify data — use this for preview / dry run.\n */\nexport async function findConsolidationCandidates(\n _projectDir: string,\n projectId: string,\n opts?: { threshold?: number; limit?: number; afterId?: number },\n): Promise<ConsolidationCluster[]> {\n const threshold = opts?.threshold ?? DEFAULT_SIMILARITY_THRESHOLD;\n const page = await loadConsolidationPage(projectId, opts ?? {});\n return findClusters(page.observations, threshold);\n}\n\n/**\n * Execute consolidation — merge clusters into single observations.\n *\n * For each cluster:\n * 1. Keep the most recent observation as the \"primary\"\n * 2. Merge facts, files, concepts from all members (deduplicated)\n * 3. Create a consolidated narrative\n * 4. Remove the other members\n */\nexport async function executeConsolidation(\n _projectDir: string,\n projectId: string,\n opts?: { threshold?: number; limit?: number; afterId?: number },\n): Promise<ConsolidationResult> {\n const store = getObservationStore();\n const page = await loadConsolidationPage(projectId, opts ?? {});\n const clusters = findClusters(page.observations, opts?.threshold ?? DEFAULT_SIMILARITY_THRESHOLD);\n\n if (clusters.length === 0) {\n return {\n clustersFound: 0,\n observationsMerged: 0,\n observationsAfter: await store.countByProject(projectId),\n scanned: page.observations.length,\n ...(page.nextCursor === undefined ? {} : { nextCursor: page.nextCursor }),\n merges: [],\n };\n }\n\n const result: ConsolidationResult = {\n clustersFound: clusters.length,\n observationsMerged: 0,\n observationsAfter: 0,\n scanned: page.observations.length,\n ...(page.nextCursor === undefined ? {} : { nextCursor: page.nextCursor }),\n merges: [],\n };\n\n await store.atomic(async (tx) => {\n const idsToRemove = new Set<number>();\n const updated = new Map<number, Observation>();\n\n for (let ci = 0; ci < clusters.length; ci++) {\n const cluster = clusters[ci];\n const members = (await Promise.all(cluster.ids.map((id) => tx.getById(id))))\n .filter((observation): observation is Observation => {\n if (!observation) return false;\n return observation.projectId === projectId\n && (observation.status ?? 'active') === 'active';\n });\n\n if (members.length < MIN_CLUSTER_SIZE) continue;\n\n // Sort by date — most recent first\n members.sort((a, b) =>\n new Date(b.updatedAt || b.createdAt).getTime() -\n new Date(a.updatedAt || a.createdAt).getTime(),\n );\n\n const primary = members[0];\n const others = members.slice(1);\n\n // Merge facts (deduplicated)\n const allFacts = new Set(primary.facts);\n for (const other of others) {\n for (const fact of other.facts) allFacts.add(fact);\n }\n\n // Merge files (deduplicated, case-insensitive)\n const fileSet = new Set(primary.filesModified.map(f => f.toLowerCase()));\n const allFiles = [...primary.filesModified];\n for (const other of others) {\n for (const f of other.filesModified) {\n if (!fileSet.has(f.toLowerCase())) {\n fileSet.add(f.toLowerCase());\n allFiles.push(f);\n }\n }\n }\n\n // Merge concepts (deduplicated)\n const conceptSet = new Set(primary.concepts);\n for (const other of others) {\n for (const c of other.concepts) conceptSet.add(c);\n }\n\n // Build consolidated narrative\n const narrativeParts = [primary.narrative];\n for (const other of others) {\n if (other.narrative !== primary.narrative) {\n narrativeParts.push(`[Consolidated from #${other.id}] ${other.narrative}`);\n }\n }\n\n // Update primary\n primary.facts = [...allFacts];\n primary.filesModified = allFiles;\n primary.concepts = [...conceptSet];\n primary.narrative = narrativeParts.join('\\n\\n');\n primary.updatedAt = new Date().toISOString();\n primary.revisionCount = (primary.revisionCount ?? 1) + others.length;\n updated.set(primary.id, primary);\n\n // Mark others for removal\n for (const other of others) {\n idsToRemove.add(other.id);\n }\n\n result.observationsMerged += others.length;\n result.merges.push({\n clusterId: ci,\n mergedIds: cluster.ids,\n resultTitle: primary.title,\n factCount: primary.facts.length,\n });\n }\n\n await Promise.all([...updated.values()].map((observation) => tx.update(observation)));\n await Promise.all([...idsToRemove].map((id) => tx.remove(id)));\n });\n\n result.observationsAfter = await store.countByProject(projectId);\n\n return result;\n}\n","/**\n * Memory Compact Engine\n *\n * Dual-mode memory management inspired by:\n * - Mem0's ADD/UPDATE/DELETE/NONE decision model with content merging\n * - Cipher's dual-mode architecture (LLM + heuristic fallback)\n *\n * Two paths:\n * 1. LLM mode (compactOnWrite): Single LLM call → extract facts + compare + decide + merge\n * 2. Free mode (heuristicCompact): Vector similarity → rule-based ADD/UPDATE/NONE\n *\n * Both paths produce a CompactDecision that the caller executes.\n */\n\nimport { callLLM, isLLMEnabled } from './provider.js';\n\n/** The decision the compact engine makes for each memory operation */\nexport type MemoryAction = 'ADD' | 'UPDATE' | 'DELETE' | 'NONE';\n\n/** Existing memory entry for comparison */\nexport interface ExistingMemory {\n id: number;\n title: string;\n narrative: string;\n facts: string;\n score: number;\n}\n\n/** The compact decision — what to do with the new memory */\nexport interface CompactDecision {\n action: MemoryAction;\n /** ID of existing memory to UPDATE/DELETE */\n targetId?: number;\n /** Brief explanation of why this action was chosen */\n reason: string;\n /** Merged narrative for UPDATE (Mem0-style rewrite) */\n mergedNarrative?: string;\n /** Merged facts for UPDATE */\n mergedFacts?: string[];\n /** LLM-extracted enriched facts (only in LLM mode) */\n enrichedFacts?: string[];\n /** Whether LLM was used for this decision */\n usedLLM: boolean;\n}\n\n/**\n * Unified Compact on Write prompt (Mem0-inspired, single LLM call).\n *\n * This prompt does 3 things in 1 call:\n * 1. Extract structured facts from the new content\n * 2. Compare with existing similar memories\n * 3. Decide ADD/UPDATE/DELETE/NONE and merge if needed\n */\nconst COMPACT_ON_WRITE_PROMPT = `You are a smart coding memory manager. You control the memory of a cross-IDE coding assistant.\n\nYou receive a NEW MEMORY to store and a list of EXISTING similar memories. Your job:\n1. Extract the key facts from the new memory\n2. Compare with existing memories\n3. Decide the best action\n\nActions:\n- ADD: New memory contains unique information. Store it as-is.\n- UPDATE: New memory supersedes or improves an existing one. Merge them into a single, comprehensive memory.\n- DELETE: An existing memory is outdated/contradicted by the new one. Remove it.\n- NONE: New memory is redundant. Existing memories already cover this. Skip storing.\n\nDecision rules:\n- Same topic updated (e.g., \"MySQL → PostgreSQL\"): UPDATE the old memory with merged content\n- Bug fixed that was reported as open: UPDATE the bug report to include the fix\n- Task completed that was tracked as in-progress: UPDATE to mark completed\n- Minor variation of existing memory: NONE (skip)\n- Completely new topic: ADD\n- Old info directly contradicted: DELETE the old one\n- Prefer UPDATE over ADD — keep memory count low, merge information\n\nFor UPDATE: write a merged narrative that combines the best of both old and new, preserving all important details. Also merge the facts lists, removing duplicates.\n\nRespond in JSON only:\n{\n \"action\": \"ADD\" | \"UPDATE\" | \"DELETE\" | \"NONE\",\n \"targetId\": null or existing_memory_id_number,\n \"reason\": \"brief explanation of decision\",\n \"mergedNarrative\": \"merged narrative text (required for UPDATE, null otherwise)\",\n \"mergedFacts\": [\"merged fact 1\", \"merged fact 2\"] or null,\n \"extractedFacts\": [\"fact extracted from new content 1\", \"fact 2\"]\n}`;\n\n// ─── Heuristic Constants (Cipher-inspired) ───────────────────────────\n\n/** Similarity threshold above which we consider memories as \"same topic\" */\nconst SIMILARITY_HIGH = 0.75;\n/** Similarity threshold for \"related but different\" */\nconst SIMILARITY_MEDIUM = 0.5;\n\n// ─── LLM Mode ────────────────────────────────────────────────────────\n\n/**\n * Compact on Write — LLM mode.\n *\n * Single LLM call that extracts facts, compares with existing memories,\n * and decides ADD/UPDATE/DELETE/NONE with merged content.\n *\n * Inspired by Mem0's `get_update_memory_messages` but unified into 1 call.\n */\nexport async function compactOnWrite(\n newMemory: { title: string; narrative: string; facts: string[] },\n existingMemories: ExistingMemory[],\n): Promise<CompactDecision> {\n if (!isLLMEnabled()) {\n return heuristicCompact(newMemory, existingMemories);\n }\n\n if (existingMemories.length === 0) {\n return { action: 'ADD', reason: 'No existing memories to compare', usedLLM: false };\n }\n\n // Build the prompt with new + existing memories (Mem0's temp_uuid_mapping approach)\n const existingList = existingMemories\n .map(m => `[ID: ${m.id}] (similarity: ${m.score.toFixed(2)}) ${m.title}\\n Narrative: ${m.narrative}\\n Facts: ${m.facts}`)\n .join('\\n\\n');\n\n const userMessage = `NEW MEMORY:\nTitle: ${newMemory.title}\nNarrative: ${newMemory.narrative}\nFacts: ${newMemory.facts.join('; ')}\n\nEXISTING SIMILAR MEMORIES:\n${existingList}`;\n\n try {\n const response = await callLLM(COMPACT_ON_WRITE_PROMPT, userMessage);\n\n // Parse response — handle markdown code blocks\n let content = response.content.trim();\n if (content.startsWith('```')) {\n content = content.replace(/^```(?:json)?\\s*/, '').replace(/\\s*```$/, '');\n }\n\n const parsed = JSON.parse(content) as {\n action: string;\n targetId?: number | null;\n reason?: string;\n mergedNarrative?: string | null;\n mergedFacts?: string[] | null;\n extractedFacts?: string[] | null;\n };\n\n // Validate action\n const action = parsed.action?.toUpperCase() as MemoryAction;\n if (!action || !['ADD', 'UPDATE', 'DELETE', 'NONE'].includes(action)) {\n return { action: 'ADD', reason: 'LLM response invalid, defaulting to ADD', usedLLM: true };\n }\n\n // Validate targetId exists in existing memories for UPDATE/DELETE\n if ((action === 'UPDATE' || action === 'DELETE') && parsed.targetId != null) {\n const targetExists = existingMemories.some(m => m.id === parsed.targetId);\n if (!targetExists) {\n // LLM hallucinated an ID (common issue noted in Mem0's code)\n return { action: 'ADD', reason: `LLM referenced non-existent memory #${parsed.targetId}, defaulting to ADD`, usedLLM: true };\n }\n }\n\n return {\n action,\n targetId: parsed.targetId ?? undefined,\n reason: parsed.reason ?? 'LLM decision',\n mergedNarrative: parsed.mergedNarrative ?? undefined,\n mergedFacts: parsed.mergedFacts ?? undefined,\n enrichedFacts: parsed.extractedFacts ?? undefined,\n usedLLM: true,\n };\n } catch (err) {\n // LLM failed — fall back to heuristic\n console.error(`[memorix] LLM compact failed, falling back to heuristic:`, (err as Error)?.message ?? err);\n return heuristicCompact(newMemory, existingMemories);\n }\n}\n\n// ─── Free Mode (Heuristic) ───────────────────────────────────────────\n\n/**\n * Heuristic Compact — Free mode, no LLM needed.\n *\n * Uses vector similarity scores from search results to make decisions.\n * Inspired by Cipher's fallback logic in extract_and_operate_memory.ts.\n *\n * Decision logic:\n * - score >= 0.75: Very similar → check if new is more complete\n * - New is longer/richer → UPDATE (merge)\n * - Otherwise → NONE (skip, already covered)\n * - score >= 0.50: Related topic\n * - Same entity + same type → UPDATE if new has more facts\n * - Otherwise → ADD (different enough)\n * - score < 0.50: Different topic → ADD\n */\nexport function heuristicCompact(\n newMemory: { title: string; narrative: string; facts: string[] },\n existingMemories: ExistingMemory[],\n): CompactDecision {\n if (existingMemories.length === 0) {\n return { action: 'ADD', reason: 'No existing memories to compare', usedLLM: false };\n }\n\n const best = existingMemories[0]; // Already sorted by score\n\n // High similarity — very likely same topic\n if (best.score >= SIMILARITY_HIGH) {\n const newLength = newMemory.narrative.length + newMemory.facts.join(' ').length;\n const oldLength = best.narrative.length + best.facts.length;\n\n if (newLength > oldLength * 1.2) {\n // New memory is substantially richer — UPDATE with merged content\n const mergedNarrative = mergeTexts(best.narrative, newMemory.narrative);\n const mergedFacts = mergeFacts(best.facts, newMemory.facts.join('\\n'));\n return {\n action: 'UPDATE',\n targetId: best.id,\n reason: `New memory is more comprehensive (${newLength} > ${oldLength} chars)`,\n mergedNarrative,\n mergedFacts,\n usedLLM: false,\n };\n }\n\n // New memory is not richer — skip it\n return {\n action: 'NONE',\n targetId: best.id,\n reason: `Existing memory #${best.id} already covers this topic (similarity: ${best.score.toFixed(2)})`,\n usedLLM: false,\n };\n }\n\n // Medium similarity — related but might be different enough\n if (best.score >= SIMILARITY_MEDIUM) {\n const newFactCount = newMemory.facts.length;\n const oldFactCount = best.facts.split('\\n').filter(Boolean).length;\n\n if (newFactCount > oldFactCount) {\n // New has more facts — UPDATE\n const mergedNarrative = mergeTexts(best.narrative, newMemory.narrative);\n const mergedFacts = mergeFacts(best.facts, newMemory.facts.join('\\n'));\n return {\n action: 'UPDATE',\n targetId: best.id,\n reason: `New memory has more facts (${newFactCount} > ${oldFactCount}), merging`,\n mergedNarrative,\n mergedFacts,\n usedLLM: false,\n };\n }\n\n // Related but not richer — ADD as separate memory\n return { action: 'ADD', reason: `Related to #${best.id} but different enough to keep separate`, usedLLM: false };\n }\n\n // Low similarity — new topic\n return { action: 'ADD', reason: 'No similar memories found', usedLLM: false };\n}\n\n// ─── Content Merging Utilities ───────────────────────────────────────\n\n/**\n * Merge two narrative texts, keeping the more comprehensive version\n * while preserving unique information from both.\n */\nfunction mergeTexts(oldText: string, newText: string): string {\n // If new text is significantly longer, prefer it\n if (newText.length > oldText.length * 1.5) return newText;\n // If old text is significantly longer, append new info\n if (oldText.length > newText.length * 1.5) return oldText;\n // Similar length — combine with separator\n return `${newText}\\n\\n[Previous context]: ${oldText}`;\n}\n\n/**\n * Merge two fact lists, removing duplicates.\n * oldFacts is newline-separated string, newFacts is array.\n */\nfunction mergeFacts(oldFactsStr: string, newFactsStr: string): string[] {\n const oldFacts = oldFactsStr.split('\\n').filter(Boolean).map(f => f.trim());\n const newFacts = newFactsStr.split('\\n').filter(Boolean).map(f => f.trim());\n\n const seen = new Set<string>();\n const merged: string[] = [];\n\n // Add new facts first (they're more recent)\n for (const f of newFacts) {\n const normalized = f.toLowerCase();\n if (!seen.has(normalized)) {\n seen.add(normalized);\n merged.push(f);\n }\n }\n\n // Add old facts that aren't duplicates\n for (const f of oldFacts) {\n const normalized = f.toLowerCase();\n if (!seen.has(normalized)) {\n seen.add(normalized);\n merged.push(f);\n }\n }\n\n return merged;\n}\n\n// ─── Batch Dedup (for memorix_deduplicate tool) ──────────────────────\n\n/**\n * LLM-powered dedup for batch cleanup.\n * Compares a new memory against existing ones and returns a decision.\n * Used by memorix_deduplicate tool.\n */\nexport async function deduplicateMemory(\n newMemory: { title: string; narrative: string; facts: string[] },\n existingMemories: Array<{ id: number; title: string; narrative: string; facts: string }>,\n): Promise<CompactDecision | null> {\n if (!isLLMEnabled()) return null;\n if (existingMemories.length === 0) return { action: 'ADD', reason: 'No existing memories', usedLLM: false };\n\n const asExisting: ExistingMemory[] = existingMemories.map(m => ({\n ...m,\n score: 0.8, // Batch dedup assumes high similarity (pre-filtered)\n }));\n\n return compactOnWrite(newMemory, asExisting);\n}\n","/**\n * Retention & Decay Engine\n *\n * Manages memory relevance over time using exponential decay.\n * Sources:\n * - mcp-memory-service: ExponentialDecayCalculator (importance × decay × access_boost)\n * - MemCP: Active → Archive → Purge lifecycle with immunity rules\n *\n * Relevance formula:\n * score = baseImportance × e^(-ageDays / retentionPeriod) × accessBoost × connectionBoost\n *\n * Immunity: observations with importance=critical, valueCategory=core, accessCount>=3,\n * or tagged \"keep\"/\"pinned\" are never auto-archived.\n * High-importance types (gotcha/decision/trade-off/reasoning) retain a long 180-day\n * retention period but are no longer permanently immune — they decay normally.\n */\n\nimport type { MemorixDocument, Observation, ObservationReader } from '../types.js';\nimport { getObservationStore } from '../store/obs-store.js';\nimport { canManageObservation } from './visibility.js';\n\n// ── Importance → Retention Period mapping ────────────────────────────\n\nexport type ImportanceLevel = 'critical' | 'high' | 'medium' | 'low';\n\nconst RETENTION_DAYS: Record<ImportanceLevel, number> = {\n critical: 365,\n high: 180,\n medium: 90,\n low: 30,\n};\n\nconst BASE_IMPORTANCE: Record<ImportanceLevel, number> = {\n critical: 1.0,\n high: 0.8,\n medium: 0.5,\n low: 0.3,\n};\n\n// ── Observation Type → Default Importance ────────────────────────────\n\nconst TYPE_IMPORTANCE: Record<string, ImportanceLevel> = {\n gotcha: 'high',\n decision: 'high',\n 'trade-off': 'high',\n reasoning: 'high',\n 'problem-solution': 'medium',\n 'how-it-works': 'medium',\n 'what-changed': 'low',\n 'why-it-exists': 'medium',\n discovery: 'low',\n 'session-request': 'low',\n probe: 'low',\n};\n\n/** Per-type retention period overrides (in days). When set, replaces the importance-based base retention. */\nconst TYPE_RETENTION_OVERRIDE: Partial<Record<string, number>> = {\n probe: 7, // Operational heartbeats: expire after ~7 days regardless of source/valueCategory\n};\n\n// ── Immunity ─────────────────────────────────────────────────────────\n\nconst PROTECTED_TAGS = new Set(['keep', 'important', 'pinned', 'critical']);\nconst MIN_ACCESS_FOR_IMMUNITY = 3;\n\n/** Minimum effective retention period in days — prevents extreme multiplier combinations\n * (e.g. hook × ephemeral = 0.25×) from producing unreasonably short windows. */\nconst MIN_RETENTION_DAYS = 7;\n\n/**\n * Get retention period multiplier based on sourceDetail.\n * Neutral (1.0) for unknown/undefined sourceDetail — backward-compatible.\n */\nfunction getSourceRetentionMultiplier(doc: MemorixDocument): number {\n if (doc.sourceDetail === 'hook') return 0.5; // hook auto-captures: half the retention period\n if (doc.sourceDetail === 'git-ingest') return 1.5; // git-backed truth: extend retention\n return 1.0; // explicit/undefined: neutral\n}\n\n/**\n * Get retention period multiplier based on valueCategory.\n * Neutral (1.0) for undefined/contextual — backward-compatible.\n */\nfunction getValueCategoryMultiplier(doc: MemorixDocument): number {\n if (doc.valueCategory === 'ephemeral') return 0.5; // short-lived context: decay faster\n if (doc.valueCategory === 'core') return 2.0; // durable knowledge: extend retention\n return 1.0; // contextual/undefined: neutral\n}\n\n/**\n * Compute the effective retention period in days, with floor applied.\n * Combines base retention (from importance/type) with source and valueCategory multipliers.\n */\nexport function getEffectiveRetentionDays(doc: MemorixDocument): number {\n const typeOverride = TYPE_RETENTION_OVERRIDE[doc.type];\n if (typeOverride !== undefined) {\n // Type-specific override: use the override directly, ignoring importance-based base retention.\n // Source multiplier still applies so that e.g. hook-sourced probes decay even faster.\n // valueCategory multiplier is intentionally excluded for type-override types:\n // probe + core must NOT extend to 14 days -- probe is always short-lived.\n const raw = typeOverride * getSourceRetentionMultiplier(doc);\n return Math.max(MIN_RETENTION_DAYS, raw);\n }\n const importance = getImportanceLevel(doc);\n const raw = RETENTION_DAYS[importance] * getSourceRetentionMultiplier(doc) * getValueCategoryMultiplier(doc);\n return Math.max(MIN_RETENTION_DAYS, raw);\n}\n\n/**\n * Check if an observation is immune from archiving/decay.\n * Immune observations maintain a minimum relevance score.\n */\nexport function isImmune(doc: MemorixDocument): boolean {\n // Probe observations are operational heartbeats -- never immune, regardless of valueCategory or access.\n if (doc.type === 'probe') return false;\n\n // A candidate has not earned durable status. Never let an automatic core\n // classification turn unqualified capture into permanently retained memory.\n if (doc.admissionState === 'candidate' || doc.admissionState === 'ephemeral') return false;\n\n // formation-classified core memories are immune regardless of type\n if (doc.valueCategory === 'core') return true;\n\n const importance = getImportanceLevel(doc);\n // Only 'critical' importance grants type-based immunity.\n // 'high' importance types (gotcha/decision/trade-off/reasoning) keep their long\n // 180-day retention period but are no longer permanently immune — this prevents\n // unbounded growth of never-accessed high-type observations.\n if (importance === 'critical') return true;\n if ((doc.accessCount ?? 0) >= MIN_ACCESS_FOR_IMMUNITY) return true;\n\n const concepts = doc.concepts?.split(', ').map((c) => c.toLowerCase()) ?? [];\n return concepts.some((c) => PROTECTED_TAGS.has(c));\n}\n\n/**\n * Return a human-readable reason for why an observation is immune, or null if not immune.\n */\nexport function getImmunityReason(doc: MemorixDocument): string | null {\n // Probe observations are never immune\n if (doc.type === 'probe') return null;\n\n // Automatic traces and candidates have not earned durable status. Keep the\n // explanation aligned with isImmune() even when an earlier classifier gave\n // a candidate the core value category.\n if (doc.admissionState === 'candidate' || doc.admissionState === 'ephemeral') return null;\n\n if (doc.valueCategory === 'core') return 'core valueCategory (formation-classified)';\n const importance = getImportanceLevel(doc);\n if (importance === 'critical') return 'critical importance';\n if ((doc.accessCount ?? 0) >= MIN_ACCESS_FOR_IMMUNITY) return `frequently accessed (${doc.accessCount}×)`;\n const concepts = doc.concepts?.split(', ').map((c) => c.toLowerCase()) ?? [];\n if (concepts.some((c) => PROTECTED_TAGS.has(c))) return 'protected tag';\n return null;\n}\n\n// ── Relevance Scoring ────────────────────────────────────────────────\n\nexport interface RelevanceScore {\n observationId: number;\n totalScore: number;\n baseImportance: number;\n decayFactor: number;\n accessBoost: number;\n ageDays: number;\n isImmune: boolean;\n}\n\n/**\n * Get the importance level for an observation based on its type.\n */\nexport function getImportanceLevel(doc: MemorixDocument): ImportanceLevel {\n return TYPE_IMPORTANCE[doc.type] ?? 'medium';\n}\n\n/**\n * Calculate the relevance score for a single observation.\n *\n * Formula (from mcp-memory-service):\n * score = baseImportance × e^(-ageDays / retentionPeriod) × accessBoost\n *\n * Access boost (from mcp-memory-service):\n * 1 + 0.1 × accessCount (10% boost per access, capped at 2.0)\n */\nexport function calculateRelevance(\n doc: MemorixDocument,\n referenceTime?: Date,\n): RelevanceScore {\n const now = referenceTime ?? new Date();\n const importance = getImportanceLevel(doc);\n const base = BASE_IMPORTANCE[importance];\n const retention = getEffectiveRetentionDays(doc);\n\n // Age in days\n const createdAt = new Date(doc.createdAt);\n const ageDays = Math.max(0, (now.getTime() - createdAt.getTime()) / (1000 * 60 * 60 * 24));\n\n // Exponential decay\n const decayFactor = Math.exp(-ageDays / retention);\n\n // Access boost: 10% per access, capped at 2.0×\n const accessCount = doc.accessCount ?? 0;\n const accessBoost = Math.min(2.0, 1 + 0.1 * accessCount);\n\n let totalScore = base * decayFactor * accessBoost;\n\n // Immune observations get minimum 0.5 relevance\n const immune = isImmune(doc);\n if (immune) {\n totalScore = Math.max(totalScore, 0.5);\n }\n\n return {\n observationId: doc.observationId,\n totalScore,\n baseImportance: base,\n decayFactor,\n accessBoost,\n ageDays,\n isImmune: immune,\n };\n}\n\n/**\n * Score and rank observations by relevance.\n * Returns sorted (highest relevance first) with scores.\n */\nexport function rankByRelevance(\n docs: MemorixDocument[],\n referenceTime?: Date,\n): RelevanceScore[] {\n return docs\n .map((doc) => calculateRelevance(doc, referenceTime))\n .sort((a, b) => b.totalScore - a.totalScore);\n}\n\n// ── Retention Lifecycle ──────────────────────────────────────────────\n\nexport type RetentionZone = 'active' | 'stale' | 'archive-candidate';\n\n/**\n * Classify an observation into a retention zone.\n *\n * Lifecycle (from MemCP):\n * Active: recently accessed or high importance\n * Stale: not accessed, beyond 50% of retention period\n * Archive-candidate: not accessed, beyond 100% of retention period, not immune\n */\nexport function getRetentionZone(doc: MemorixDocument, referenceTime?: Date): RetentionZone {\n const now = referenceTime ?? new Date();\n const importance = getImportanceLevel(doc);\n const retention = getEffectiveRetentionDays(doc);\n\n const createdAt = new Date(doc.createdAt);\n const ageDays = (now.getTime() - createdAt.getTime()) / (1000 * 60 * 60 * 24);\n\n // Recently accessed = active regardless of age\n if (doc.lastAccessedAt) {\n const lastAccess = new Date(doc.lastAccessedAt);\n const daysSinceAccess = (now.getTime() - lastAccess.getTime()) / (1000 * 60 * 60 * 24);\n if (daysSinceAccess < 7) return 'active';\n }\n\n if (isImmune(doc)) return 'active';\n if (ageDays > retention) return 'archive-candidate';\n if (ageDays > retention * 0.5) return 'stale';\n return 'active';\n}\n\n/**\n * Get archive candidates from a list of observations.\n * Returns observations that are beyond their retention period and not immune.\n */\nexport function getArchiveCandidates(\n docs: MemorixDocument[],\n referenceTime?: Date,\n): MemorixDocument[] {\n return docs.filter((doc) => getRetentionZone(doc, referenceTime) === 'archive-candidate');\n}\n\n/**\n * Get retention summary statistics.\n */\nexport function getRetentionSummary(\n docs: MemorixDocument[],\n referenceTime?: Date,\n): { active: number; stale: number; archiveCandidates: number; immune: number } {\n let active = 0;\n let stale = 0;\n let archiveCandidates = 0;\n let immune = 0;\n\n for (const doc of docs) {\n const zone = getRetentionZone(doc, referenceTime);\n if (zone === 'active') active++;\n else if (zone === 'stale') stale++;\n else archiveCandidates++;\n if (isImmune(doc)) immune++;\n }\n\n return { active, stale, archiveCandidates, immune };\n}\n\n// ── Retention Explainability ─────────────────────────────────────────\n\nexport interface RetentionExplanation {\n observationId: number;\n importanceLevel: ImportanceLevel;\n baseRetentionDays: number;\n sourceMultiplier: number;\n valueCategoryMultiplier: number;\n effectiveRetentionDays: number;\n zone: RetentionZone;\n immune: boolean;\n /** Human-readable reason for immunity, or null when not immune. */\n immunityReason: string | null;\n ageDays: number;\n /** Short human-readable summary of the retention posture. */\n summary: string;\n}\n\n/**\n * Produce a structured explanation of why an observation has its current\n * retention posture. Designed for operator-facing reporting.\n */\nexport function explainRetention(\n doc: MemorixDocument,\n referenceTime?: Date,\n): RetentionExplanation {\n const importance = getImportanceLevel(doc);\n const baseRetention = RETENTION_DAYS[importance];\n const srcMul = getSourceRetentionMultiplier(doc);\n const vcMul = getValueCategoryMultiplier(doc);\n const effective = getEffectiveRetentionDays(doc);\n const zone = getRetentionZone(doc, referenceTime);\n const immuneFlag = isImmune(doc);\n const immunityReason = getImmunityReason(doc);\n\n const now = referenceTime ?? new Date();\n const ageDays = Math.max(\n 0,\n (now.getTime() - new Date(doc.createdAt).getTime()) / (1000 * 60 * 60 * 24),\n );\n\n // Build a concise human-readable summary\n const parts: string[] = [];\n parts.push(`${importance} importance (${baseRetention}d base)`);\n if (srcMul !== 1.0) parts.push(`source ${srcMul}×`);\n if (vcMul !== 1.0) parts.push(`valueCategory ${vcMul}×`);\n parts.push(`→ ${effective}d effective`);\n if (immuneFlag) {\n parts.push(`immune: ${immunityReason}`);\n } else {\n parts.push(`zone: ${zone}`);\n }\n\n return {\n observationId: doc.observationId,\n importanceLevel: importance,\n baseRetentionDays: baseRetention,\n sourceMultiplier: srcMul,\n valueCategoryMultiplier: vcMul,\n effectiveRetentionDays: effective,\n zone,\n immune: immuneFlag,\n immunityReason,\n ageDays: Math.round(ageDays),\n // Summary is rendered inside markdown table cells in memorix_retention output,\n // so avoid pipe separators that would split the row into extra columns.\n summary: parts.join(' ; '),\n };\n}\n\n// ── Auto-Archive ────────────────────────────────────────────────────\n\nexport interface ArchiveExpiredBatchOptions {\n projectId: string;\n afterId?: number;\n limit?: number;\n referenceTime?: Date;\n accessMap?: Map<number, { accessCount: number; lastAccessedAt: string }>;\n /** Omit only for trusted background maintenance. */\n reader?: ObservationReader;\n}\n\nexport interface ArchiveExpiredBatchResult {\n archived: number;\n scanned: number;\n nextCursor?: number;\n}\n\nfunction toRetentionDocument(\n obs: Observation,\n accessMap?: Map<number, { accessCount: number; lastAccessedAt: string }>,\n): MemorixDocument {\n const access = accessMap?.get(obs.id);\n return {\n id: `obs-${obs.id}`,\n observationId: obs.id,\n entityName: obs.entityName,\n type: obs.type,\n title: obs.title,\n narrative: obs.narrative,\n facts: obs.facts.join('\\n'),\n filesModified: obs.filesModified.join('\\n'),\n concepts: obs.concepts.join(', '),\n tokens: obs.tokens,\n createdAt: obs.createdAt,\n projectId: obs.projectId,\n accessCount: access?.accessCount ?? 0,\n lastAccessedAt: access?.lastAccessedAt ?? '',\n status: obs.status ?? 'active',\n source: obs.source ?? 'agent',\n sourceDetail: obs.sourceDetail ?? '',\n valueCategory: obs.valueCategory ?? '',\n admissionState: obs.admissionState ?? '',\n admissionReason: obs.admissionReason ?? '',\n };\n}\n\n/**\n * Archive one bounded page of a project's active memories. The caller owns the\n * cursor, which makes the operation safe to run from a durable maintenance job.\n */\nexport async function archiveExpiredBatch(\n _projectDir: string,\n options: ArchiveExpiredBatchOptions,\n): Promise<ArchiveExpiredBatchResult> {\n const store = getObservationStore();\n const limit = Math.min(500, Math.max(1, Math.floor(options.limit ?? 100)));\n const afterId = Math.max(0, Math.floor(options.afterId ?? 0));\n const page = await store.loadByProject(options.projectId, {\n status: 'active',\n afterId,\n limit: limit + 1,\n });\n const hasMore = page.length > limit;\n const scanned = hasMore ? page.slice(0, limit) : page;\n const candidateIds = scanned\n .filter((observation) => !options.reader || canManageObservation(observation, options.reader))\n .filter((observation) => getRetentionZone(\n toRetentionDocument(observation, options.accessMap),\n options.referenceTime,\n ) === 'archive-candidate')\n .map((observation) => observation.id);\n\n const archived = candidateIds.length === 0\n ? 0\n : await store.atomic(async (tx) => {\n const updates = await Promise.all(\n candidateIds.map((id) => tx.setStatus(id, 'archived', 'active')),\n );\n return updates.filter(Boolean).length;\n });\n\n const nextCursor = hasMore && scanned.length > 0\n ? scanned[scanned.length - 1].id\n : undefined;\n return nextCursor === undefined\n ? { archived, scanned: scanned.length }\n : { archived, scanned: scanned.length, nextCursor };\n}\n\n/**\n * Archive expired observations by setting status='archived' in-place.\n *\n * Phase 2 change: instead of moving observations to a separate\n * observations.archived.json file, we update their status in the\n * canonical store (SQLite or JSON). This eliminates the separate\n * archive file and keeps all observation data in one place.\n *\n * Returns the count of archived observations.\n */\nexport async function archiveExpired(\n projectDir: string,\n referenceTime?: Date,\n accessMap?: Map<number, { accessCount: number; lastAccessedAt: string }>,\n projectId?: string,\n reader?: ObservationReader,\n): Promise<{ archived: number; remaining: number }> {\n const store = getObservationStore();\n if (projectId) {\n let afterId: number | undefined;\n let archived = 0;\n do {\n const batch = await archiveExpiredBatch(projectDir, {\n projectId,\n afterId,\n referenceTime,\n accessMap,\n reader,\n });\n archived += batch.archived;\n afterId = batch.nextCursor;\n } while (afterId !== undefined);\n\n const remainingObservations = await store.loadByProject(projectId, { status: 'active' });\n const remaining = reader\n ? remainingObservations.filter((observation) => canManageObservation(observation, reader)).length\n : remainingObservations.length;\n return { archived, remaining };\n }\n\n return await store.atomic(async (tx) => {\n const allObs = await tx.loadAll();\n\n // Only consider active observations for archiving\n const activeObs = allObs.filter((observation) =>\n (observation.status ?? 'active') === 'active' &&\n (!projectId || observation.projectId === projectId),\n );\n const archivedIds: number[] = [];\n\n for (const obs of activeObs) {\n const doc = toRetentionDocument(obs, accessMap);\n const zone = getRetentionZone(doc, referenceTime);\n if (zone === 'archive-candidate') {\n archivedIds.push(obs.id);\n }\n }\n\n if (archivedIds.length === 0) {\n return { archived: 0, remaining: activeObs.length };\n }\n\n const updates = await Promise.all(archivedIds.map((id) => tx.setStatus(id, 'archived', 'active')));\n const archived = updates.filter(Boolean).length;\n\n return { archived, remaining: activeObs.length - archived };\n });\n}\n","import { execFile } from 'node:child_process';\nimport { createHash } from 'node:crypto';\nimport { promisify } from 'node:util';\nimport type {\n CodeGraphProviderKind,\n CodeStateScanCompleteness,\n CodeStateSnapshotInput,\n CodeStateWorktreeState,\n} from './types.js';\n\nconst execFileAsync = promisify(execFile);\nconst GIT_TIMEOUT_MS = 3_000;\nconst GIT_MAX_BUFFER_BYTES = 256 * 1024;\n\ninterface GitResult {\n ok: boolean;\n output: Buffer;\n}\n\nasync function runGit(rootPath: string, args: string[]): Promise<GitResult> {\n try {\n const result = await execFileAsync('git', ['-C', rootPath, ...args], {\n encoding: 'buffer',\n windowsHide: true,\n timeout: GIT_TIMEOUT_MS,\n maxBuffer: GIT_MAX_BUFFER_BYTES,\n });\n const output = Buffer.isBuffer(result.stdout)\n ? result.stdout\n : Buffer.from(result.stdout ?? '');\n return { ok: true, output };\n } catch {\n return { ok: false, output: Buffer.alloc(0) };\n }\n}\n\nfunction changedPathCount(status: Buffer): number {\n const entries = status.toString('utf8').split('\\0');\n let count = 0;\n for (let index = 0; index < entries.length; index++) {\n const entry = entries[index];\n if (!entry) continue;\n count++;\n const code = entry.slice(0, 2);\n if (code.includes('R') || code.includes('C')) index++;\n }\n return count;\n}\n\nfunction fingerprint(baseRevision: string | undefined, status: Buffer): string {\n return createHash('sha256')\n .update(baseRevision ?? '')\n .update('\\0')\n .update(status)\n .digest('hex');\n}\n\nexport interface CollectCodeStateInput {\n projectId: string;\n projectRoot: string;\n provider: CodeGraphProviderKind;\n indexedAt: string;\n completeness: CodeStateScanCompleteness;\n}\n\n/**\n * Capture bounded Git metadata for a completed scan. No source file contents\n * are copied into the snapshot, and an unavailable Git executable is explicit\n * instead of being treated as a clean worktree.\n */\nexport async function collectCodeStateSnapshot(\n input: CollectCodeStateInput,\n): Promise<CodeStateSnapshotInput> {\n const [revision, status] = await Promise.all([\n runGit(input.projectRoot, ['rev-parse', 'HEAD']),\n runGit(input.projectRoot, ['status', '--porcelain=v1', '-z', '--untracked-files=normal']),\n ]);\n const baseRevision = revision.ok\n ? revision.output.toString('utf8').trim() || undefined\n : undefined;\n const worktreeState: CodeStateWorktreeState = status.ok\n ? (status.output.length > 0 ? 'dirty' : 'clean')\n : 'unavailable';\n\n return {\n projectId: input.projectId,\n provider: input.provider,\n ...(baseRevision ? { baseRevision } : {}),\n worktreeFingerprint: fingerprint(baseRevision, status.ok ? status.output : Buffer.alloc(0)),\n worktreeState,\n changedPathCount: status.ok ? changedPathCount(status.output) : 0,\n indexedAt: input.indexedAt,\n completeness: input.completeness,\n };\n}\n","export const DEFAULT_CODEGRAPH_EXCLUDES = [\n 'node_modules/**',\n 'dist/**',\n 'build/**',\n 'coverage/**',\n '.next/**',\n '.turbo/**',\n '.git/**',\n '.tmp/**',\n '.worktrees/**',\n '.claude/worktrees/**',\n 'vendor/**',\n '.venv/**',\n 'venv/**',\n '.tox/**',\n 'target/**',\n '.gradle/**',\n '.mvn/**',\n 'obj/**',\n 'Pods/**',\n 'DerivedData/**',\n];\n\nexport function normalizeCodeGraphExcludePatterns(exclude?: string[]): string[] {\n return [...new Set([\n ...DEFAULT_CODEGRAPH_EXCLUDES,\n ...(exclude ?? []).map(pattern => pattern.trim()).filter(Boolean),\n ])];\n}\n\nexport function isCodeGraphExcludedPath(path: string, exclude?: string[]): boolean {\n const normalized = normalizeCodePath(path);\n return normalizeCodeGraphExcludePatterns(exclude).some((pattern) => matchesPattern(normalized, normalizeCodePath(pattern)));\n}\n\nfunction normalizeCodePath(path: string): string {\n return path.replace(/\\\\/g, '/').replace(/^\\.\\/+/, '');\n}\n\nfunction matchesPattern(path: string, pattern: string): boolean {\n if (pattern.endsWith('/**')) {\n const base = pattern.slice(0, -3);\n if (base.startsWith('**/')) {\n const suffix = base.slice(3);\n return path === suffix || path.endsWith(`/${suffix}`) || path.includes(`/${suffix}/`);\n }\n if (!base.includes('/')) {\n return path === base || path.startsWith(`${base}/`) || path.includes(`/${base}/`);\n }\n return path === base || path.startsWith(`${base}/`);\n }\n if (pattern.startsWith('**/')) {\n const suffix = pattern.slice(3);\n return path === suffix || path.endsWith(`/${suffix}`);\n }\n return path === pattern || path.startsWith(`${pattern}/`);\n}\n","import { createHash } from 'node:crypto';\nimport { readdirSync, readFileSync, statSync, type Dirent } from 'node:fs';\nimport { join, relative } from 'node:path';\nimport type { CodeEdge, CodeFile, CodeStateSnapshot, CodeSymbol } from './types.js';\nimport { collectCodeStateSnapshot } from './code-state.js';\nimport { makeCodeEdgeId, makeCodeFileId, makeCodeSymbolId, normalizeCodePath } from './ids.js';\nimport { isCodeGraphExcludedPath, normalizeCodeGraphExcludePatterns } from './exclude.js';\nimport { CodeGraphStore, type CodeGraphFileDelta } from './store.js';\n\nexport interface LiteIndexOptions {\n projectId: string;\n projectRoot: string;\n exclude?: string[];\n maxFiles?: number;\n maxFileBytes?: number;\n}\n\nexport interface LiteIndexResult {\n files: CodeFile[];\n symbols: CodeSymbol[];\n edges: CodeEdge[];\n skippedOversizedFiles: number;\n unreadableFiles: number;\n}\n\nexport interface LiteRefreshResult {\n scannedFiles: number;\n changedFiles: number;\n unchangedFiles: number;\n metadataOnlyFiles: number;\n removedFiles: number;\n indexedSymbols: number;\n indexedEdges: number;\n skippedOversizedFiles: number;\n unreadableFiles: number;\n removalScanDeferred: boolean;\n snapshot: CodeStateSnapshot;\n}\n\nexport const DEFAULT_CODEGRAPH_MAX_FILE_BYTES = 2 * 1024 * 1024;\n\nconst LANGUAGE_BY_EXTENSION = new Map<string, string>([\n ['.ts', 'typescript'],\n ['.tsx', 'typescript'],\n ['.js', 'javascript'],\n ['.jsx', 'javascript'],\n ['.mjs', 'javascript'],\n ['.cjs', 'javascript'],\n ['.py', 'python'],\n ['.go', 'go'],\n ['.rs', 'rust'],\n ['.java', 'java'],\n ['.cs', 'csharp'],\n ['.c', 'c'],\n ['.h', 'c'],\n ['.cpp', 'cpp'],\n ['.cc', 'cpp'],\n ['.cxx', 'cpp'],\n ['.hpp', 'cpp'],\n ['.hh', 'cpp'],\n ['.hxx', 'cpp'],\n ['.php', 'php'],\n ['.rb', 'ruby'],\n ['.kt', 'kotlin'],\n ['.kts', 'kotlin'],\n]);\n\nconst SUPPORTED_EXTENSIONS = new Set(LANGUAGE_BY_EXTENSION.keys());\n\ninterface SymbolPattern {\n kind: CodeSymbol['kind'];\n re: RegExp;\n}\n\ninterface LanguageProfile {\n symbols: SymbolPattern[];\n imports: RegExp[];\n}\n\nconst identifier = String.raw`([A-Za-z_$][\\w$]*)`;\nconst languageProfiles: Record<string, LanguageProfile> = {\n typescript: {\n symbols: [\n { kind: 'function', re: new RegExp(String.raw`(?:export\\s+)?(?:async\\s+)?function\\s+${identifier}\\s*\\([^)]*\\)`, 'g') },\n { kind: 'class', re: new RegExp(String.raw`(?:export\\s+)?class\\s+${identifier}\\b`, 'g') },\n { kind: 'interface', re: new RegExp(String.raw`(?:export\\s+)?interface\\s+${identifier}\\b`, 'g') },\n { kind: 'type', re: new RegExp(String.raw`(?:export\\s+)?type\\s+${identifier}\\b`, 'g') },\n { kind: 'constant', re: new RegExp(String.raw`(?:export\\s+)?const\\s+${identifier}\\s*=`, 'g') },\n ],\n imports: [/import\\s+(?:[^'\"]+\\s+from\\s+)?['\"]([^'\"]+)['\"]/g],\n },\n javascript: {\n symbols: [\n { kind: 'function', re: new RegExp(String.raw`(?:export\\s+)?(?:async\\s+)?function\\s+${identifier}\\s*\\([^)]*\\)`, 'g') },\n { kind: 'class', re: new RegExp(String.raw`(?:export\\s+)?class\\s+${identifier}\\b`, 'g') },\n { kind: 'constant', re: new RegExp(String.raw`(?:export\\s+)?const\\s+${identifier}\\s*=`, 'g') },\n ],\n imports: [/import\\s+(?:[^'\"]+\\s+from\\s+)?['\"]([^'\"]+)['\"]/g, /require\\(['\"]([^'\"]+)['\"]\\)/g],\n },\n python: {\n symbols: [\n { kind: 'class', re: /^class\\s+([A-Za-z_][\\w]*)\\b/gm },\n { kind: 'function', re: /^def\\s+([A-Za-z_][\\w]*)\\s*\\(/gm },\n { kind: 'function', re: /^async\\s+def\\s+([A-Za-z_][\\w]*)\\s*\\(/gm },\n ],\n imports: [/^import\\s+([A-Za-z_][\\w.]*)(?:\\s+as\\s+\\w+)?/gm, /^from\\s+([A-Za-z_][\\w.]*)\\s+import\\s+/gm],\n },\n go: {\n symbols: [\n { kind: 'function', re: /^func\\s+(?:\\([^)]+\\)\\s*)?([A-Za-z_][\\w]*)\\s*\\(/gm },\n { kind: 'type', re: /^type\\s+([A-Za-z_][\\w]*)\\s+(?:struct|interface)\\b/gm },\n ],\n imports: [/import\\s+\"([^\"]+)\"/g, /import\\s*\\(([\\s\\S]*?)\\)/g],\n },\n rust: {\n symbols: [\n { kind: 'function', re: /(?:pub\\s+)?fn\\s+([A-Za-z_][\\w]*)\\s*\\(/g },\n { kind: 'class', re: /(?:pub\\s+)?struct\\s+([A-Za-z_][\\w]*)\\b/g },\n { kind: 'type', re: /(?:pub\\s+)?enum\\s+([A-Za-z_][\\w]*)\\b/g },\n { kind: 'interface', re: /(?:pub\\s+)?trait\\s+([A-Za-z_][\\w]*)\\b/g },\n ],\n imports: [/use\\s+([^;]+);/g],\n },\n java: {\n symbols: [\n { kind: 'class', re: /\\b(?:public|private|protected)?\\s*(?:abstract\\s+|final\\s+)?class\\s+([A-Za-z_][\\w]*)\\b/g },\n { kind: 'interface', re: /\\b(?:public|private|protected)?\\s*interface\\s+([A-Za-z_][\\w]*)\\b/g },\n { kind: 'method', re: /\\b(?:public|private|protected)\\s+(?:static\\s+)?(?:final\\s+)?[A-Za-z_<>\\[\\], ?]+\\s+([A-Za-z_][\\w]*)\\s*\\([^)]*\\)\\s*\\{/g },\n ],\n imports: [/import\\s+([^;]+);/g],\n },\n csharp: {\n symbols: [\n { kind: 'class', re: /\\b(?:public|private|protected|internal)?\\s*(?:abstract\\s+|sealed\\s+|static\\s+)?class\\s+([A-Za-z_][\\w]*)\\b/g },\n { kind: 'interface', re: /\\b(?:public|private|protected|internal)?\\s*interface\\s+([A-Za-z_][\\w]*)\\b/g },\n { kind: 'method', re: /\\b(?:public|private|protected|internal)\\s+(?:static\\s+)?[A-Za-z_<>\\[\\], ?]+\\s+([A-Za-z_][\\w]*)\\s*\\([^)]*\\)\\s*\\{/g },\n ],\n imports: [/using\\s+([^;]+);/g],\n },\n c: {\n symbols: [\n { kind: 'type', re: /\\bstruct\\s+([A-Za-z_][\\w]*)\\b/g },\n { kind: 'function', re: /^(?:[A-Za-z_][\\w]*\\s+)+([A-Za-z_][\\w]*)\\s*\\([^;{}]*\\)\\s*\\{/gm },\n ],\n imports: [/#include\\s+[<\"]([^>\"]+)[>\"]/g],\n },\n cpp: {\n symbols: [\n { kind: 'class', re: /\\bclass\\s+([A-Za-z_][\\w]*)\\b/g },\n { kind: 'type', re: /\\bstruct\\s+([A-Za-z_][\\w]*)\\b/g },\n { kind: 'function', re: /^(?:[A-Za-z_:][\\w:<>,~*&\\s]*\\s+)+([A-Za-z_][\\w]*)\\s*\\([^;{}]*\\)\\s*\\{/gm },\n ],\n imports: [/#include\\s+[<\"]([^>\"]+)[>\"]/g],\n },\n php: {\n symbols: [\n { kind: 'class', re: /\\bclass\\s+([A-Za-z_][\\w]*)\\b/g },\n { kind: 'interface', re: /\\binterface\\s+([A-Za-z_][\\w]*)\\b/g },\n { kind: 'function', re: /\\bfunction\\s+([A-Za-z_][\\w]*)\\s*\\(/g },\n ],\n imports: [/(?:require|include)(?:_once)?\\s*\\(?\\s*['\"]([^'\"]+)['\"]/g],\n },\n ruby: {\n symbols: [\n { kind: 'class', re: /^class\\s+([A-Za-z_][\\w]*(?:::[A-Za-z_][\\w]*)*)/gm },\n { kind: 'function', re: /^def\\s+([A-Za-z_][\\w]*[!?=]?)/gm },\n ],\n imports: [/require\\s+['\"]([^'\"]+)['\"]/g],\n },\n kotlin: {\n symbols: [\n { kind: 'class', re: /\\bclass\\s+([A-Za-z_][\\w]*)\\b/g },\n { kind: 'interface', re: /\\binterface\\s+([A-Za-z_][\\w]*)\\b/g },\n { kind: 'function', re: /\\bfun\\s+([A-Za-z_][\\w]*)\\s*\\(/g },\n ],\n imports: [/import\\s+([A-Za-z_][\\w.]+)/g],\n },\n};\n\nfunction hashText(text: string): string {\n return createHash('sha256').update(text).digest('hex');\n}\n\nfunction extension(path: string): string {\n const index = path.lastIndexOf('.');\n return index === -1 ? '' : path.slice(index);\n}\n\nfunction languageForPath(path: string): string {\n const ext = extension(path);\n return LANGUAGE_BY_EXTENSION.get(ext) ?? 'unknown';\n}\n\nfunction resolveMaxFileBytes(value: number | undefined): number {\n if (!Number.isFinite(value)) return DEFAULT_CODEGRAPH_MAX_FILE_BYTES;\n return Math.max(1, Math.floor(value!));\n}\n\nfunction walk(root: string, exclude: string[], maxFiles: number): string[] {\n const out: string[] = [];\n const visit = (dir: string) => {\n if (out.length >= maxFiles) return;\n let entries: Dirent<string>[];\n try {\n entries = readdirSync(dir, { withFileTypes: true });\n } catch {\n return;\n }\n\n for (const entry of entries) {\n const abs = join(dir, entry.name);\n const rel = normalizeCodePath(relative(root, abs));\n if (isCodeGraphExcludedPath(rel, exclude)) continue;\n if (entry.isDirectory()) {\n if (entry.name === '.git' || entry.name === '.worktrees' || entry.name === '.tmp' || entry.name === 'node_modules') continue;\n if (rel === '.claude/worktrees' || rel.startsWith('.claude/worktrees/')) continue;\n visit(abs);\n if (out.length >= maxFiles) return;\n continue;\n }\n if (!entry.isFile()) continue;\n if (!SUPPORTED_EXTENSIONS.has(extension(entry.name))) continue;\n out.push(abs);\n if (out.length >= maxFiles) return;\n }\n };\n visit(root);\n return out;\n}\n\nfunction lineOf(text: string, index: number): number {\n return text.slice(0, index).split(/\\r?\\n/).length;\n}\n\nfunction extractSymbols(projectId: string, file: CodeFile, text: string, indexedAt: string): CodeSymbol[] {\n const symbols: CodeSymbol[] = [];\n const profile = file.language ? languageProfiles[file.language] : undefined;\n const patterns = profile?.symbols ?? [];\n\n for (const { kind, re } of patterns) {\n re.lastIndex = 0;\n for (const match of text.matchAll(re)) {\n const name = match[1];\n if (!name || name.includes('\\n')) continue;\n const startLine = lineOf(text, match.index ?? 0);\n const id = makeCodeSymbolId({ projectId, path: file.path, qualifiedName: name, kind });\n symbols.push({\n id,\n projectId,\n fileId: file.id,\n path: file.path,\n name,\n qualifiedName: name,\n kind,\n startLine,\n endLine: startLine,\n signature: match[0].slice(0, 160),\n contentHash: hashText(match[0]),\n indexedAt,\n });\n }\n }\n return symbols;\n}\n\nfunction extractImportEdges(projectId: string, file: CodeFile, text: string, indexedAt: string): CodeEdge[] {\n const edges: CodeEdge[] = [];\n const profile = file.language ? languageProfiles[file.language] : undefined;\n const imports = profile?.imports ?? [];\n\n for (const re of imports) {\n re.lastIndex = 0;\n for (const match of text.matchAll(re)) {\n const target = (match[1] ?? '').trim();\n if (!target) continue;\n if (target.includes('\\n')) {\n for (const line of target.split(/\\r?\\n/).map(item => item.trim().replace(/^\"|\"$/g, '')).filter(Boolean)) {\n const id = makeCodeEdgeId(projectId, file.id, 'imports', line);\n edges.push({\n id,\n projectId,\n fromFileId: file.id,\n type: 'imports',\n confidence: 0.7,\n evidence: line,\n indexedAt,\n });\n }\n continue;\n }\n const id = makeCodeEdgeId(projectId, file.id, 'imports', target);\n edges.push({\n id,\n projectId,\n fromFileId: file.id,\n type: 'imports',\n confidence: 0.7,\n evidence: target,\n indexedAt,\n });\n }\n }\n return edges;\n}\n\ninterface LiteFileIndexAttempt {\n delta?: CodeGraphFileDelta;\n unreadable: boolean;\n}\n\nfunction indexFileLite(\n projectId: string,\n projectRoot: string,\n abs: string,\n indexedAt: string,\n fileStat?: ReturnType<typeof statSync>,\n): LiteFileIndexAttempt {\n const rel = normalizeCodePath(relative(projectRoot, abs));\n try {\n const text = readFileSync(abs, 'utf-8');\n const stat = fileStat ?? statSync(abs);\n const file: CodeFile = {\n id: makeCodeFileId(projectId, rel),\n projectId,\n path: rel,\n language: languageForPath(rel),\n contentHash: hashText(text),\n // Preserve filesystem precision. Rounding here made same-size edits in\n // a short Windows timestamp window indistinguishable to refresh.\n mtimeMs: Number(stat.mtimeMs),\n sizeBytes: Number(stat.size),\n indexedAt,\n };\n return {\n delta: {\n file,\n symbols: extractSymbols(projectId, file, text, indexedAt),\n edges: extractImportEdges(projectId, file, text, indexedAt),\n },\n unreadable: false,\n };\n } catch {\n return { unreadable: true };\n }\n}\n\nexport async function indexProjectLite(options: LiteIndexOptions): Promise<LiteIndexResult> {\n const exclude = normalizeCodeGraphExcludePatterns(options.exclude);\n const maxFiles = options.maxFiles ?? 5000;\n const maxFileBytes = resolveMaxFileBytes(options.maxFileBytes);\n const indexedAt = new Date().toISOString();\n const paths = walk(options.projectRoot, exclude, maxFiles);\n const files: CodeFile[] = [];\n const symbols: CodeSymbol[] = [];\n const edges: CodeEdge[] = [];\n let skippedOversizedFiles = 0;\n let unreadableFiles = 0;\n\n for (const abs of paths) {\n let stat: ReturnType<typeof statSync>;\n try {\n stat = statSync(abs);\n } catch {\n unreadableFiles++;\n continue;\n }\n if (Number(stat.size) > maxFileBytes) {\n skippedOversizedFiles++;\n continue;\n }\n const attempt = indexFileLite(options.projectId, options.projectRoot, abs, indexedAt, stat);\n if (!attempt.delta) {\n if (attempt.unreadable) unreadableFiles++;\n continue;\n }\n files.push(attempt.delta.file);\n symbols.push(...attempt.delta.symbols);\n edges.push(...attempt.delta.edges);\n }\n\n return { files, symbols, edges, skippedOversizedFiles, unreadableFiles };\n}\n\n/**\n * Refresh the Lite graph incrementally. A directory walk is still necessary to\n * discover deletes, but unchanged files are not read, hashed, or reparsed.\n */\nexport async function refreshProjectLite(\n store: CodeGraphStore,\n options: LiteIndexOptions,\n): Promise<LiteRefreshResult> {\n const exclude = normalizeCodeGraphExcludePatterns(options.exclude);\n const maxFiles = options.maxFiles ?? 5000;\n const maxFileBytes = resolveMaxFileBytes(options.maxFileBytes);\n const indexedAt = new Date().toISOString();\n const paths = walk(options.projectRoot, exclude, maxFiles);\n const existingByPath = new Map(store.listFiles(options.projectId).map((file) => [file.path, file]));\n const changed: CodeGraphFileDelta[] = [];\n const metadataOnly: CodeFile[] = [];\n const seenPaths = new Set<string>();\n const oversizedExistingFileIds = new Set<string>();\n let unchangedFiles = 0;\n let skippedOversizedFiles = 0;\n let unreadableFiles = 0;\n\n for (const abs of paths) {\n const rel = normalizeCodePath(relative(options.projectRoot, abs));\n // A discovered but temporarily unreadable path is not deletion evidence.\n seenPaths.add(rel);\n let stat: ReturnType<typeof statSync>;\n try {\n stat = statSync(abs);\n } catch {\n unreadableFiles++;\n continue;\n }\n const existing = existingByPath.get(rel);\n const mtimeMs = Number(stat.mtimeMs);\n const sizeBytes = Number(stat.size);\n if (sizeBytes > maxFileBytes) {\n skippedOversizedFiles++;\n if (existing) oversizedExistingFileIds.add(existing.id);\n continue;\n }\n if (existing && existing.mtimeMs === mtimeMs && existing.sizeBytes === sizeBytes) {\n unchangedFiles++;\n continue;\n }\n\n const attempt = indexFileLite(options.projectId, options.projectRoot, abs, indexedAt, stat);\n if (!attempt.delta) {\n if (attempt.unreadable) unreadableFiles++;\n continue;\n }\n const delta = attempt.delta;\n if (existing?.contentHash === delta.file.contentHash) {\n metadataOnly.push(delta.file);\n unchangedFiles++;\n } else {\n changed.push(delta);\n }\n }\n\n // At the file cap, absence from this partial walk is not proof of deletion.\n const removalScanDeferred = paths.length >= maxFiles;\n const removedFileIds = [...new Set([\n ...oversizedExistingFileIds,\n ...(removalScanDeferred\n ? []\n : [...existingByPath.values()]\n .filter((file) => !seenPaths.has(file.path))\n .map((file) => file.id)),\n ])];\n store.applyFileDeltas(options.projectId, {\n changed,\n metadataOnly,\n removedFileIds,\n });\n const completeness = {\n scannedFiles: paths.length,\n maxFiles,\n changedFiles: changed.length,\n unchangedFiles,\n metadataOnlyFiles: metadataOnly.length,\n removedFiles: removedFileIds.length,\n skippedOversizedFiles,\n unreadableFiles,\n removalScanDeferred,\n };\n const snapshot = store.recordCodeStateSnapshot(await collectCodeStateSnapshot({\n projectId: options.projectId,\n projectRoot: options.projectRoot,\n provider: 'lite',\n indexedAt,\n completeness,\n }));\n return {\n scannedFiles: paths.length,\n changedFiles: changed.length,\n unchangedFiles,\n metadataOnlyFiles: metadataOnly.length,\n removedFiles: removedFileIds.length,\n indexedSymbols: changed.reduce((total, delta) => total + delta.symbols.length, 0),\n indexedEdges: changed.reduce((total, delta) => total + delta.edges.length, 0),\n skippedOversizedFiles,\n unreadableFiles,\n removalScanDeferred,\n snapshot,\n };\n}\n","import { createHash, randomUUID } from 'node:crypto';\nimport { sanitizeCredentials } from '../memory/secret-filter.js';\nimport { getDatabase } from '../store/sqlite-db.js';\nimport type {\n ClaimConflict,\n ClaimEvent,\n ClaimEvidenceRef,\n KnowledgeClaim,\n KnowledgeClaimStatus,\n} from './types.js';\n\nfunction optionalText(value: unknown): string | undefined {\n return typeof value === 'string' && value ? value : undefined;\n}\n\nfunction rowToClaim(row: any): KnowledgeClaim {\n return {\n id: row.id,\n projectId: row.projectId,\n subject: row.subject,\n predicate: row.predicate,\n objectValue: row.objectValue,\n scope: row.scope,\n claimKey: row.claimKey,\n conflictKey: row.conflictKey,\n status: row.status,\n confidence: Number(row.confidence),\n observedAt: row.observedAt,\n ...(optionalText(row.validFrom) ? { validFrom: row.validFrom } : {}),\n ...(optionalText(row.validTo) ? { validTo: row.validTo } : {}),\n ...(optionalText(row.supersededBy) ? { supersededBy: row.supersededBy } : {}),\n reviewState: row.reviewState,\n origin: row.origin,\n createdAt: row.createdAt,\n updatedAt: row.updatedAt,\n };\n}\n\nfunction rowToEvidence(row: any): ClaimEvidenceRef {\n return {\n id: row.id,\n claimId: row.claimId,\n evidenceKind: row.evidenceKind,\n evidenceId: row.evidenceId,\n relation: row.relation,\n ...(optionalText(row.snapshotId) ? { snapshotId: row.snapshotId } : {}),\n ...(optionalText(row.locator) ? { locator: row.locator } : {}),\n ...(optionalText(row.capturedHash) ? { capturedHash: row.capturedHash } : {}),\n createdAt: row.createdAt,\n };\n}\n\nfunction rowToEvent(row: any): ClaimEvent {\n return {\n id: row.id,\n projectId: row.projectId,\n claimId: row.claimId,\n kind: row.kind,\n ...(optionalText(row.fromStatus) ? { fromStatus: row.fromStatus } : {}),\n ...(optionalText(row.toStatus) ? { toStatus: row.toStatus } : {}),\n ...(optionalText(row.relatedClaimId) ? { relatedClaimId: row.relatedClaimId } : {}),\n ...(optionalText(row.detail) ? { detail: row.detail } : {}),\n createdAt: row.createdAt,\n };\n}\n\nfunction evidenceKey(input: Omit<ClaimEvidenceRef, 'id' | 'claimId' | 'createdAt'>): string {\n return createHash('sha256').update(JSON.stringify([\n input.evidenceKind,\n input.evidenceId,\n input.relation,\n input.snapshotId ?? '',\n input.locator ?? '',\n input.capturedHash ?? '',\n ])).digest('hex');\n}\n\n/**\n * SQLite access for the claim ledger. Domain policy belongs in claims.ts; this\n * class only preserves records and their audit trail atomically.\n */\nexport class ClaimStore {\n private db: any = null;\n\n async init(dataDir: string): Promise<void> {\n this.db = getDatabase(dataDir);\n }\n\n transaction<T>(fn: () => T): T {\n return this.db.transaction(fn)();\n }\n\n getClaim(id: string): KnowledgeClaim | undefined {\n const row = this.db.prepare('SELECT * FROM knowledge_claims WHERE id = ?').get(id);\n return row ? rowToClaim(row) : undefined;\n }\n\n listClaims(\n projectId: string,\n options: { statuses?: readonly KnowledgeClaimStatus[]; limit?: number } = {},\n ): KnowledgeClaim[] {\n const limit = Math.max(1, Math.min(1_000, Math.floor(options.limit ?? 500)));\n if (options.statuses && options.statuses.length > 0) {\n return this.db.prepare(`\n SELECT * FROM knowledge_claims\n WHERE projectId = ? AND status IN (SELECT value FROM json_each(?))\n ORDER BY updatedAt DESC, id\n LIMIT ?\n `).all(projectId, JSON.stringify([...new Set(options.statuses)]), limit).map(rowToClaim);\n }\n return this.db.prepare(`\n SELECT * FROM knowledge_claims\n WHERE projectId = ?\n ORDER BY updatedAt DESC, id\n LIMIT ?\n `).all(projectId, limit).map(rowToClaim);\n }\n\n findReusableClaim(projectId: string, claimKey: string): KnowledgeClaim | undefined {\n const row = this.db.prepare(`\n SELECT * FROM knowledge_claims\n WHERE projectId = ? AND claimKey = ? AND status IN ('active', 'disputed')\n ORDER BY updatedAt DESC\n LIMIT 1\n `).get(projectId, claimKey);\n return row ? rowToClaim(row) : undefined;\n }\n\n listClaimsByConflictKey(projectId: string, conflictKey: string): KnowledgeClaim[] {\n return this.db.prepare(`\n SELECT * FROM knowledge_claims\n WHERE projectId = ? AND conflictKey = ?\n ORDER BY createdAt ASC, id\n `).all(projectId, conflictKey).map(rowToClaim);\n }\n\n listConflicts(projectId: string): ClaimConflict[] {\n const rows = this.db.prepare(`\n SELECT conflictKey\n FROM knowledge_claims\n WHERE projectId = ? AND status IN ('active', 'disputed') AND reviewState = 'approved'\n GROUP BY conflictKey\n HAVING COUNT(DISTINCT claimKey) > 1\n ORDER BY conflictKey\n `).all(projectId) as Array<{ conflictKey: string }>;\n return rows.map(({ conflictKey }) => ({\n conflictKey,\n claims: this.listClaimsByConflictKey(projectId, conflictKey)\n .filter(claim => claim.status === 'active' || claim.status === 'disputed'),\n }));\n }\n\n insertClaim(claim: KnowledgeClaim): void {\n this.db.prepare(`\n INSERT INTO knowledge_claims (\n id, projectId, subject, predicate, objectValue, scope, claimKey, conflictKey,\n status, confidence, observedAt, validFrom, validTo, supersededBy,\n reviewState, origin, createdAt, updatedAt\n ) VALUES (\n @id, @projectId, @subject, @predicate, @objectValue, @scope, @claimKey, @conflictKey,\n @status, @confidence, @observedAt, @validFrom, @validTo, @supersededBy,\n @reviewState, @origin, @createdAt, @updatedAt\n )\n `).run({\n ...claim,\n validFrom: claim.validFrom ?? null,\n validTo: claim.validTo ?? null,\n supersededBy: claim.supersededBy ?? null,\n });\n }\n\n updateClaim(claim: KnowledgeClaim): void {\n this.db.prepare(`\n UPDATE knowledge_claims SET\n subject = @subject,\n predicate = @predicate,\n objectValue = @objectValue,\n scope = @scope,\n claimKey = @claimKey,\n conflictKey = @conflictKey,\n status = @status,\n confidence = @confidence,\n observedAt = @observedAt,\n validFrom = @validFrom,\n validTo = @validTo,\n supersededBy = @supersededBy,\n reviewState = @reviewState,\n origin = @origin,\n updatedAt = @updatedAt\n WHERE id = @id\n `).run({\n ...claim,\n validFrom: claim.validFrom ?? null,\n validTo: claim.validTo ?? null,\n supersededBy: claim.supersededBy ?? null,\n });\n }\n\n touchClaim(id: string, updatedAt: string): void {\n this.db.prepare('UPDATE knowledge_claims SET updatedAt = ? WHERE id = ?').run(updatedAt, id);\n }\n\n insertEvidence(input: Omit<ClaimEvidenceRef, 'id' | 'createdAt'> & { createdAt?: string }): boolean {\n const createdAt = input.createdAt ?? new Date().toISOString();\n const key = evidenceKey(input);\n const result = this.db.prepare(`\n INSERT OR IGNORE INTO knowledge_claim_evidence (\n id, claimId, evidenceKind, evidenceId, relation, snapshotId,\n locator, capturedHash, evidenceKey, createdAt\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n `).run(\n randomUUID(),\n input.claimId,\n input.evidenceKind,\n input.evidenceId,\n input.relation,\n input.snapshotId ?? null,\n input.locator ? sanitizeCredentials(input.locator) : null,\n input.capturedHash ?? null,\n key,\n createdAt,\n );\n return Number(result.changes ?? 0) > 0;\n }\n\n listEvidence(claimId: string): ClaimEvidenceRef[] {\n return this.db.prepare(`\n SELECT * FROM knowledge_claim_evidence\n WHERE claimId = ?\n ORDER BY createdAt ASC, id\n `).all(claimId).map(rowToEvidence);\n }\n\n recordEvent(input: Omit<ClaimEvent, 'id' | 'createdAt'> & { createdAt?: string }): ClaimEvent {\n const event: ClaimEvent = {\n id: randomUUID(),\n ...input,\n ...(input.detail ? { detail: sanitizeCredentials(input.detail) } : {}),\n createdAt: input.createdAt ?? new Date().toISOString(),\n };\n this.db.prepare(`\n INSERT INTO knowledge_claim_events (\n id, projectId, claimId, kind, fromStatus, toStatus,\n relatedClaimId, detail, createdAt\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)\n `).run(\n event.id,\n event.projectId,\n event.claimId,\n event.kind,\n event.fromStatus ?? null,\n event.toStatus ?? null,\n event.relatedClaimId ?? null,\n event.detail ?? null,\n event.createdAt,\n );\n return event;\n }\n\n listEvents(claimId: string): ClaimEvent[] {\n return this.db.prepare(`\n SELECT * FROM knowledge_claim_events\n WHERE claimId = ?\n ORDER BY createdAt ASC, id\n `).all(claimId).map(rowToEvent);\n }\n}\n","import { createHash, randomUUID } from 'node:crypto';\nimport { countTextTokens } from '../compact/token-budget.js';\nimport type { CodeGraphStore } from '../codegraph/store.js';\nimport type { CodeStateSnapshot, ObservationCodeRef } from '../codegraph/types.js';\nimport { sanitizeCredentials } from '../memory/secret-filter.js';\nimport type { Observation, ObservationType } from '../types.js';\nimport { ClaimStore } from './claim-store.js';\nimport type {\n ClaimConflict,\n ClaimEvidenceInput,\n ClaimEvidenceRef,\n ClaimSelection,\n ClaimWriteResult,\n KnowledgeClaim,\n KnowledgeClaimInput,\n KnowledgeClaimReviewState,\n KnowledgeClaimStatus,\n} from './types.js';\n\nconst MAX_TERM_LENGTH = 2_000;\nconst MAX_EVIDENCE_ID_LENGTH = 1_000;\nconst TOKEN_PATTERN = /[\\p{L}\\p{N}_./:-]+/gu;\n\nconst PREDICATE_BY_OBSERVATION_TYPE: Partial<Record<ObservationType, string>> = {\n decision: 'decision',\n 'trade-off': 'trade-off',\n 'why-it-exists': 'rationale',\n 'what-changed': 'changed',\n 'problem-solution': 'workaround',\n gotcha: 'caution',\n 'how-it-works': 'behavior',\n discovery: 'finding',\n reasoning: 'rationale',\n};\n\nfunction compactText(value: string, field: string): string {\n if (typeof value !== 'string') throw new Error('Claim ' + field + ' must be text');\n const sanitized = sanitizeCredentials(value).trim().replace(/\\s+/g, ' ');\n if (!sanitized) throw new Error('Claim ' + field + ' is required');\n if (sanitized.length > MAX_TERM_LENGTH) throw new Error('Claim ' + field + ' is too long');\n return sanitized;\n}\n\nfunction normalizedTerm(value: string): string {\n return compactText(value, 'identity').toLocaleLowerCase('en-US');\n}\n\nfunction hashIdentity(parts: string[]): string {\n return createHash('sha256').update(parts.join(String.fromCharCode(31))).digest('hex');\n}\n\nexport function buildClaimIdentity(input: Pick<KnowledgeClaimInput, 'subject' | 'predicate' | 'objectValue' | 'scope'>): {\n claimKey: string;\n conflictKey: string;\n} {\n const subject = normalizedTerm(input.subject);\n const predicate = normalizedTerm(input.predicate);\n const objectValue = normalizedTerm(input.objectValue);\n return {\n claimKey: hashIdentity([subject, predicate, objectValue, input.scope]),\n conflictKey: hashIdentity([subject, predicate, input.scope]),\n };\n}\n\nfunction clampConfidence(value: number | undefined): number {\n if (value === undefined) return 0.7;\n if (!Number.isFinite(value) || value < 0 || value > 1) {\n throw new Error('Claim confidence must be a number between 0 and 1');\n }\n return value;\n}\n\nfunction validateEvidence(input: ClaimEvidenceInput[]): ClaimEvidenceInput[] {\n if (!Array.isArray(input) || input.length === 0) {\n throw new Error('A knowledge claim requires at least one evidence reference');\n }\n return input.map((evidence) => {\n if (!evidence || typeof evidence !== 'object') {\n throw new Error('Claim evidence must be an object');\n }\n const evidenceId = compactText(evidence.evidenceId, 'evidence id');\n if (evidenceId.length > MAX_EVIDENCE_ID_LENGTH) {\n throw new Error('Claim evidence id is too long');\n }\n if (!['observation', 'git', 'code', 'test', 'document', 'workflow', 'run'].includes(evidence.evidenceKind)) {\n throw new Error('Claim evidence kind is invalid');\n }\n if (!['supports', 'contradicts', 'derives', 'verifies'].includes(evidence.relation)) {\n throw new Error('Claim evidence relation is invalid');\n }\n return {\n evidenceKind: evidence.evidenceKind,\n evidenceId,\n relation: evidence.relation,\n ...(evidence.snapshotId ? { snapshotId: compactText(evidence.snapshotId, 'evidence snapshot id') } : {}),\n ...(evidence.locator ? { locator: compactText(evidence.locator, 'evidence locator') } : {}),\n ...(evidence.capturedHash ? { capturedHash: compactText(evidence.capturedHash, 'evidence hash') } : {}),\n };\n });\n}\n\nfunction normalizeClaimInput(input: KnowledgeClaimInput): {\n claim: KnowledgeClaim;\n evidence: ClaimEvidenceInput[];\n} {\n if (!['project', 'workspace', 'team', 'workflow', 'task'].includes(input.scope)) {\n throw new Error('Claim scope is invalid');\n }\n const projectId = compactText(input.projectId, 'project id');\n const subject = compactText(input.subject, 'subject');\n const predicate = compactText(input.predicate, 'predicate');\n const objectValue = compactText(input.objectValue, 'object value');\n const identity = buildClaimIdentity({ subject, predicate, objectValue, scope: input.scope });\n const origin = input.origin ?? 'explicit';\n let reviewState: KnowledgeClaimReviewState = input.reviewState ?? 'approved';\n let status: KnowledgeClaimStatus = input.status ?? 'active';\n if (origin === 'model') {\n if (input.reviewState === 'approved' || input.status === 'active') {\n throw new Error('A model-origin claim cannot be approved or active without explicit review');\n }\n reviewState = input.reviewState ?? 'draft';\n status = input.status ?? 'unknown';\n }\n if (!['approved', 'needs-review', 'draft', 'rejected'].includes(reviewState)) {\n throw new Error('Claim review state is invalid');\n }\n if (!['active', 'superseded', 'disputed', 'unknown'].includes(status)) {\n throw new Error('Claim status is invalid');\n }\n const now = new Date().toISOString();\n return {\n claim: {\n id: randomUUID(),\n projectId,\n subject,\n predicate,\n objectValue,\n scope: input.scope,\n claimKey: identity.claimKey,\n conflictKey: identity.conflictKey,\n status,\n confidence: clampConfidence(input.confidence),\n observedAt: input.observedAt ?? now,\n ...(input.validFrom ? { validFrom: input.validFrom } : {}),\n ...(input.validTo ? { validTo: input.validTo } : {}),\n reviewState,\n origin,\n createdAt: now,\n updatedAt: now,\n },\n evidence: validateEvidence(input.evidence),\n };\n}\n\nfunction activeConflictClaims(store: ClaimStore, projectId: string, conflictKey: string): KnowledgeClaim[] {\n return store.listClaimsByConflictKey(projectId, conflictKey).filter(claim =>\n (claim.status === 'active' || claim.status === 'disputed') && claim.reviewState === 'approved');\n}\n\nfunction reconcileConflicts(\n store: ClaimStore,\n projectId: string,\n conflictKey: string,\n now: string,\n): ClaimConflict[] {\n const claims = activeConflictClaims(store, projectId, conflictKey);\n const hasConflict = new Set(claims.map(claim => claim.claimKey)).size > 1;\n for (const claim of claims) {\n const nextStatus: KnowledgeClaimStatus = hasConflict ? 'disputed' : 'active';\n if (claim.status === nextStatus) continue;\n store.updateClaim({ ...claim, status: nextStatus, updatedAt: now });\n store.recordEvent({\n projectId,\n claimId: claim.id,\n kind: hasConflict ? 'conflicted' : 'requalified',\n fromStatus: claim.status,\n toStatus: nextStatus,\n detail: hasConflict\n ? 'A different approved assertion has the same subject, predicate, and scope.'\n : 'No remaining approved competing assertion exists.',\n createdAt: now,\n });\n }\n return store.listConflicts(projectId).filter(conflict => conflict.conflictKey === conflictKey);\n}\n\nfunction persistEvidence(store: ClaimStore, claim: KnowledgeClaim, evidence: ClaimEvidenceInput[], now: string): void {\n let added = false;\n for (const item of evidence) {\n added = store.insertEvidence({ claimId: claim.id, ...item, createdAt: now }) || added;\n }\n if (added) {\n store.touchClaim(claim.id, now);\n store.recordEvent({\n projectId: claim.projectId,\n claimId: claim.id,\n kind: 'evidence-added',\n detail: 'Additional source evidence was attached.',\n createdAt: now,\n });\n }\n}\n\n/** Write one claim without allowing a summary to replace its source evidence. */\nexport function writeClaim(store: ClaimStore, input: KnowledgeClaimInput): ClaimWriteResult {\n const normalized = normalizeClaimInput(input);\n return store.transaction(() => {\n const existing = store.findReusableClaim(normalized.claim.projectId, normalized.claim.claimKey);\n if (existing) {\n persistEvidence(store, existing, normalized.evidence, normalized.claim.updatedAt);\n return {\n claim: store.getClaim(existing.id) ?? existing,\n created: false,\n conflicts: store.listConflicts(existing.projectId)\n .filter(conflict => conflict.conflictKey === existing.conflictKey),\n };\n }\n\n store.insertClaim(normalized.claim);\n for (const evidence of normalized.evidence) {\n store.insertEvidence({ claimId: normalized.claim.id, ...evidence, createdAt: normalized.claim.createdAt });\n }\n store.recordEvent({\n projectId: normalized.claim.projectId,\n claimId: normalized.claim.id,\n kind: 'created',\n toStatus: normalized.claim.status,\n detail: 'Claim created with source evidence.',\n createdAt: normalized.claim.createdAt,\n });\n const conflicts = reconcileConflicts(\n store,\n normalized.claim.projectId,\n normalized.claim.conflictKey,\n normalized.claim.updatedAt,\n );\n return {\n claim: store.getClaim(normalized.claim.id) ?? normalized.claim,\n created: true,\n conflicts,\n };\n });\n}\n\n/**\n * Deliberately approve or reject a source-backed claim after its evidence has\n * been checked. Derived agent observations never cross this boundary by\n * themselves.\n */\nexport function reviewClaim(\n store: ClaimStore,\n input: {\n claimId: string;\n reviewState: Extract<KnowledgeClaimReviewState, 'approved' | 'rejected'>;\n detail: string;\n },\n): KnowledgeClaim {\n if (input.reviewState !== 'approved' && input.reviewState !== 'rejected') {\n throw new Error('A claim review must approve or reject the claim');\n }\n const detail = compactText(input.detail, 'review detail');\n return store.transaction(() => {\n const claim = store.getClaim(input.claimId);\n if (!claim) throw new Error('Claim was not found');\n if (input.reviewState === 'approved' && claim.status === 'superseded') {\n throw new Error('A superseded claim cannot be approved');\n }\n const now = new Date().toISOString();\n const nextStatus: KnowledgeClaimStatus = input.reviewState === 'rejected'\n ? 'unknown'\n : claim.status === 'unknown' && claim.reviewState === 'rejected'\n ? 'active'\n : claim.status;\n const updated: KnowledgeClaim = {\n ...claim,\n status: nextStatus,\n reviewState: input.reviewState,\n updatedAt: now,\n };\n store.updateClaim(updated);\n store.recordEvent({\n projectId: claim.projectId,\n claimId: claim.id,\n kind: 'reviewed',\n fromStatus: claim.status,\n toStatus: updated.status,\n detail: 'Review: ' + claim.reviewState + ' -> ' + input.reviewState + '. ' + detail,\n createdAt: now,\n });\n reconcileConflicts(store, claim.projectId, claim.conflictKey, now);\n return store.getClaim(claim.id) ?? updated;\n });\n}\n\nexport function supersedeClaim(\n store: ClaimStore,\n input: {\n claimId: string;\n replacementClaimId: string;\n evidence: ClaimEvidenceInput[];\n },\n): { superseded: KnowledgeClaim; replacement: KnowledgeClaim } {\n const evidence = validateEvidence(input.evidence);\n return store.transaction(() => {\n const claim = store.getClaim(input.claimId);\n const replacement = store.getClaim(input.replacementClaimId);\n if (!claim || !replacement) throw new Error('Both claims must exist before supersession');\n if (claim.projectId !== replacement.projectId || claim.conflictKey !== replacement.conflictKey) {\n throw new Error('A replacement claim must address the same project assertion');\n }\n if (claim.id === replacement.id) throw new Error('A claim cannot supersede itself');\n const now = new Date().toISOString();\n persistEvidence(store, claim, evidence, now);\n const updated: KnowledgeClaim = {\n ...claim,\n status: 'superseded',\n validTo: now,\n supersededBy: replacement.id,\n updatedAt: now,\n };\n store.updateClaim(updated);\n store.recordEvent({\n projectId: claim.projectId,\n claimId: claim.id,\n kind: 'superseded',\n fromStatus: claim.status,\n toStatus: 'superseded',\n relatedClaimId: replacement.id,\n detail: 'Superseded by an evidence-backed replacement claim.',\n createdAt: now,\n });\n reconcileConflicts(store, claim.projectId, claim.conflictKey, now);\n return {\n superseded: store.getClaim(claim.id) ?? updated,\n replacement: store.getClaim(replacement.id) ?? replacement,\n };\n });\n}\n\nfunction hashObservation(observation: Observation): string {\n return createHash('sha256').update(JSON.stringify([\n observation.title,\n observation.narrative,\n observation.facts,\n observation.filesModified,\n observation.updatedAt ?? observation.createdAt,\n ])).digest('hex');\n}\n\nfunction evidenceFromCodeRef(ref: ObservationCodeRef): ClaimEvidenceInput {\n return {\n evidenceKind: 'code',\n evidenceId: 'code-ref:' + ref.id,\n relation: 'supports',\n ...(ref.snapshotId ? { snapshotId: ref.snapshotId } : {}),\n locator: 'code-ref/' + ref.id,\n ...(ref.capturedSymbolHash || ref.capturedFileHash\n ? { capturedHash: ref.capturedSymbolHash ?? ref.capturedFileHash }\n : {}),\n };\n}\n\n/**\n * Converts only explicit or Git-ingested observations into conservative,\n * reviewable source claims. Hook/model-derived memories remain ordinary memory\n * until an agent or operator explicitly promotes them.\n */\nexport function deriveLowRiskClaimsFromObservation(\n store: ClaimStore,\n observation: Observation,\n codeStore?: CodeGraphStore,\n): KnowledgeClaim[] {\n const predicate = PREDICATE_BY_OBSERVATION_TYPE[observation.type];\n const isExplicit = observation.sourceDetail === 'explicit';\n const isGit = observation.source === 'git' || observation.sourceDetail === 'git-ingest';\n if (!predicate || observation.status !== 'active' || (!isExplicit && !isGit)) return [];\n\n const evidence: ClaimEvidenceInput[] = [{\n evidenceKind: 'observation',\n evidenceId: 'observation:' + observation.id,\n relation: 'supports',\n locator: 'observation/' + observation.id,\n capturedHash: hashObservation(observation),\n }];\n if (observation.commitHash) {\n evidence.push({\n evidenceKind: 'git',\n evidenceId: 'git:' + observation.commitHash,\n relation: 'verifies',\n locator: 'git:' + observation.commitHash,\n capturedHash: observation.commitHash,\n });\n }\n const refs = codeStore?.listObservationRefs(observation.projectId, observation.id) ?? [];\n for (const ref of refs) evidence.push(evidenceFromCodeRef(ref));\n\n const confidence = Math.min(0.9, (isGit ? 0.75 : 0.7) + refs.filter(ref => ref.status === 'current').length * 0.05);\n const result = writeClaim(store, {\n projectId: observation.projectId,\n subject: observation.entityName,\n predicate,\n objectValue: observation.title,\n scope: 'project',\n confidence,\n observedAt: observation.updatedAt ?? observation.createdAt,\n reviewState: isGit ? 'approved' : 'needs-review',\n origin: isGit ? 'git' : 'derived',\n evidence,\n });\n return [result.claim];\n}\n\nfunction incompleteSnapshot(snapshot: CodeStateSnapshot | undefined): boolean {\n if (!snapshot) return false;\n return snapshot.completeness.skippedOversizedFiles > 0\n || (snapshot.completeness.unreadableFiles ?? 0) > 0\n || snapshot.completeness.removalScanDeferred;\n}\n\nfunction requalification(\n claim: KnowledgeClaim,\n refs: Map<string, ObservationCodeRef>,\n evidence: ClaimEvidenceRef[],\n snapshot: CodeStateSnapshot | undefined,\n): { status: KnowledgeClaimStatus; confidence: number; reviewState: KnowledgeClaimReviewState; reason?: string } | undefined {\n if (claim.status === 'superseded' || claim.reviewState === 'draft' || claim.reviewState === 'rejected') return undefined;\n const codeEvidence = evidence.filter(item => item.evidenceKind === 'code');\n if (codeEvidence.length === 0) return undefined;\n const linkedRefs = codeEvidence\n .map(item => refs.get(item.evidenceId.replace(/^code-ref:/, '')))\n .filter((ref): ref is ObservationCodeRef => !!ref);\n const missingOrStale = linkedRefs.length !== codeEvidence.length || linkedRefs.some(ref => ref.status === 'stale');\n if (missingOrStale) {\n return {\n status: 'unknown',\n confidence: Math.min(claim.confidence, 0.2),\n reviewState: 'needs-review',\n reason: 'Bound code evidence is no longer current.',\n };\n }\n if (linkedRefs.some(ref => ref.status === 'suspect')) {\n return {\n status: claim.status === 'disputed' ? 'disputed' : 'active',\n confidence: Math.min(claim.confidence, 0.5),\n reviewState: 'needs-review',\n reason: 'Bound file evidence changed and needs review.',\n };\n }\n if (incompleteSnapshot(snapshot)) {\n return {\n status: claim.status === 'disputed' ? 'disputed' : 'active',\n confidence: Math.min(claim.confidence, 0.55),\n reviewState: 'needs-review',\n reason: 'The latest code scan is incomplete.',\n };\n }\n return undefined;\n}\n\n/** Re-score code-bound claims after a completed CodeGraph refresh. */\nexport function requalifyClaimsForCodeState(\n store: ClaimStore,\n codeStore: CodeGraphStore,\n projectId: string,\n): { requalified: number; incompleteSnapshot: boolean } {\n const snapshot = codeStore.latestSnapshot(projectId);\n const refs = new Map(codeStore.listProjectObservationRefs(projectId).map(ref => [ref.id, ref]));\n let requalified = 0;\n store.transaction(() => {\n for (const claim of store.listClaims(projectId)) {\n const next = requalification(claim, refs, store.listEvidence(claim.id), snapshot);\n if (!next) continue;\n if (\n next.status === claim.status\n && next.confidence === claim.confidence\n && next.reviewState === claim.reviewState\n ) {\n continue;\n }\n const updated = {\n ...claim,\n status: next.status,\n confidence: next.confidence,\n reviewState: next.reviewState,\n updatedAt: new Date().toISOString(),\n };\n store.updateClaim(updated);\n store.recordEvent({\n projectId,\n claimId: claim.id,\n kind: 'requalified',\n fromStatus: claim.status,\n toStatus: next.status,\n detail: next.reason,\n createdAt: updated.updatedAt,\n });\n requalified += 1;\n }\n });\n return { requalified, incompleteSnapshot: incompleteSnapshot(snapshot) };\n}\n\nfunction normalizedTokens(value: string): Set<string> {\n const raw = sanitizeCredentials(value)\n .toLocaleLowerCase('en-US')\n .match(TOKEN_PATTERN)\n ?? [];\n return new Set(raw\n .map(token => token.replace(/^[,;:!?]+|[,;:!?.]+$/g, ''))\n .filter(token => token.length > 1));\n}\n\nfunction taskTokens(task: string): Set<string> {\n return normalizedTokens(task);\n}\n\nfunction scoreClaim(claim: KnowledgeClaim, tokens: Set<string>): number {\n const text = [claim.subject, claim.predicate, claim.objectValue]\n .join(' ')\n .toLocaleLowerCase('en-US');\n const words = normalizedTokens(text);\n let matches = 0;\n for (const token of tokens) {\n if (words.has(token)) matches += 1;\n }\n if (matches === 0) return 0;\n const statusWeight = claim.status === 'active' ? 0.25 : claim.status === 'disputed' ? 0.2 : 0.1;\n return matches * 10 + claim.confidence + statusWeight;\n}\n\nfunction formatClaim(claim: KnowledgeClaim): string {\n return sanitizeCredentials([claim.subject, claim.predicate, claim.objectValue].join(' '));\n}\n\n/**\n * A deterministic compact selector used by the later Workset builder. It\n * returns no generic claim dump when no task terms match.\n */\nexport function selectClaimsForTask(\n store: ClaimStore,\n input: { projectId: string; task: string; limit?: number; maxTokens?: number },\n): ClaimSelection {\n const limit = Math.max(1, Math.min(12, Math.floor(input.limit ?? 4)));\n const maxTokens = Math.max(16, Math.min(1_000, Math.floor(input.maxTokens ?? 160)));\n const tokens = taskTokens(input.task);\n if (tokens.size === 0) return { claims: [], cautions: [], tokenCount: 0, reasons: {} };\n\n const candidates = store.listClaims(input.projectId, {\n statuses: ['active', 'disputed', 'unknown'],\n limit: 1_000,\n }).filter(claim => claim.reviewState !== 'draft' && claim.reviewState !== 'rejected');\n const scored = candidates\n .map(claim => ({ claim, score: scoreClaim(claim, tokens) }))\n .filter(item => item.score > 0)\n .sort((left, right) => right.score - left.score || left.claim.id.localeCompare(right.claim.id));\n if (scored.length === 0) return { claims: [], cautions: [], tokenCount: 0, reasons: {} };\n\n const selected = new Map<string, KnowledgeClaim>();\n for (const { claim } of scored.slice(0, limit)) selected.set(claim.id, claim);\n for (const claim of [...selected.values()]) {\n for (const sibling of store.listClaimsByConflictKey(input.projectId, claim.conflictKey)) {\n if (sibling.status === 'active' || sibling.status === 'disputed') selected.set(sibling.id, sibling);\n }\n }\n\n const ordered = [...selected.values()]\n .sort((left, right) => scoreClaim(right, tokens) - scoreClaim(left, tokens) || left.id.localeCompare(right.id));\n const included: KnowledgeClaim[] = [];\n let tokenCount = 0;\n for (const claim of ordered) {\n const nextTokens = countTextTokens(formatClaim(claim));\n if (included.length > 0 && tokenCount + nextTokens > maxTokens) continue;\n included.push(claim);\n tokenCount += nextTokens;\n }\n\n const cautions = new Set<string>();\n const reasons: Record<string, string> = {};\n for (const claim of included) {\n reasons[claim.id] = 'task terms matched source-qualified claim';\n if (claim.status === 'disputed') cautions.add('claim-conflict');\n if (claim.status === 'unknown' || claim.reviewState === 'needs-review') {\n cautions.add('claim-needs-review');\n }\n }\n return { claims: included, cautions: [...cautions].sort(), tokenCount, reasons };\n}\n","import { createHash } from 'node:crypto';\nimport { promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport matter from 'gray-matter';\nimport { atomicWriteFile } from '../store/file-lock.js';\nimport type { KnowledgePage, KnowledgePageFrontmatter, KnowledgePageKind, KnowledgePageReviewState, KnowledgePageStatus } from './workspace-types.js';\n\nconst PAGE_KINDS: KnowledgePageKind[] = ['topic', 'decision', 'risk', 'index', 'schema', 'log'];\nconst PAGE_STATUSES: KnowledgePageStatus[] = ['active', 'proposed'];\nconst REVIEW_STATES: KnowledgePageReviewState[] = ['approved', 'needs-review'];\nconst LINK_PATTERN = /\\[[^\\]]+\\]\\(([^)]+)\\)/g;\n\nfunction hashContent(content: string): string {\n return createHash('sha256').update(content).digest('hex');\n}\n\nfunction stringField(data: Record<string, unknown>, key: string): string {\n const value = data[key];\n if (typeof value !== 'string' || !value.trim()) {\n throw new Error('missing required field ' + key);\n }\n return value.trim();\n}\n\nfunction stringArray(data: Record<string, unknown>, key: string): string[] {\n const value = data[key];\n if (!Array.isArray(value) || value.some(item => typeof item !== 'string')) {\n throw new Error('field ' + key + ' must be a string array');\n }\n return value.map(item => item.trim()).filter(Boolean);\n}\n\nfunction optionalString(data: Record<string, unknown>, key: string): string | undefined {\n const value = data[key];\n if (value === undefined || value === null || value === '') return undefined;\n if (typeof value !== 'string') throw new Error('field ' + key + ' must be text');\n return value.trim() || undefined;\n}\n\nexport function validateKnowledgePageFrontmatter(data: Record<string, unknown>): KnowledgePageFrontmatter {\n const kind = stringField(data, 'kind') as KnowledgePageKind;\n const status = stringField(data, 'status') as KnowledgePageStatus;\n const reviewState = stringField(data, 'reviewState') as KnowledgePageReviewState;\n if (!PAGE_KINDS.includes(kind)) throw new Error('field kind is invalid');\n if (!PAGE_STATUSES.includes(status)) throw new Error('field status is invalid');\n if (!REVIEW_STATES.includes(reviewState)) throw new Error('field reviewState is invalid');\n return {\n id: stringField(data, 'id'),\n title: stringField(data, 'title'),\n kind,\n status,\n reviewState,\n claimIds: stringArray(data, 'claimIds'),\n evidenceRefs: stringArray(data, 'evidenceRefs'),\n ...(optionalString(data, 'snapshotId') ? { snapshotId: optionalString(data, 'snapshotId') } : {}),\n tags: stringArray(data, 'tags'),\n sourceHash: stringField(data, 'sourceHash'),\n generatedAt: stringField(data, 'generatedAt'),\n updatedAt: stringField(data, 'updatedAt'),\n };\n}\n\nexport function extractInternalMarkdownLinks(body: string): string[] {\n const links = new Set<string>();\n for (const match of body.matchAll(LINK_PATTERN)) {\n const raw = match[1].trim();\n if (!raw || raw.startsWith('#') || /^[a-z][a-z0-9+.-]*:/i.test(raw)) continue;\n const pathPart = raw.split('#', 1)[0].replace(/\\\\/g, '/');\n if (!pathPart.endsWith('.md')) continue;\n links.add(pathPart);\n }\n return [...links].sort();\n}\n\nexport function resolvePageLink(sourceRelativePath: string, target: string): string | undefined {\n const sourceDir = path.posix.dirname(sourceRelativePath.replace(/\\\\/g, '/'));\n const normalized = path.posix.normalize(path.posix.join(sourceDir, target.replace(/\\\\/g, '/')));\n if (!normalized || normalized === '.' || normalized === '..' || normalized.startsWith('../')) return undefined;\n return normalized;\n}\n\nexport function renderKnowledgePage(frontmatter: KnowledgePageFrontmatter, body: string): string {\n const normalizedBody = body.trimEnd() + '\\n';\n return matter.stringify(normalizedBody, {\n id: frontmatter.id,\n title: frontmatter.title,\n kind: frontmatter.kind,\n status: frontmatter.status,\n reviewState: frontmatter.reviewState,\n claimIds: frontmatter.claimIds,\n evidenceRefs: frontmatter.evidenceRefs,\n ...(frontmatter.snapshotId ? { snapshotId: frontmatter.snapshotId } : {}),\n tags: frontmatter.tags,\n sourceHash: frontmatter.sourceHash,\n generatedAt: frontmatter.generatedAt,\n updatedAt: frontmatter.updatedAt,\n });\n}\n\nexport async function readKnowledgePage(absolutePath: string, workspaceRoot?: string): Promise<KnowledgePage> {\n const raw = await fs.readFile(absolutePath, 'utf8');\n try {\n const parsed = matter(raw);\n const frontmatter = validateKnowledgePageFrontmatter(parsed.data as Record<string, unknown>);\n return {\n absolutePath,\n relativePath: workspaceRoot\n ? path.relative(workspaceRoot, absolutePath).split(path.sep).join('/')\n : path.basename(absolutePath),\n frontmatter,\n body: parsed.content.trim(),\n contentHash: hashContent(raw),\n links: extractInternalMarkdownLinks(parsed.content),\n };\n } catch (error) {\n const detail = error instanceof Error ? error.message : 'invalid page data';\n throw new Error('Malformed knowledge page frontmatter in ' + absolutePath + ': ' + detail);\n }\n}\n\nexport async function writeKnowledgePage(absolutePath: string, content: string): Promise<string> {\n await fs.mkdir(path.dirname(absolutePath), { recursive: true });\n await atomicWriteFile(absolutePath, content);\n return hashContent(content);\n}\n\nexport function pageContentHash(content: string): string {\n return hashContent(content);\n}\n","import { createHash } from 'node:crypto';\nimport { promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport type { CodeGraphStore } from '../codegraph/store.js';\nimport { withFileLock } from '../store/file-lock.js';\nimport { ClaimStore } from './claim-store.js';\nimport { extractInternalMarkdownLinks, pageContentHash, readKnowledgePage, renderKnowledgePage, resolvePageLink, writeKnowledgePage } from './markdown.js';\nimport { KnowledgeWorkspaceStore } from './workspace-store.js';\nimport { getKnowledgeWorkspacePaths, resolveKnowledgeWorkspaceFile } from './workspace.js';\nimport type {\n KnowledgePage,\n KnowledgePageFrontmatter,\n KnowledgePageRecord,\n KnowledgeProposal,\n KnowledgeProposalReason,\n KnowledgeWorkspace,\n WikiLintIssue,\n WikiLintResult,\n} from './workspace-types.js';\n\nexport { readKnowledgePage } from './markdown.js';\n\nexport interface CompileKnowledgeWorkspaceResult {\n proposals: KnowledgeProposal[];\n published: KnowledgePageRecord[];\n}\n\nfunction hash(value: string): string {\n return createHash('sha256').update(value).digest('hex');\n}\n\nfunction now(): string {\n return new Date().toISOString();\n}\n\nasync function storeFor(workspace: KnowledgeWorkspace): Promise<KnowledgeWorkspaceStore> {\n if (!workspace.dataDir) throw new Error('Knowledge workspace has no operational data directory');\n const store = new KnowledgeWorkspaceStore();\n await store.init(workspace.dataDir);\n return store;\n}\n\nfunction topicSlug(subject: string): string {\n const safe = subject\n .toLocaleLowerCase('en-US')\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '')\n .slice(0, 48);\n return (safe || 'topic') + '-' + hash(subject).slice(0, 8);\n}\n\nfunction groupClaims(claims: ReturnType<ClaimStore['listClaims']>): Map<string, ReturnType<ClaimStore['listClaims']>> {\n const groups = new Map<string, ReturnType<ClaimStore['listClaims']>>();\n for (const claim of claims) {\n const group = groups.get(claim.subject) ?? [];\n group.push(claim);\n groups.set(claim.subject, group);\n }\n return groups;\n}\n\nfunction selectPublishableClaims(claims: ClaimStore, projectId: string) {\n return claims.listClaims(projectId, { statuses: ['active'], limit: 1_000 })\n .filter(claim => claim.reviewState === 'approved');\n}\n\nfunction evidenceRefs(claims: ReturnType<ClaimStore['listClaims']>, store: ClaimStore): string[] {\n const refs = new Set<string>();\n for (const claim of claims) {\n for (const evidence of store.listEvidence(claim.id)) {\n refs.add('claim:' + claim.id + ':evidence:' + evidence.id);\n }\n }\n return [...refs].sort();\n}\n\nfunction snapshotIdForClaims(claims: ReturnType<ClaimStore['listClaims']>, store: ClaimStore): string | undefined {\n const ids = new Set<string>();\n for (const claim of claims) {\n for (const evidence of store.listEvidence(claim.id)) {\n if (evidence.snapshotId) ids.add(evidence.snapshotId);\n }\n }\n return ids.size === 1 ? [...ids][0] : undefined;\n}\n\nfunction sourceHashForClaims(claims: ReturnType<ClaimStore['listClaims']>, store: ClaimStore): string {\n const source = claims.map(claim => ({\n id: claim.id,\n status: claim.status,\n confidence: claim.confidence,\n evidence: store.listEvidence(claim.id).map(item => ({\n id: item.id,\n kind: item.evidenceKind,\n evidenceId: item.evidenceId,\n relation: item.relation,\n snapshotId: item.snapshotId ?? '',\n capturedHash: item.capturedHash ?? '',\n })),\n }));\n return hash(JSON.stringify(source));\n}\n\nfunction renderTopicBody(title: string, claims: ReturnType<ClaimStore['listClaims']>, store: ClaimStore): string {\n const lines = [\n '# ' + title,\n '',\n 'This page is compiled from approved source-qualified claims.',\n '',\n '## Current claims',\n '',\n ];\n for (const claim of claims) {\n lines.push('- ' + claim.predicate + ': ' + claim.objectValue + ' (claim ' + claim.id + ')');\n }\n lines.push('');\n lines.push('## Evidence');\n lines.push('');\n for (const claim of claims) {\n lines.push('### Claim ' + claim.id);\n const evidence = store.listEvidence(claim.id);\n if (evidence.length === 0) {\n lines.push('- Missing evidence.');\n continue;\n }\n for (const item of evidence) {\n const location = item.locator ? ' at ' + item.locator : '';\n const snapshot = item.snapshotId ? ' (snapshot ' + item.snapshotId + ')' : '';\n lines.push('- ' + item.evidenceKind + ': ' + item.evidenceId + location + snapshot);\n }\n }\n lines.push('');\n return lines.join('\\n');\n}\n\nfunction candidatePage(\n workspace: KnowledgeWorkspace,\n title: string,\n claims: ReturnType<ClaimStore['listClaims']>,\n store: ClaimStore,\n): { page: KnowledgePage; content: string; targetRelativePath: string; proposalRelativePath: string } {\n const sourceHash = sourceHashForClaims(claims, store);\n const generatedAt = now();\n const slug = topicSlug(title);\n const targetRelativePath = 'pages/' + slug + '.md';\n const proposalRelativePath = 'proposals/' + slug + '.md';\n const frontmatter: KnowledgePageFrontmatter = {\n id: 'page:' + hash(workspace.projectId + ':' + title).slice(0, 24),\n title,\n kind: 'topic',\n status: 'proposed',\n reviewState: 'needs-review',\n claimIds: claims.map(claim => claim.id).sort(),\n evidenceRefs: evidenceRefs(claims, store),\n ...(snapshotIdForClaims(claims, store) ? { snapshotId: snapshotIdForClaims(claims, store) } : {}),\n tags: ['generated', 'topic'],\n sourceHash,\n generatedAt,\n updatedAt: generatedAt,\n };\n const content = renderKnowledgePage(frontmatter, renderTopicBody(title, claims, store));\n const proposalPath = resolveKnowledgeWorkspaceFile(workspace, proposalRelativePath);\n return {\n page: {\n absolutePath: proposalPath,\n relativePath: proposalRelativePath,\n frontmatter,\n body: renderTopicBody(title, claims, store),\n contentHash: pageContentHash(content),\n links: [],\n },\n content,\n targetRelativePath,\n proposalRelativePath,\n };\n}\n\nasync function fileHashIfPresent(filePath: string): Promise<string | undefined> {\n try {\n return pageContentHash(await fs.readFile(filePath, 'utf8'));\n } catch (error) {\n const code = error && typeof error === 'object' && 'code' in error\n ? (error as { code?: string }).code\n : undefined;\n if (code === 'ENOENT') return undefined;\n throw error;\n }\n}\n\nasync function writeIndex(workspace: KnowledgeWorkspace, store: KnowledgeWorkspaceStore): Promise<void> {\n const paths = getKnowledgeWorkspacePaths(workspace);\n const published = store.listPages(workspace.id)\n .filter(page => page.status === 'active')\n .sort((left, right) => left.title.localeCompare(right.title));\n const pending = store.listProposals(workspace.id, 'pending')\n .sort((left, right) => left.proposalPath.localeCompare(right.proposalPath));\n const lines = ['# Knowledge Workspace', '', '## Published pages', ''];\n if (published.length === 0) {\n lines.push('No published pages yet.');\n } else {\n for (const page of published) lines.push('- [' + page.title + '](' + page.relativePath + ')');\n }\n lines.push('');\n lines.push('## Review queue');\n lines.push('');\n if (pending.length === 0) {\n lines.push('No pending proposals.');\n } else {\n for (const proposal of pending) {\n const relative = path.relative(paths.root, proposal.proposalPath).split(path.sep).join('/');\n lines.push('- [' + path.basename(proposal.proposalPath, '.md') + '](' + relative + ')');\n }\n }\n lines.push('');\n await writeKnowledgePage(paths.index, lines.join('\\n'));\n}\n\nasync function appendLog(workspace: KnowledgeWorkspace, line: string): Promise<void> {\n const logPath = getKnowledgeWorkspacePaths(workspace).log;\n await fs.appendFile(logPath, '- ' + now() + ' ' + line + '\\n', 'utf8');\n}\n\nfunction toPageRecord(\n workspace: KnowledgeWorkspace,\n page: KnowledgePage,\n status: KnowledgePageRecord['status'],\n contentHash: string,\n manualContentHash?: string,\n): KnowledgePageRecord {\n return {\n id: page.frontmatter.id,\n workspaceId: workspace.id,\n relativePath: page.relativePath.replace(/^proposals\\//, 'pages/'),\n title: page.frontmatter.title,\n kind: page.frontmatter.kind,\n status,\n reviewState: page.frontmatter.reviewState,\n contentHash,\n sourceHash: page.frontmatter.sourceHash,\n claimIds: page.frontmatter.claimIds,\n ...(page.frontmatter.snapshotId ? { snapshotId: page.frontmatter.snapshotId } : {}),\n tags: page.frontmatter.tags,\n generatedAt: page.frontmatter.generatedAt,\n updatedAt: page.frontmatter.updatedAt,\n ...(manualContentHash ? { manualContentHash } : {}),\n };\n}\n\nexport async function compileKnowledgeWorkspace(input: {\n workspace: KnowledgeWorkspace;\n claims: ClaimStore;\n}): Promise<CompileKnowledgeWorkspaceResult> {\n const store = await storeFor(input.workspace);\n const published: KnowledgePageRecord[] = [];\n const proposals: KnowledgeProposal[] = [];\n const claims = selectPublishableClaims(input.claims, input.workspace.projectId);\n\n await withFileLock(getKnowledgeWorkspacePaths(input.workspace).root, async () => {\n for (const [title, group] of groupClaims(claims)) {\n const candidate = candidatePage(input.workspace, title, group, input.claims);\n const targetPath = resolveKnowledgeWorkspaceFile(input.workspace, candidate.targetRelativePath);\n const proposalPath = resolveKnowledgeWorkspaceFile(input.workspace, candidate.proposalRelativePath);\n let existing = store.getPage(input.workspace.id, candidate.targetRelativePath);\n const actualTargetHash = await fileHashIfPresent(targetPath);\n if (actualTargetHash && !existing) {\n const manualRecord = {\n ...toPageRecord(input.workspace, candidate.page, 'active', actualTargetHash, actualTargetHash),\n reviewState: 'needs-review' as const,\n sourceHash: 'manual:' + actualTargetHash,\n };\n store.upsertPage(manualRecord);\n existing = manualRecord;\n }\n\n if (\n actualTargetHash\n && existing\n && existing.status === 'active'\n && !existing.manualContentHash\n && actualTargetHash === existing.contentHash\n && existing.sourceHash === candidate.page.frontmatter.sourceHash\n ) {\n published.push(existing);\n continue;\n }\n\n let reason: KnowledgeProposalReason = 'new-page';\n let baseContentHash: string | undefined;\n if (actualTargetHash) {\n baseContentHash = existing?.contentHash;\n if (\n !existing\n || existing.status !== 'active'\n || !!existing.manualContentHash\n || actualTargetHash !== existing.contentHash\n ) {\n reason = 'manual-edit-protected';\n } else {\n reason = 'source-changed';\n }\n }\n\n if (!actualTargetHash) {\n store.upsertPage(toPageRecord(input.workspace, candidate.page, 'proposed', candidate.page.contentHash));\n }\n await writeKnowledgePage(proposalPath, candidate.content);\n const proposal = store.createProposal({\n workspaceId: input.workspace.id,\n pageId: candidate.page.frontmatter.id,\n targetPath,\n proposalPath,\n ...(baseContentHash ? { baseContentHash } : {}),\n sourceHash: candidate.page.frontmatter.sourceHash,\n reason,\n });\n proposals.push(proposal);\n await appendLog(input.workspace, 'proposed ' + candidate.targetRelativePath + ' (' + reason + ').');\n }\n store.markWorkspaceCompiled(input.workspace.id);\n await writeIndex(input.workspace, store);\n });\n return { proposals, published };\n}\n\nexport async function applyKnowledgeProposal(input: {\n workspace: KnowledgeWorkspace;\n proposalId: string;\n /** Explicit review acknowledgement before replacing a manually edited page. */\n allowManualOverwrite?: boolean;\n}): Promise<{ proposal: KnowledgeProposal; targetPath: string }> {\n const store = await storeFor(input.workspace);\n const proposal = store.getProposal(input.proposalId);\n if (!proposal || proposal.workspaceId !== input.workspace.id) {\n throw new Error('Knowledge proposal was not found for this workspace');\n }\n if (proposal.status !== 'pending') throw new Error('Knowledge proposal is not pending review');\n const root = getKnowledgeWorkspacePaths(input.workspace).root;\n const targetPath = path.resolve(proposal.targetPath);\n const proposalPath = path.resolve(proposal.proposalPath);\n if (!targetPath.startsWith(root + path.sep) || !proposalPath.startsWith(root + path.sep)) {\n throw new Error('Knowledge proposal path escapes its workspace');\n }\n\n await withFileLock(root, async () => {\n const actualTargetHash = await fileHashIfPresent(targetPath);\n if (\n proposal.baseContentHash\n && actualTargetHash !== proposal.baseContentHash\n && !input.allowManualOverwrite\n ) {\n throw new Error('The target page has manual changes; review the proposal before applying it');\n }\n if (!proposal.baseContentHash && actualTargetHash && !input.allowManualOverwrite) {\n throw new Error('The target page already exists and has no known safe base revision');\n }\n const proposalPage = await readKnowledgePage(proposalPath, root);\n const activeFrontmatter: KnowledgePageFrontmatter = {\n ...proposalPage.frontmatter,\n status: 'active',\n reviewState: 'approved',\n updatedAt: now(),\n };\n const content = renderKnowledgePage(activeFrontmatter, proposalPage.body);\n const contentHash = await writeKnowledgePage(targetPath, content);\n const activePage = await readKnowledgePage(targetPath, root);\n const record = toPageRecord(input.workspace, activePage, 'active', contentHash);\n store.upsertPage(record);\n store.replacePageClaims(record.id, record.claimIds);\n store.replacePageLinks(record.id, activePage.links.map(link => resolvePageLink(record.relativePath, link)).filter((link): link is string => !!link));\n store.markProposalApplied(proposal.id);\n await appendLog(\n input.workspace,\n 'applied ' + record.relativePath + (input.allowManualOverwrite ? ' after explicit manual overwrite review.' : '.'),\n );\n await writeIndex(input.workspace, store);\n });\n return { proposal: store.getProposal(proposal.id)!, targetPath };\n}\n\nasync function markdownFiles(directory: string): Promise<string[]> {\n const files: string[] = [];\n let entries: Array<import('node:fs').Dirent>;\n try {\n entries = await fs.readdir(directory, { withFileTypes: true });\n } catch {\n return files;\n }\n for (const entry of entries) {\n const filePath = path.join(directory, entry.name);\n if (entry.isDirectory()) {\n files.push(...await markdownFiles(filePath));\n } else if (entry.isFile() && entry.name.toLowerCase().endsWith('.md')) {\n files.push(filePath);\n }\n }\n return files;\n}\n\nexport async function lintKnowledgeWorkspace(input: {\n workspace: KnowledgeWorkspace;\n claims: ClaimStore;\n codeStore?: CodeGraphStore;\n}): Promise<WikiLintResult> {\n const store = await storeFor(input.workspace);\n const paths = getKnowledgeWorkspacePaths(input.workspace);\n const issues: WikiLintIssue[] = [];\n const validPages: KnowledgePage[] = [];\n const files = await markdownFiles(paths.pages);\n\n for (const filePath of files) {\n try {\n validPages.push(await readKnowledgePage(filePath, paths.root));\n } catch (error) {\n issues.push({\n kind: 'malformed-frontmatter',\n severity: 'error',\n message: error instanceof Error ? error.message : 'Malformed knowledge page.',\n relativePath: path.relative(paths.root, filePath).split(path.sep).join('/'),\n });\n }\n }\n\n const indexed = new Set<string>();\n try {\n const index = await fs.readFile(paths.index, 'utf8');\n for (const link of extractInternalMarkdownLinks(index)) {\n const resolved = resolvePageLink('index.md', link);\n if (resolved) indexed.add(resolved);\n }\n } catch {\n issues.push({\n kind: 'broken-link',\n severity: 'error',\n message: 'Knowledge index is missing.',\n relativePath: 'index.md',\n });\n }\n\n const latestSnapshotId = input.codeStore?.latestSnapshot(input.workspace.projectId)?.id;\n for (const page of validPages) {\n if (!indexed.has(page.relativePath)) {\n issues.push({\n kind: 'orphan-page',\n severity: 'warning',\n message: 'Page is not linked from index.md.',\n relativePath: page.relativePath,\n });\n }\n for (const link of page.links) {\n const target = resolvePageLink(page.relativePath, link);\n if (!target || !await fileHashIfPresent(resolveKnowledgeWorkspaceFile(input.workspace, target))) {\n issues.push({\n kind: 'broken-link',\n severity: 'error',\n message: 'Internal Markdown link does not resolve to a workspace page.',\n relativePath: page.relativePath,\n });\n }\n }\n for (const claimId of page.frontmatter.claimIds) {\n const claim = input.claims.getClaim(claimId);\n if (!claim) {\n issues.push({\n kind: 'missing-claim',\n severity: 'error',\n message: 'Page references a claim that is not present in the ledger.',\n relativePath: page.relativePath,\n claimId,\n });\n continue;\n }\n if (input.claims.listEvidence(claim.id).length === 0) {\n issues.push({\n kind: 'missing-evidence',\n severity: 'error',\n message: 'Page claim has no source evidence.',\n relativePath: page.relativePath,\n claimId,\n });\n }\n if (claim.status === 'superseded') {\n issues.push({\n kind: 'superseded-claim',\n severity: 'error',\n message: 'Page still presents a superseded primary claim.',\n relativePath: page.relativePath,\n claimId,\n });\n }\n if (claim.status === 'disputed') {\n issues.push({\n kind: 'unresolved-conflict',\n severity: 'error',\n message: 'Page claim has an unresolved competing assertion.',\n relativePath: page.relativePath,\n claimId,\n });\n }\n }\n if (latestSnapshotId && page.frontmatter.snapshotId && page.frontmatter.snapshotId !== latestSnapshotId) {\n issues.push({\n kind: 'stale-snapshot',\n severity: 'warning',\n message: 'Page was compiled against an older code snapshot.',\n relativePath: page.relativePath,\n });\n }\n }\n\n for (const proposal of store.listProposals(input.workspace.id, 'pending')) {\n if (proposal.reason === 'manual-edit-protected') {\n issues.push({\n kind: 'manual-edit-protected',\n severity: 'warning',\n message: 'A newer proposal was held because the target page has manual edits.',\n relativePath: path.relative(paths.root, proposal.targetPath).split(path.sep).join('/'),\n });\n }\n }\n\n const valid = !issues.some(issue => issue.severity === 'error');\n store.markWorkspaceLinted(input.workspace.id, valid ? 'ready' : 'needs-review');\n return { valid, pagesScanned: validPages.length, issues };\n}\n","import matter from 'gray-matter';\nimport type { AgentTarget, WorkflowEntry } from '../types.js';\n\n/**\n * WorkflowSyncer — converts workflows between agent formats.\n *\n * Supported conversions:\n * Windsurf .windsurf/workflows/*.md → Codex SKILL.md\n * Windsurf .windsurf/workflows/*.md → Cursor .cursor/rules/*.mdc\n * Windsurf .windsurf/workflows/*.md → Claude Code CLAUDE.md section\n */\nexport class WorkflowSyncer {\n /**\n * Parse a Windsurf workflow markdown file into a WorkflowEntry.\n */\n parseWindsurfWorkflow(fileName: string, raw: string): WorkflowEntry {\n const name = fileName.replace(/\\.md$/i, '');\n let description = '';\n let content = raw;\n\n try {\n const parsed = matter(raw);\n description = parsed.data?.description ?? '';\n content = parsed.content.trim();\n } catch {\n // No frontmatter — use raw content\n }\n\n return {\n name,\n description,\n content,\n source: 'windsurf',\n filePath: `.windsurf/workflows/${fileName}`,\n };\n }\n\n /**\n * Convert a workflow to Codex SKILL.md format.\n */\n toCodexSkill(wf: WorkflowEntry): { filePath: string; content: string } {\n const safeName = this.sanitizeName(wf.name);\n const fm: Record<string, string> = { name: safeName };\n if (wf.description) {\n fm.description = wf.description;\n }\n const content = matter.stringify(wf.content, fm);\n return {\n filePath: `.agents/skills/${safeName}/SKILL.md`,\n content,\n };\n }\n\n /**\n * Convert a workflow to Cursor .mdc rule format.\n */\n toCursorRule(wf: WorkflowEntry): { filePath: string; content: string } {\n const safeName = this.sanitizeName(wf.name);\n const fm: Record<string, string> = {};\n if (wf.description) {\n fm.description = wf.description;\n }\n fm.globs = '';\n fm.alwaysApply = 'false';\n const content = matter.stringify(wf.content, fm);\n return {\n filePath: `.cursor/rules/${safeName}.mdc`,\n content,\n };\n }\n\n /**\n * Convert a workflow to a CLAUDE.md section string.\n */\n toClaudeSection(wf: WorkflowEntry): string {\n const lines: string[] = [];\n lines.push(`## Workflow: ${wf.name}`);\n if (wf.description) {\n lines.push('');\n lines.push(`> ${wf.description}`);\n }\n lines.push('');\n lines.push(wf.content);\n return lines.join('\\n');\n }\n\n /**\n * Convert all workflows to the target agent format.\n * Returns an array of { filePath, content } for each generated file.\n */\n convertAll(\n workflows: WorkflowEntry[],\n target: AgentTarget,\n ): { filePath: string; content: string }[] {\n if (target === 'windsurf') {\n // No conversion needed — already in Windsurf format\n return [];\n }\n\n if (target === 'codex') {\n return workflows.map((wf) => this.toCodexSkill(wf));\n }\n\n if (target === 'cursor') {\n return workflows.map((wf) => this.toCursorRule(wf));\n }\n\n if (target === 'claude-code') {\n // Merge all workflows into a single CLAUDE.md\n const sections = workflows.map((wf) => this.toClaudeSection(wf));\n return [\n {\n filePath: 'CLAUDE.md',\n content: sections.join('\\n\\n'),\n },\n ];\n }\n\n return [];\n }\n\n // ---- Helpers ----\n\n private sanitizeName(name: string): string {\n return name\n .replace(/[^a-zA-Z0-9_-]/g, '-')\n .replace(/-+/g, '-')\n .replace(/^-|-$/g, '')\n || 'workflow';\n }\n}\n","import { randomUUID } from 'node:crypto';\nimport { getDatabase } from '../store/sqlite-db.js';\nimport type {\n WorkflowRun,\n WorkflowRunInput,\n WorkflowRunOutcome,\n WorkflowSpec,\n WorkflowVerificationVerdict,\n} from './workflow-types.js';\n\nfunction parseJson<T>(value: unknown, fallback: T): T {\n if (typeof value !== 'string' || !value) return fallback;\n try {\n return JSON.parse(value) as T;\n } catch {\n return fallback;\n }\n}\n\nfunction optionalText(value: unknown): string | undefined {\n return typeof value === 'string' && value.trim() ? value : undefined;\n}\n\nfunction rowToWorkflow(row: any): WorkflowSpec {\n return parseJson<WorkflowSpec>(row.specJson, {\n id: row.id,\n workspaceId: row.workspaceId,\n title: row.title,\n description: '',\n status: row.status,\n version: row.version,\n taskLenses: [],\n triggers: [],\n assumptions: [],\n requiredContext: [],\n guardrails: [],\n allowedTools: [],\n phases: [],\n verificationGates: [],\n claimIds: [],\n evidenceRefs: [],\n codeRefs: [],\n compatibleAgents: [],\n body: '',\n sourcePath: row.sourcePath,\n sourceHash: row.sourceHash,\n contentHash: row.contentHash,\n createdAt: row.createdAt,\n updatedAt: row.updatedAt,\n });\n}\n\nfunction rowToRun(row: any): WorkflowRun {\n return {\n id: row.id,\n workflowId: row.workflowId,\n projectId: row.projectId,\n task: row.task,\n ...(optionalText(row.startingSnapshotId) ? { startingSnapshotId: row.startingSnapshotId } : {}),\n selectedEvidence: parseJson<string[]>(row.selectedEvidenceJson, []),\n phaseState: parseJson<WorkflowRun['phaseState']>(row.phaseStateJson, {}),\n outcome: row.outcome as WorkflowRunOutcome,\n verificationVerdict: row.verificationVerdict as WorkflowVerificationVerdict,\n ...(optionalText(row.failureReason) ? { failureReason: row.failureReason } : {}),\n startedAt: row.startedAt,\n ...(optionalText(row.completedAt) ? { completedAt: row.completedAt } : {}),\n };\n}\n\nexport class WorkflowStore {\n private db: any = null;\n\n async init(dataDir: string): Promise<void> {\n this.db = getDatabase(dataDir);\n }\n\n upsertWorkflow(workflow: WorkflowSpec): WorkflowSpec {\n this.db.prepare(\n 'INSERT INTO knowledge_workflows (id, workspaceId, sourcePath, title, status, version, sourceHash, contentHash, specJson, importedFrom, createdAt, updatedAt) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT(workspaceId, sourcePath) DO UPDATE SET id = excluded.id, title = excluded.title, status = excluded.status, version = excluded.version, sourceHash = excluded.sourceHash, contentHash = excluded.contentHash, specJson = excluded.specJson, importedFrom = excluded.importedFrom, updatedAt = excluded.updatedAt',\n ).run(\n workflow.id,\n workflow.workspaceId,\n workflow.sourcePath,\n workflow.title,\n workflow.status,\n workflow.version,\n workflow.sourceHash,\n workflow.contentHash,\n JSON.stringify(workflow),\n workflow.importedFrom ?? null,\n workflow.createdAt,\n workflow.updatedAt,\n );\n return this.getWorkflowByPath(workflow.workspaceId, workflow.sourcePath)!;\n }\n\n getWorkflow(id: string): WorkflowSpec | undefined {\n const row = this.db.prepare('SELECT * FROM knowledge_workflows WHERE id = ?').get(id);\n return row ? rowToWorkflow(row) : undefined;\n }\n\n getWorkflowByPath(workspaceId: string, sourcePath: string): WorkflowSpec | undefined {\n const row = this.db.prepare('SELECT * FROM knowledge_workflows WHERE workspaceId = ? AND sourcePath = ?').get(workspaceId, sourcePath);\n return row ? rowToWorkflow(row) : undefined;\n }\n\n listWorkflows(workspaceId: string, status?: WorkflowSpec['status']): WorkflowSpec[] {\n const rows = status\n ? this.db.prepare('SELECT * FROM knowledge_workflows WHERE workspaceId = ? AND status = ? ORDER BY title, id').all(workspaceId, status)\n : this.db.prepare('SELECT * FROM knowledge_workflows WHERE workspaceId = ? ORDER BY title, id').all(workspaceId);\n return rows.map(rowToWorkflow);\n }\n\n recordRun(input: WorkflowRunInput): WorkflowRun {\n const run: WorkflowRun = {\n id: randomUUID(),\n workflowId: input.workflowId,\n projectId: input.projectId,\n task: input.task.trim(),\n ...(input.startingSnapshotId ? { startingSnapshotId: input.startingSnapshotId } : {}),\n selectedEvidence: [...new Set(input.selectedEvidence ?? [])],\n phaseState: input.phaseState ?? {},\n outcome: input.outcome,\n verificationVerdict: input.verificationVerdict ?? (input.outcome === 'failed' ? 'failed' : 'not-run'),\n ...(input.failureReason?.trim() ? { failureReason: input.failureReason.trim() } : {}),\n startedAt: input.startedAt ?? new Date().toISOString(),\n ...(input.completedAt ? { completedAt: input.completedAt } : input.outcome !== 'in-progress' ? { completedAt: new Date().toISOString() } : {}),\n };\n this.db.prepare(\n 'INSERT INTO knowledge_workflow_runs (id, workflowId, projectId, task, startingSnapshotId, selectedEvidenceJson, phaseStateJson, outcome, verificationVerdict, failureReason, startedAt, completedAt) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)',\n ).run(\n run.id,\n run.workflowId,\n run.projectId,\n run.task,\n run.startingSnapshotId ?? null,\n JSON.stringify(run.selectedEvidence),\n JSON.stringify(run.phaseState),\n run.outcome,\n run.verificationVerdict,\n run.failureReason ?? null,\n run.startedAt,\n run.completedAt ?? null,\n );\n return this.getRun(run.id)!;\n }\n\n getRun(id: string): WorkflowRun | undefined {\n const row = this.db.prepare('SELECT * FROM knowledge_workflow_runs WHERE id = ?').get(id);\n return row ? rowToRun(row) : undefined;\n }\n\n listRuns(projectId: string, workflowId?: string, limit = 20): WorkflowRun[] {\n const boundedLimit = Math.max(1, Math.min(Math.floor(limit), 100));\n const rows = workflowId\n ? this.db.prepare('SELECT * FROM knowledge_workflow_runs WHERE projectId = ? AND workflowId = ? ORDER BY startedAt DESC LIMIT ?').all(projectId, workflowId, boundedLimit)\n : this.db.prepare('SELECT * FROM knowledge_workflow_runs WHERE projectId = ? ORDER BY startedAt DESC LIMIT ?').all(projectId, boundedLimit);\n return rows.map(rowToRun);\n }\n\n recentFailureCautions(projectId: string, workflowId: string, limit = 2): string[] {\n return this.listRuns(projectId, workflowId, limit)\n .filter(run => run.outcome === 'failed' || run.verificationVerdict === 'failed')\n .map(run => run.failureReason\n ? 'Previous run failed: ' + run.failureReason\n : 'Previous run has a failed verification gate.');\n }\n}\n","import type { ProjectContextExplain } from './project-context.js';\n\nexport type TaskLensId =\n | 'bugfix'\n | 'feature'\n | 'release'\n | 'onboarding'\n | 'refactor'\n | 'docs'\n | 'test'\n | 'general';\n\nexport interface TaskLens {\n id: TaskLensId;\n description: string;\n sourceLimit: number;\n cautionLimit: number;\n hideUnrelatedCautionDetails: boolean;\n hideUnrelatedReliableDetails: boolean;\n}\n\ntype ProjectContextSource = ProjectContextExplain['sources'][number];\n\nconst STOP_WORDS = new Set([\n 'a',\n 'an',\n 'and',\n 'as',\n 'for',\n 'in',\n 'into',\n 'of',\n 'on',\n 'onto',\n 'the',\n 'this',\n 'that',\n 'to',\n 'with',\n 'work',\n 'project',\n 'continue',\n '继续',\n '项目',\n]);\n\nconst LENSES: Record<TaskLensId, TaskLens> = {\n bugfix: {\n id: 'bugfix',\n description: 'debug the failure with current code and the smallest repro first',\n sourceLimit: 6,\n cautionLimit: 4,\n hideUnrelatedCautionDetails: true,\n hideUnrelatedReliableDetails: false,\n },\n feature: {\n id: 'feature',\n description: 'build a scoped feature from nearby source, types, and user flow',\n sourceLimit: 6,\n cautionLimit: 3,\n hideUnrelatedCautionDetails: true,\n hideUnrelatedReliableDetails: false,\n },\n release: {\n id: 'release',\n description: 'prepare a release using current metadata, changelog, build, and package checks',\n sourceLimit: 4,\n cautionLimit: 2,\n hideUnrelatedCautionDetails: true,\n hideUnrelatedReliableDetails: true,\n },\n onboarding: {\n id: 'onboarding',\n description: 'understand the project shape before trusting old implementation details',\n sourceLimit: 4,\n cautionLimit: 2,\n hideUnrelatedCautionDetails: true,\n hideUnrelatedReliableDetails: true,\n },\n refactor: {\n id: 'refactor',\n description: 'change structure carefully by reading shared code, call sites, and tests',\n sourceLimit: 6,\n cautionLimit: 4,\n hideUnrelatedCautionDetails: true,\n hideUnrelatedReliableDetails: false,\n },\n docs: {\n id: 'docs',\n description: 'update documentation against current code and public entry points',\n sourceLimit: 5,\n cautionLimit: 2,\n hideUnrelatedCautionDetails: true,\n hideUnrelatedReliableDetails: true,\n },\n test: {\n id: 'test',\n description: 'work from tests, fixtures, harnesses, and the related source files',\n sourceLimit: 6,\n cautionLimit: 3,\n hideUnrelatedCautionDetails: true,\n hideUnrelatedReliableDetails: false,\n },\n general: {\n id: 'general',\n description: 'balanced project handoff with current facts, code memory, and verification hints',\n sourceLimit: 8,\n cautionLimit: 5,\n hideUnrelatedCautionDetails: false,\n hideUnrelatedReliableDetails: false,\n },\n};\n\nconst KEYWORDS: Record<Exclude<TaskLensId, 'general'>, string[]> = {\n bugfix: [\n 'bug',\n 'crash',\n 'incident',\n 'debug',\n 'error',\n 'fail',\n 'failing',\n 'fix',\n 'fixing',\n 'issue',\n 'regression',\n 'repro',\n '报错',\n '崩溃',\n '故障',\n '失败',\n '修复',\n '问题',\n ],\n feature: ['add', 'build', 'feature', 'implement', 'new', 'support', '新增', '实现', '支持', '功能'],\n release: ['bump', 'changelog', 'npm', 'pack', 'publish', 'release', 'version', '发版', '发布', '版本'],\n onboarding: ['architecture', 'handoff', 'onboard', 'overview', 'understand', '接手', '了解', '理解', '架构'],\n refactor: ['cleanup', 'migrate', 'refactor', 'rename', 'restructure', '重构', '迁移', '改造'],\n docs: ['doc', 'docs', 'readme', '文档', '说明'],\n test: ['coverage', 'fixture', 'smoke', 'spec', 'test', 'tests', 'testing', 'vitest', '测试'],\n};\n\n// Continuation is a delivery intent, not a task lens. A request can both resume\n// prior work and be a bugfix, feature, or release task, so callers keep the\n// normal lens and add a bounded prior-work projection separately.\nconst CONTINUATION_KEYWORDS = [\n 'continue',\n 'resume',\n 'pick up',\n 'carry on',\n 'previous session',\n '继续',\n '接手',\n '恢复',\n '延续',\n '上次会话',\n];\n\nconst LENS_PRIORITY: Exclude<TaskLensId, 'general'>[] = [\n 'bugfix',\n 'release',\n 'test',\n 'refactor',\n 'feature',\n 'docs',\n 'onboarding',\n];\n\nfunction normalizePath(path: string): string {\n return path.replace(/\\\\/g, '/');\n}\n\nfunction tokenize(text: string): string[] {\n return (text.toLowerCase().match(/[a-z0-9_./-]+|[\\u4e00-\\u9fff]+/g) ?? [])\n .map(token => token.trim())\n .filter(token => token.length > 1 && !STOP_WORDS.has(token));\n}\n\n/**\n * Match a task keyword only when the task states it as an action or intent,\n * rather than prohibiting that action. Workflow selection shares this rule so\n * a safety constraint cannot reintroduce an intent rejected by task routing.\n */\nexport function containsTaskKeyword(text: string, keyword: string): boolean {\n const matcher = /^[a-z0-9_-]+$/i.test(keyword)\n ? new RegExp(`(^|[^a-z0-9_-])${keyword.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')}(?=[^a-z0-9_-]|$)`, 'gi')\n : new RegExp(keyword.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'), 'gi');\n let match: RegExpExecArray | null;\n while ((match = matcher.exec(text)) !== null) {\n const keywordIndex = match.index + (match[1]?.length ?? 0);\n if (!isNegatedTaskKeyword(text, keywordIndex)) return true;\n }\n return false;\n}\n\n/**\n * Task text often carries safety constraints such as \"do not publish\". Those\n * constraints must not route a debugging task into the release workflow.\n * Keep this deliberately small and local: it only suppresses a keyword inside\n * the same sentence when the sentence explicitly negates an action.\n */\nfunction isNegatedTaskKeyword(text: string, keywordIndex: number): boolean {\n const boundary = Math.max(\n text.lastIndexOf('.', keywordIndex - 1),\n text.lastIndexOf('!', keywordIndex - 1),\n text.lastIndexOf('?', keywordIndex - 1),\n text.lastIndexOf(';', keywordIndex - 1),\n text.lastIndexOf('\\n', keywordIndex - 1),\n text.lastIndexOf('\\u3002', keywordIndex - 1),\n text.lastIndexOf('\\uff01', keywordIndex - 1),\n text.lastIndexOf('\\uff1f', keywordIndex - 1),\n text.lastIndexOf('\\uff1b', keywordIndex - 1),\n );\n let prefix = text.slice(boundary + 1, keywordIndex).toLowerCase();\n const contrast = /(?:,|\\uff0c)\\s*(?:but|however|instead|yet|\\u4f46\\u662f|\\u4f46|\\u800c\\u662f)\\s*/gi;\n let contrastMatch: RegExpExecArray | null;\n let contrastEnd = -1;\n while ((contrastMatch = contrast.exec(prefix)) !== null) contrastEnd = contrast.lastIndex;\n if (contrastEnd >= 0) prefix = prefix.slice(contrastEnd);\n if (/\\b(?:do|does|did|should|must|can|could|will|would|may|might)\\s+not\\b/.test(prefix)) return true;\n if (/\\b(?:don't|dont|never|without|avoid|skip)\\b/.test(prefix)) return true;\n if (/(?:^|[\\s,])no\\s+(?:[a-z0-9_-]+\\s*){0,4}$/i.test(prefix)) return true;\n const chineseClauseStart = Math.max(prefix.lastIndexOf(','), prefix.lastIndexOf('\\uff0c'), prefix.lastIndexOf('\\u3001'));\n const chineseClause = prefix.slice(chineseClauseStart + 1);\n return /(?:\\u4e0d\\u8981|\\u4e0d\\u5e94|\\u4e0d\\u53ef|\\u4e0d\\u80fd|\\u4e0d\\u4f1a|\\u7981\\u6b62|\\u52ff|\\u4e0d)\\s*(?:\\u7acb\\u5373|\\u76f4\\u63a5|\\u518d|\\u73b0\\u5728|\\u64c5\\u81ea|\\u5148)?\\s*$/.test(chineseClause);\n}\n\nexport function resolveTaskLens(task?: string): TaskLens {\n const normalized = (task ?? '').toLowerCase();\n if (!normalized.trim()) return LENSES.general;\n\n let best: { id: TaskLensId; score: number; priority: number } = {\n id: 'general',\n score: 0,\n priority: Number.MAX_SAFE_INTEGER,\n };\n\n for (const id of LENS_PRIORITY) {\n const score = KEYWORDS[id].reduce((sum, keyword) => sum + (containsTaskKeyword(normalized, keyword) ? 1 : 0), 0);\n const priority = LENS_PRIORITY.indexOf(id);\n if (score > best.score || (score === best.score && score > 0 && priority < best.priority)) {\n best = { id, score, priority };\n }\n }\n\n return best.score > 0 ? LENSES[best.id] : LENSES.general;\n}\n\n/**\n * Detect when the caller is asking to continue existing work. This stays\n * separate from task-lens routing so \"continue fixing the timeout\" remains a\n * bugfix, while still receiving a compact prior-work brief.\n */\nexport function isContinuationTask(task?: string): boolean {\n const normalized = (task ?? '').trim().toLowerCase();\n return normalized.length > 0 && CONTINUATION_KEYWORDS.some((keyword) =>\n containsTaskKeyword(normalized, keyword),\n );\n}\n\nfunction pathKindScore(path: string, lens: TaskLens): number {\n const normalized = normalizePath(path).toLowerCase();\n const name = normalized.split('/').pop() ?? normalized;\n const inDocs = normalized.startsWith('docs/') || name === 'readme.md' || name.includes('readme');\n const isTest = /(^|\\/)(tests?|__tests__|spec|fixtures?)\\//.test(normalized)\n || /\\.(test|spec)\\.[cm]?[jt]sx?$/.test(normalized)\n || /\\.(test|spec)\\.py$/.test(normalized);\n const isSource = normalized.startsWith('src/') || normalized.includes('/src/');\n const isPackage = name === 'package.json' || name === 'package-lock.json' || name === 'pnpm-lock.yaml' || name === 'yarn.lock';\n const isChangelog = name === 'changelog.md' || name === 'changes.md';\n const isWorkflow = normalized.startsWith('.github/workflows/');\n\n switch (lens.id) {\n case 'bugfix':\n return (isTest ? 80 : 0) + (isSource ? 50 : 0) + (normalized.includes('debug') ? 20 : 0);\n case 'test':\n return (isTest ? 90 : 0) + (isSource ? 45 : 0);\n case 'release':\n return (isChangelog ? 100 : 0) + (isPackage ? 90 : 0) + (isWorkflow ? 70 : 0) + (inDocs ? 35 : 0);\n case 'onboarding':\n return (name === 'readme.md' ? 100 : 0) + (inDocs ? 80 : 0) + (isPackage ? 45 : 0) + (isSource ? 20 : 0);\n case 'docs':\n return (inDocs ? 100 : 0) + (isChangelog ? 60 : 0) + (isSource ? 25 : 0);\n case 'refactor':\n return (isSource ? 70 : 0) + (isTest ? 65 : 0);\n case 'feature':\n return (isSource ? 80 : 0) + (isTest ? 45 : 0) + (inDocs ? 20 : 0);\n default:\n if (isSource || isTest) return 60;\n if (normalized.startsWith('packages/') && normalized.includes('/src/')) return 45;\n if (inDocs) return 20;\n return 0;\n }\n}\n\nfunction tokenScore(text: string, tokens: string[]): number {\n if (tokens.length === 0) return 0;\n const normalized = text.toLowerCase();\n return tokens.reduce((sum, token) => sum + (normalized.includes(token) ? 12 : 0), 0);\n}\n\nfunction sourceTaskMatchScore(source: ProjectContextSource, task?: string): number {\n const tokens = tokenize(task ?? '');\n if (tokens.length === 0) return 0;\n const text = [\n source.title,\n source.path ?? '',\n source.symbol ?? '',\n ].join('\\n').toLowerCase();\n const matches = tokens.filter(token => text.includes(token)).length;\n if (matches >= 2) return 40;\n if (matches === 1) return 24;\n return 0;\n}\n\nfunction fallbackPathRank(path: string): number {\n const normalized = normalizePath(path);\n if (normalized.startsWith('src/')) return 0;\n if (normalized.startsWith('tests/') || normalized.startsWith('test/')) return 1;\n if (normalized.startsWith('packages/') && normalized.includes('/src/')) return 2;\n if (normalized.startsWith('docs/') || normalized.toLowerCase() === 'readme.md') return 3;\n return 4;\n}\n\nexport function rankLensPaths(paths: string[], lens: TaskLens, task?: string): string[] {\n const tokens = tokenize(task ?? '');\n return [...new Set(paths.map(normalizePath))]\n .map((path, index) => ({\n path,\n index,\n score: pathKindScore(path, lens) + tokenScore(path, tokens),\n fallback: fallbackPathRank(path),\n }))\n .sort((a, b) => b.score - a.score || a.fallback - b.fallback || a.index - b.index || a.path.localeCompare(b.path))\n .map(item => item.path);\n}\n\nexport function lensPathCandidates(lens: TaskLens): string[] {\n switch (lens.id) {\n case 'release':\n return ['CHANGELOG.md', 'package.json', 'package-lock.json', '.github/workflows/ci.yml', '.github/workflows/test.yml', 'README.md'];\n case 'onboarding':\n return ['README.md', 'docs/README.md', 'docs/API_REFERENCE.md', 'package.json'];\n case 'docs':\n return ['README.md', 'README.zh-CN.md', 'docs/README.md', 'docs/API_REFERENCE.md', 'CHANGELOG.md'];\n case 'test':\n case 'bugfix':\n return ['tests', 'test'];\n default:\n return [];\n }\n}\n\nexport function scoreLensSource(source: ProjectContextSource, lens: TaskLens, task?: string): number {\n const tokens = tokenize(task ?? '');\n const text = [source.title, source.type, source.path ?? '', source.symbol ?? ''].join('\\n');\n return pathKindScore(source.path ?? '', lens) + tokenScore(text, tokens) + sourceTaskMatchScore(source, task);\n}\n\nexport function rankLensSources<T extends ProjectContextSource>(sources: T[], lens: TaskLens, task?: string): T[] {\n return [...sources]\n .map((source, index) => ({\n source,\n index,\n score: scoreLensSource(source, lens, task),\n }))\n .sort((a, b) => b.score - a.score || a.source.observationId - b.source.observationId || a.index - b.index)\n .map(item => item.source);\n}\n\nexport function lensVerificationHints(lens: TaskLens): string[] {\n switch (lens.id) {\n case 'bugfix':\n return [\n 'run the smallest failing test or repro first',\n 'inspect the changed code path before trusting old memory',\n ];\n case 'test':\n return [\n 'run the exact focused test file or test name first',\n 'inspect fixtures and harness setup before changing assertions',\n ];\n case 'release':\n return [\n 'run build, tests, package smoke, and publish dry-run where available',\n 'verify package metadata, changelog, and Git state before publishing',\n ];\n case 'onboarding':\n return [\n 'read the docs/start files first, then inspect only the code paths needed for the task',\n 'treat old implementation memories as leads until current code confirms them',\n ];\n case 'refactor':\n return [\n 'inspect call sites and tests before editing shared code',\n 'run the narrow affected test plus one regression smoke',\n ];\n case 'docs':\n return [\n 'check headings, links, commands, and examples against current code',\n 'run the smallest docs or package smoke available',\n ];\n case 'feature':\n return [\n 'inspect the closest existing implementation pattern before adding new code',\n 'run focused tests plus one user-flow smoke after changes',\n ];\n default:\n return [\n 'inspect the Start here files before editing',\n 'run the smallest relevant test or smoke command after changes',\n ];\n }\n}\n\nexport function shouldShowLensSource(source: ProjectContextSource, lens: TaskLens, task?: string): boolean {\n if (lens.id === 'general') return true;\n const score = scoreLensSource(source, lens, task);\n if (lens.id === 'onboarding' || lens.id === 'release' || lens.id === 'docs') return score >= 40;\n return score > 0;\n}\n","import { createHash } from 'node:crypto';\nimport { promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport matter from 'gray-matter';\nimport type { AgentTarget } from '../types.js';\nimport { atomicWriteFile, withFileLock } from '../store/file-lock.js';\nimport { WorkflowSyncer } from '../workspace/workflow-sync.js';\nimport { getKnowledgeWorkspacePaths, resolveKnowledgeWorkspaceFile } from './workspace.js';\nimport { WorkflowStore } from './workflow-store.js';\nimport { containsTaskKeyword } from '../codegraph/task-lens.js';\nimport type {\n WorkflowAdapterPreview,\n WorkflowAdapterTarget,\n WorkflowPhase,\n WorkflowRun,\n WorkflowRunInput,\n WorkflowSelection,\n WorkflowSpec,\n WorkflowStatus,\n} from './workflow-types.js';\nimport type { KnowledgeWorkspace } from './workspace-types.js';\n\nconst KNOWN_AGENTS: AgentTarget[] = [\n 'windsurf',\n 'cursor',\n 'claude-code',\n 'codex',\n 'copilot',\n 'antigravity',\n 'gemini-cli',\n 'openclaw',\n 'hermes',\n 'omp',\n 'kiro',\n 'opencode',\n 'trae',\n];\n\nexport const WORKFLOW_ADAPTER_TARGETS: WorkflowAdapterTarget[] = [\n 'codex',\n 'claude-code',\n 'cursor',\n 'windsurf',\n];\n\nconst STATUS_VALUES: WorkflowStatus[] = ['draft', 'active', 'archived'];\n\nfunction hash(value: string): string {\n return createHash('sha256').update(value).digest('hex');\n}\n\nfunction now(): string {\n return new Date().toISOString();\n}\n\nfunction slug(value: string): string {\n const normalized = value\n .trim()\n .toLowerCase()\n .replace(/[^a-z0-9\\u4e00-\\u9fff]+/g, '-')\n .replace(/^-+|-+$/g, '')\n .slice(0, 72);\n return normalized || 'workflow';\n}\n\nfunction titleFromName(name: string): string {\n return name\n .replace(/[-_]+/g, ' ')\n .split(' ')\n .filter(Boolean)\n .map(part => part.slice(0, 1).toUpperCase() + part.slice(1))\n .join(' ') || 'Imported Workflow';\n}\n\nfunction requiredText(data: Record<string, unknown>, key: string): string {\n const value = data[key];\n if (typeof value !== 'string' || !value.trim()) {\n throw new Error('workflow frontmatter requires ' + key);\n }\n return value.trim();\n}\n\nfunction optionalText(data: Record<string, unknown>, key: string): string | undefined {\n const value = data[key];\n if (value === undefined || value === null || value === '') return undefined;\n if (typeof value !== 'string') throw new Error('workflow frontmatter field ' + key + ' must be text');\n return value.trim() || undefined;\n}\n\nfunction optionalStringArray(data: Record<string, unknown>, key: string): string[] {\n const value = data[key];\n if (value === undefined || value === null) return [];\n if (!Array.isArray(value) || value.some(item => typeof item !== 'string')) {\n throw new Error('workflow frontmatter field ' + key + ' must be a string array');\n }\n return [...new Set(value.map(item => item.trim()).filter(Boolean))];\n}\n\nfunction optionalNumber(data: Record<string, unknown>, key: string, fallback: number): number {\n const value = data[key];\n if (value === undefined || value === null || value === '') return fallback;\n if (typeof value !== 'number' || !Number.isInteger(value) || value < 1) {\n throw new Error('workflow frontmatter field ' + key + ' must be a positive integer');\n }\n return value;\n}\n\nfunction optionalStatus(data: Record<string, unknown>): WorkflowStatus {\n const value = data.status;\n if (value === undefined || value === null || value === '') return 'draft';\n if (typeof value !== 'string' || !STATUS_VALUES.includes(value as WorkflowStatus)) {\n throw new Error('workflow frontmatter field status is invalid');\n }\n return value as WorkflowStatus;\n}\n\nfunction normalizeAgents(values: string[]): AgentTarget[] {\n const unknown = values.filter(value => !KNOWN_AGENTS.includes(value as AgentTarget));\n if (unknown.length > 0) {\n throw new Error('workflow frontmatter has unsupported agent: ' + unknown[0]);\n }\n return values as AgentTarget[];\n}\n\nfunction phaseFromValue(value: unknown, index: number): WorkflowPhase {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n throw new Error('workflow frontmatter phases must contain objects');\n }\n const data = value as Record<string, unknown>;\n const title = requiredText(data, 'title');\n const phaseId = optionalText(data, 'id') ?? slug(title) + '-' + (index + 1);\n return {\n id: phaseId,\n title,\n instructions: optionalText(data, 'instructions') ?? '',\n branches: optionalStringArray(data, 'branches'),\n expectedOutputs: optionalStringArray(data, 'expectedOutputs'),\n verificationGates: optionalStringArray(data, 'verificationGates'),\n };\n}\n\nfunction phasesFromBody(body: string): WorkflowPhase[] {\n const headers = [...body.matchAll(/^##\\s+(.+?)\\s*$/gm)];\n if (headers.length === 0) {\n const instructions = body.trim();\n return instructions\n ? [{\n id: 'execute',\n title: 'Execute',\n instructions,\n branches: [],\n expectedOutputs: [],\n verificationGates: [],\n }]\n : [];\n }\n return headers.map((match, index) => {\n const title = match[1].trim();\n const start = (match.index ?? 0) + match[0].length;\n const end = index + 1 < headers.length\n ? (headers[index + 1].index ?? body.length)\n : body.length;\n return {\n id: slug(title) + '-' + (index + 1),\n title,\n instructions: body.slice(start, end).trim(),\n branches: [],\n expectedOutputs: [],\n verificationGates: [],\n };\n });\n}\n\nfunction normalizeSourcePath(sourcePath: string): string {\n const normalized = sourcePath.replace(/\\\\/g, '/');\n if (\n !normalized.startsWith('workflows/')\n || !normalized.toLowerCase().endsWith('.md')\n || normalized.includes('../')\n || path.posix.normalize(normalized) !== normalized\n ) {\n throw new Error('workflow source path must be a safe workflows/*.md path');\n }\n return normalized;\n}\n\nfunction sourceHashFor(workflow: Omit<WorkflowSpec, 'sourceHash' | 'contentHash'> | WorkflowSpec): string {\n return hash(JSON.stringify({\n id: workflow.id,\n title: workflow.title,\n description: workflow.description,\n status: workflow.status,\n version: workflow.version,\n taskLenses: workflow.taskLenses,\n triggers: workflow.triggers,\n assumptions: workflow.assumptions,\n requiredContext: workflow.requiredContext,\n guardrails: workflow.guardrails,\n allowedTools: workflow.allowedTools,\n phases: workflow.phases,\n verificationGates: workflow.verificationGates,\n claimIds: workflow.claimIds,\n evidenceRefs: workflow.evidenceRefs,\n codeRefs: workflow.codeRefs,\n compatibleAgents: workflow.compatibleAgents,\n body: workflow.body,\n sourcePath: workflow.sourcePath,\n importedFrom: workflow.importedFrom ?? null,\n }));\n}\n\nfunction workflowFrontmatter(workflow: WorkflowSpec, sourceHash: string): Record<string, unknown> {\n return {\n id: workflow.id,\n title: workflow.title,\n description: workflow.description,\n status: workflow.status,\n version: workflow.version,\n taskLenses: workflow.taskLenses,\n triggers: workflow.triggers,\n assumptions: workflow.assumptions,\n requiredContext: workflow.requiredContext,\n guardrails: workflow.guardrails,\n allowedTools: workflow.allowedTools,\n phases: workflow.phases.map(phase => ({\n id: phase.id,\n title: phase.title,\n ...(phase.instructions ? { instructions: phase.instructions } : {}),\n ...(phase.branches.length ? { branches: phase.branches } : {}),\n ...(phase.expectedOutputs.length ? { expectedOutputs: phase.expectedOutputs } : {}),\n ...(phase.verificationGates.length ? { verificationGates: phase.verificationGates } : {}),\n })),\n verificationGates: workflow.verificationGates,\n claimIds: workflow.claimIds,\n evidenceRefs: workflow.evidenceRefs,\n codeRefs: workflow.codeRefs,\n compatibleAgents: workflow.compatibleAgents,\n sourceHash,\n createdAt: workflow.createdAt,\n updatedAt: workflow.updatedAt,\n ...(workflow.importedFrom ? { importedFrom: workflow.importedFrom } : {}),\n };\n}\n\nexport function renderWorkflowMarkdown(workflow: WorkflowSpec): string {\n const sourceHash = sourceHashFor(workflow);\n return matter.stringify(workflow.body.trimEnd() + '\\n', workflowFrontmatter(workflow, sourceHash));\n}\n\nfunction parsedWorkflow(data: Record<string, unknown>, body: string, input: {\n workspaceId: string;\n sourcePath: string;\n contentHash: string;\n}): WorkflowSpec {\n const phasesValue = data.phases;\n const parsedPhases = phasesValue === undefined || phasesValue === null\n ? phasesFromBody(body)\n : Array.isArray(phasesValue)\n ? phasesValue.map(phaseFromValue)\n : (() => { throw new Error('workflow frontmatter field phases must be an array'); })();\n const candidate: WorkflowSpec = {\n id: requiredText(data, 'id'),\n workspaceId: input.workspaceId,\n title: requiredText(data, 'title'),\n description: optionalText(data, 'description') ?? '',\n status: optionalStatus(data),\n version: optionalNumber(data, 'version', 1),\n taskLenses: optionalStringArray(data, 'taskLenses'),\n triggers: optionalStringArray(data, 'triggers'),\n assumptions: optionalStringArray(data, 'assumptions'),\n requiredContext: optionalStringArray(data, 'requiredContext'),\n guardrails: optionalStringArray(data, 'guardrails'),\n allowedTools: optionalStringArray(data, 'allowedTools'),\n phases: parsedPhases,\n verificationGates: optionalStringArray(data, 'verificationGates'),\n claimIds: optionalStringArray(data, 'claimIds'),\n evidenceRefs: optionalStringArray(data, 'evidenceRefs'),\n codeRefs: optionalStringArray(data, 'codeRefs'),\n compatibleAgents: normalizeAgents(optionalStringArray(data, 'compatibleAgents').length\n ? optionalStringArray(data, 'compatibleAgents')\n : optionalStringArray(data, 'allowedAgents')),\n body: body.trim(),\n sourcePath: normalizeSourcePath(input.sourcePath),\n sourceHash: '',\n contentHash: input.contentHash,\n createdAt: optionalText(data, 'createdAt') ?? now(),\n updatedAt: optionalText(data, 'updatedAt') ?? now(),\n ...(optionalText(data, 'importedFrom') ? { importedFrom: optionalText(data, 'importedFrom') } : {}),\n };\n if (candidate.phases.length === 0) {\n throw new Error('workflow must contain at least one phase or a non-empty body');\n }\n return { ...candidate, sourceHash: sourceHashFor(candidate) };\n}\n\nexport function parseWorkflowMarkdown(raw: string, input: {\n workspaceId: string;\n sourcePath: string;\n}): WorkflowSpec {\n let parsed: matter.GrayMatterFile<string>;\n try {\n parsed = matter(raw);\n } catch (error) {\n throw new Error('Malformed workflow Markdown: ' + (error instanceof Error ? error.message : String(error)));\n }\n return parsedWorkflow(parsed.data as Record<string, unknown>, parsed.content, {\n workspaceId: input.workspaceId,\n sourcePath: input.sourcePath,\n contentHash: hash(raw),\n });\n}\n\nfunction workflowStoreDataDir(workspace: KnowledgeWorkspace): string {\n if (!workspace.dataDir) throw new Error('Knowledge workspace is missing its local data directory');\n return workspace.dataDir;\n}\n\nasync function storeFor(workspace: KnowledgeWorkspace): Promise<WorkflowStore> {\n const store = new WorkflowStore();\n await store.init(workflowStoreDataDir(workspace));\n return store;\n}\n\nfunction materializeWorkflow(workflow: WorkflowSpec): WorkflowSpec {\n const updatedAt = workflow.updatedAt || now();\n const withDates = {\n ...workflow,\n createdAt: workflow.createdAt || updatedAt,\n updatedAt,\n };\n const sourceHash = sourceHashFor(withDates);\n const content = renderWorkflowMarkdown({ ...withDates, sourceHash, contentHash: '' });\n return {\n ...withDates,\n sourceHash,\n contentHash: hash(content),\n };\n}\n\nexport async function writeCanonicalWorkflow(input: {\n workspace: KnowledgeWorkspace;\n workflow: WorkflowSpec;\n}): Promise<WorkflowSpec> {\n const paths = getKnowledgeWorkspacePaths(input.workspace);\n const workflow = materializeWorkflow({\n ...input.workflow,\n workspaceId: input.workspace.id,\n sourcePath: normalizeSourcePath(input.workflow.sourcePath),\n });\n const filePath = resolveKnowledgeWorkspaceFile(input.workspace, workflow.sourcePath);\n const content = renderWorkflowMarkdown(workflow);\n await withFileLock(paths.root, async () => {\n await fs.mkdir(path.dirname(filePath), { recursive: true });\n await atomicWriteFile(filePath, content);\n });\n const store = await storeFor(input.workspace);\n return store.upsertWorkflow({ ...workflow, contentHash: hash(content) });\n}\n\nasync function markdownFiles(directory: string): Promise<string[]> {\n let entries: Array<import('node:fs').Dirent>;\n try {\n entries = await fs.readdir(directory, { withFileTypes: true });\n } catch {\n return [];\n }\n const files: string[] = [];\n for (const entry of entries) {\n const absolutePath = path.join(directory, entry.name);\n if (entry.isDirectory()) {\n files.push(...await markdownFiles(absolutePath));\n } else if (entry.isFile() && entry.name.toLowerCase().endsWith('.md')) {\n files.push(absolutePath);\n }\n }\n return files;\n}\n\n/**\n * Make manually authored canonical files visible to selection without changing\n * them. Invalid files are returned as diagnostics instead of being treated as\n * active project instructions.\n */\nexport async function syncCanonicalWorkflows(workspace: KnowledgeWorkspace): Promise<{\n workflows: WorkflowSpec[];\n errors: Array<{ sourcePath: string; message: string }>;\n}> {\n const paths = getKnowledgeWorkspacePaths(workspace);\n const store = await storeFor(workspace);\n const workflows: WorkflowSpec[] = [];\n const errors: Array<{ sourcePath: string; message: string }> = [];\n for (const absolutePath of await markdownFiles(paths.workflows)) {\n const sourcePath = path.relative(paths.root, absolutePath).split(path.sep).join('/');\n try {\n const raw = await fs.readFile(absolutePath, 'utf8');\n const workflow = parseWorkflowMarkdown(raw, { workspaceId: workspace.id, sourcePath });\n workflows.push(store.upsertWorkflow(workflow));\n } catch (error) {\n errors.push({\n sourcePath,\n message: error instanceof Error ? error.message : String(error),\n });\n }\n }\n return { workflows, errors };\n}\n\nconst LENS_TERMS: Record<string, string[]> = {\n release: ['release', 'publish', 'npm', 'version', '发版', '发布'],\n bugfix: ['bug', 'fix', 'error', 'failure', 'issue', 'repair', '修复', '报错', '故障'],\n migration: ['migration', 'migrate', 'upgrade', '迁移', '升级'],\n review: ['review', 'audit', 'pr', 'code review', '审查', '评审'],\n onboarding: ['onboard', 'onboarding', 'understand', 'introduce', '接手', '了解'],\n refactor: ['refactor', 'cleanup', 'restructure', '重构', '整理'],\n test: ['test', 'verify', 'smoke', '测试', '验证'],\n};\n\nconst GENERIC_WORKFLOW_LENSES = new Set(['review', 'test']);\nconst GENERIC_WORKFLOW_TERMS = new Set(['review', 'audit', 'test', 'verify', 'smoke']);\n\nfunction inferTaskLenses(value: string): string[] {\n const text = value.toLowerCase();\n return Object.entries(LENS_TERMS)\n .filter(([, terms]) => terms.some(term => text.includes(term)))\n .map(([lens]) => lens);\n}\n\nfunction taskScore(workflow: WorkflowSpec, task: string): { score: number; reasons: string[] } {\n const text = task.toLowerCase();\n let score = 0;\n const reasons: string[] = [];\n const matchedLenses = new Set<string>();\n const matchedTriggers = new Set<string>();\n for (const lens of workflow.taskLenses) {\n const terms = LENS_TERMS[lens.toLowerCase()] ?? [lens.toLowerCase()];\n if (terms.some(term => containsTaskKeyword(task, term))) {\n score += 20;\n reasons.push('matches ' + lens + ' workflow');\n matchedLenses.add(lens.toLowerCase());\n }\n }\n for (const trigger of workflow.triggers) {\n const term = trigger.toLowerCase().trim();\n if (term.length >= 2 && containsTaskKeyword(task, term)) {\n score += 8;\n reasons.push('matches trigger \"' + trigger + '\"');\n matchedTriggers.add(term);\n }\n }\n const hasSpecificLens = workflow.taskLenses.some(lens => !GENERIC_WORKFLOW_LENSES.has(lens.toLowerCase()));\n const hasSpecificMatch = [...matchedLenses].some(lens => !GENERIC_WORKFLOW_LENSES.has(lens))\n || [...matchedTriggers].some(trigger => !GENERIC_WORKFLOW_TERMS.has(trigger));\n if (hasSpecificLens && !hasSpecificMatch) return { score: 0, reasons: [] };\n return { score, reasons: [...new Set(reasons)] };\n}\n\nexport function selectWorkflows(input: {\n workflows: WorkflowSpec[];\n task: string;\n projectId?: string;\n store?: WorkflowStore;\n limit?: number;\n}): WorkflowSelection[] {\n const selected = input.workflows\n .filter(workflow => workflow.status === 'active')\n .map(workflow => {\n const match = taskScore(workflow, input.task);\n const cautions = input.store && input.projectId\n ? input.store.recentFailureCautions(input.projectId, workflow.id)\n : [];\n return {\n workflow,\n score: match.score,\n reasons: match.reasons,\n firstPhase: workflow.phases[0],\n cautions,\n };\n })\n .filter(item => item.score > 0)\n .sort((left, right) => right.score - left.score || left.workflow.title.localeCompare(right.workflow.title));\n return selected.slice(0, Math.max(1, Math.min(input.limit ?? 2, 2)));\n}\n\nfunction importedWorkflowSpec(input: {\n workspace: KnowledgeWorkspace;\n sourceName: string;\n sourcePath: string;\n raw: string;\n}): WorkflowSpec {\n let sourceMatter: matter.GrayMatterFile<string>;\n try {\n sourceMatter = matter(input.raw);\n } catch (error) {\n throw new Error('Malformed Windsurf workflow Markdown: ' + (error instanceof Error ? error.message : String(error)));\n }\n if (sourceMatter.data.id !== undefined) {\n const id = requiredText(sourceMatter.data as Record<string, unknown>, 'id');\n const sourcePath = 'workflows/' + slug(id) + '.md';\n const canonical = parsedWorkflow(sourceMatter.data as Record<string, unknown>, sourceMatter.content, {\n workspaceId: input.workspace.id,\n sourcePath,\n contentHash: hash(input.raw),\n });\n return materializeWorkflow({\n ...canonical,\n importedFrom: input.sourcePath.replace(/\\\\/g, '/'),\n });\n }\n const entry = new WorkflowSyncer().parseWindsurfWorkflow(input.sourceName, input.raw);\n const content = entry.content.trim() || '## Execute\\n\\nFollow the imported workflow.';\n const lenses = inferTaskLenses(entry.name + '\\n' + entry.description);\n const createdAt = now();\n const sourcePath = 'workflows/' + slug(entry.name) + '.md';\n const spec: WorkflowSpec = {\n id: 'workflow:' + hash(input.workspace.id + ':' + sourcePath).slice(0, 24),\n workspaceId: input.workspace.id,\n title: titleFromName(entry.name),\n description: entry.description || 'Imported from ' + input.sourcePath,\n status: 'active',\n version: 1,\n taskLenses: lenses,\n triggers: lenses,\n assumptions: [],\n requiredContext: [],\n guardrails: [],\n allowedTools: [],\n phases: phasesFromBody(content),\n verificationGates: [],\n claimIds: [],\n evidenceRefs: [],\n codeRefs: [],\n compatibleAgents: WORKFLOW_ADAPTER_TARGETS,\n body: content,\n sourcePath,\n sourceHash: '',\n contentHash: '',\n createdAt,\n updatedAt: createdAt,\n importedFrom: input.sourcePath.replace(/\\\\/g, '/'),\n };\n return materializeWorkflow(spec);\n}\n\n/**\n * Import legacy Windsurf workflows into canonical Markdown. The original\n * source is read only; existing canonical workflow files are not overwritten.\n */\nexport async function importWindsurfWorkflows(input: {\n workspace: KnowledgeWorkspace;\n projectRoot: string;\n}): Promise<{\n imported: WorkflowSpec[];\n skipped: Array<{ sourcePath: string; reason: string }>;\n}> {\n const sourceDirectory = path.join(path.resolve(input.projectRoot), '.windsurf', 'workflows');\n const paths = getKnowledgeWorkspacePaths(input.workspace);\n const imported: WorkflowSpec[] = [];\n const skipped: Array<{ sourcePath: string; reason: string }> = [];\n let entries: Array<import('node:fs').Dirent>;\n try {\n entries = await fs.readdir(sourceDirectory, { withFileTypes: true });\n } catch {\n return { imported, skipped };\n }\n for (const entry of entries.filter(item => item.isFile() && item.name.toLowerCase().endsWith('.md'))) {\n const originalPath = path.join(sourceDirectory, entry.name);\n const sourcePath = path.relative(path.resolve(input.projectRoot), originalPath).split(path.sep).join('/');\n try {\n const raw = await fs.readFile(originalPath, 'utf8');\n const workflow = importedWorkflowSpec({\n workspace: input.workspace,\n sourceName: entry.name,\n sourcePath,\n raw,\n });\n const targetPath = resolveKnowledgeWorkspaceFile(input.workspace, workflow.sourcePath);\n try {\n await fs.access(targetPath);\n skipped.push({ sourcePath, reason: 'canonical workflow already exists and was preserved' });\n continue;\n } catch {\n // The generated canonical path is available.\n }\n imported.push(await writeCanonicalWorkflow({ workspace: input.workspace, workflow }));\n } catch (error) {\n skipped.push({\n sourcePath,\n reason: error instanceof Error ? error.message : String(error),\n });\n }\n }\n await fs.mkdir(paths.workflows, { recursive: true });\n return { imported, skipped };\n}\n\nfunction isWithin(root: string, candidate: string): boolean {\n const relative = path.relative(root, candidate);\n return relative !== '' && relative !== '..' && !relative.startsWith('..' + path.sep) && !path.isAbsolute(relative);\n}\n\nfunction adapterRelativePath(workflow: WorkflowSpec, agent: WorkflowAdapterTarget): string {\n const name = 'memorix-workflow-' + slug(workflow.id.replace(/^workflow:/, ''));\n if (agent === 'codex') return '.agents/skills/' + name + '/SKILL.md';\n if (agent === 'claude-code') return '.claude/skills/' + name + '/SKILL.md';\n if (agent === 'cursor') return '.cursor/rules/' + name + '.mdc';\n return '.windsurf/workflows/' + name + '.md';\n}\n\nfunction adapterMarker(workflow: WorkflowSpec): string {\n return '<!-- memorix:workflow-adapter id=\"' + workflow.id + '\" -->';\n}\n\nfunction adapterContent(workflow: WorkflowSpec, agent: WorkflowAdapterTarget): string {\n const marker = adapterMarker(workflow);\n const firstPhase = workflow.phases[0];\n const gates = workflow.verificationGates.length\n ? workflow.verificationGates\n : firstPhase.verificationGates;\n if (agent === 'codex' || agent === 'claude-code') {\n return matter.stringify([\n marker,\n '',\n '# ' + workflow.title,\n '',\n workflow.description,\n '',\n '## Start',\n '',\n firstPhase.instructions || firstPhase.title,\n '',\n '## Verification',\n '',\n ...(gates.length ? gates.map(gate => '- ' + gate) : ['- Follow the project verification standards.']),\n '',\n '## Full workflow',\n '',\n workflow.body.trim(),\n '',\n ].join('\\n'), {\n name: 'memorix-workflow-' + slug(workflow.id.replace(/^workflow:/, '')),\n description: workflow.description || workflow.title,\n });\n }\n if (agent === 'cursor') {\n return matter.stringify([\n marker,\n '',\n '# ' + workflow.title,\n '',\n workflow.body.trim(),\n '',\n ].join('\\n'), {\n description: workflow.description || workflow.title,\n globs: '',\n alwaysApply: false,\n });\n }\n return matter.stringify([\n marker,\n '',\n '# ' + workflow.title,\n '',\n workflow.body.trim(),\n '',\n ].join('\\n'), {\n description: workflow.description || workflow.title,\n });\n}\n\nfunction isWorkflowAdapterTarget(agent: AgentTarget): agent is WorkflowAdapterTarget {\n return WORKFLOW_ADAPTER_TARGETS.includes(agent as WorkflowAdapterTarget);\n}\n\nexport async function previewWorkflowAdapter(input: {\n workflow: WorkflowSpec;\n projectRoot: string;\n agent: AgentTarget;\n}): Promise<WorkflowAdapterPreview> {\n if (!isWorkflowAdapterTarget(input.agent)) {\n return {\n agent: input.agent,\n workflowId: input.workflow.id,\n status: 'unsupported',\n reason: 'This agent has no safe native workflow adapter. Use Memorix Project Context instead.',\n };\n }\n if (\n input.workflow.compatibleAgents.length > 0\n && !input.workflow.compatibleAgents.includes(input.agent)\n ) {\n return {\n agent: input.agent,\n workflowId: input.workflow.id,\n status: 'unsupported',\n reason: 'The canonical workflow does not declare compatibility with this agent.',\n };\n }\n const projectRoot = path.resolve(input.projectRoot);\n const targetPath = path.resolve(projectRoot, adapterRelativePath(input.workflow, input.agent));\n if (!isWithin(projectRoot, targetPath)) {\n throw new Error('Workflow adapter target escapes the project root');\n }\n const content = adapterContent(input.workflow, input.agent);\n let existing: string | undefined;\n try {\n existing = await fs.readFile(targetPath, 'utf8');\n } catch (error) {\n const code = error && typeof error === 'object' && 'code' in error\n ? (error as { code?: string }).code\n : undefined;\n if (code !== 'ENOENT') throw error;\n }\n if (existing === undefined) {\n return { agent: input.agent, workflowId: input.workflow.id, targetPath, content, status: 'create', reason: 'No existing project adapter file.' };\n }\n if (existing === content) {\n return { agent: input.agent, workflowId: input.workflow.id, targetPath, content, status: 'unchanged', reason: 'Existing Memorix adapter already matches the canonical workflow.' };\n }\n if (existing.includes(adapterMarker(input.workflow))) {\n return { agent: input.agent, workflowId: input.workflow.id, targetPath, content, status: 'update', reason: 'Existing Memorix-owned adapter will be updated.' };\n }\n return { agent: input.agent, workflowId: input.workflow.id, targetPath, content, status: 'conflict', reason: 'A user-owned project file already occupies this adapter path.' };\n}\n\nexport async function applyWorkflowAdapter(input: {\n workflow: WorkflowSpec;\n projectRoot: string;\n agent: AgentTarget;\n}): Promise<WorkflowAdapterPreview> {\n const initial = await previewWorkflowAdapter(input);\n if (initial.status === 'unsupported' || initial.status === 'conflict' || initial.status === 'unchanged') {\n return initial;\n }\n const projectRoot = path.resolve(input.projectRoot);\n return withFileLock(projectRoot, async () => {\n const current = await previewWorkflowAdapter(input);\n if (current.status !== 'create' && current.status !== 'update') return current;\n await fs.mkdir(path.dirname(current.targetPath!), { recursive: true });\n await atomicWriteFile(current.targetPath!, current.content!);\n return current;\n });\n}\n\nexport async function recordWorkflowRun(input: {\n workspace: KnowledgeWorkspace;\n run: WorkflowRunInput;\n}): Promise<WorkflowRun> {\n const store = await storeFor(input.workspace);\n const workflow = store.getWorkflow(input.run.workflowId);\n if (!workflow || workflow.workspaceId !== input.workspace.id) {\n throw new Error('Workflow was not found for this workspace');\n }\n if (!input.run.task.trim()) throw new Error('Workflow run task is required');\n return store.recordRun(input.run);\n}\n\nexport async function selectWorkspaceWorkflows(input: {\n workspace: KnowledgeWorkspace;\n task: string;\n limit?: number;\n}): Promise<{ selections: WorkflowSelection[]; errors: Array<{ sourcePath: string; message: string }> }> {\n const synced = await syncCanonicalWorkflows(input.workspace);\n const store = await storeFor(input.workspace);\n return {\n selections: selectWorkflows({\n workflows: synced.workflows,\n task: input.task,\n projectId: input.workspace.projectId,\n store,\n limit: input.limit,\n }),\n errors: synced.errors,\n };\n}\n","import { closeAllDatabases } from '../store/sqlite-db.js';\nimport { loadDotenv } from '../config/dotenv-loader.js';\nimport { initProjectRoot } from '../config/yaml-loader.js';\nimport { initLLM } from '../llm/provider.js';\nimport { initObservationStore } from '../store/obs-store.js';\nimport { initObservations } from '../memory/observations.js';\nimport {\n MAINTENANCE_JOB_KINDS,\n type MaintenanceJob,\n type MaintenanceJobRunResult,\n} from './maintenance-jobs.js';\nimport {\n ISOLATED_MAINTENANCE_JOB_KINDS,\n MAINTENANCE_RESULT_PREFIX,\n type IsolatedMaintenanceRequest,\n} from './isolated-maintenance.js';\nimport { createProjectMaintenanceHandler } from './project-maintenance.js';\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return Boolean(value) && typeof value === 'object' && !Array.isArray(value);\n}\n\nfunction isJob(value: unknown): value is MaintenanceJob {\n if (!isRecord(value)) return false;\n return typeof value.id === 'string'\n && typeof value.projectId === 'string'\n && typeof value.kind === 'string'\n && MAINTENANCE_JOB_KINDS.includes(value.kind as MaintenanceJob['kind'])\n && ISOLATED_MAINTENANCE_JOB_KINDS.includes(value.kind as MaintenanceJob['kind'])\n && isRecord(value.payload);\n}\n\nexport function parseMaintenanceRequest(raw: string): IsolatedMaintenanceRequest {\n let value: unknown;\n try {\n value = JSON.parse(raw);\n } catch {\n throw new Error('Maintenance runner received invalid JSON input');\n }\n if (!isRecord(value) || !isJob(value.job)) {\n throw new Error('Maintenance runner received an invalid job payload');\n }\n if (typeof value.projectRoot !== 'string' || !value.projectRoot) {\n throw new Error('Maintenance runner requires projectRoot');\n }\n if (typeof value.dataDir !== 'string' || !value.dataDir) {\n throw new Error('Maintenance runner requires dataDir');\n }\n return {\n job: value.job,\n projectRoot: value.projectRoot,\n dataDir: value.dataDir,\n };\n}\n\nexport async function executeMaintenanceRequest(\n request: IsolatedMaintenanceRequest,\n): Promise<MaintenanceJobRunResult> {\n initProjectRoot(request.projectRoot);\n loadDotenv(request.projectRoot);\n await initObservationStore(request.dataDir);\n await initObservations(request.dataDir);\n if (request.job.kind === 'consolidation') initLLM();\n\n const handler = createProjectMaintenanceHandler(\n request.job.projectId,\n request.dataDir,\n request.projectRoot,\n );\n return (await handler(request.job)) ?? { action: 'complete' };\n}\n\nfunction readStdin(): Promise<string> {\n return new Promise((resolve, reject) => {\n let raw = '';\n process.stdin.setEncoding('utf8');\n process.stdin.on('data', (chunk) => { raw += chunk; });\n process.stdin.once('error', reject);\n process.stdin.once('end', () => resolve(raw));\n });\n}\n\nexport async function main(): Promise<void> {\n try {\n const request = parseMaintenanceRequest(await readStdin());\n const result = await executeMaintenanceRequest(request);\n process.stdout.write(`${MAINTENANCE_RESULT_PREFIX}${JSON.stringify(result)}\\n`);\n } catch (error) {\n process.stderr.write(`[memorix] maintenance runner failed: ${error instanceof Error ? error.message : String(error)}\\n`);\n process.exitCode = 1;\n } finally {\n closeAllDatabases();\n }\n}\n\nif (process.argv[1] && process.argv[1].endsWith('maintenance-runner.js')) {\n void main();\n}\n","import { spawn, type ChildProcessWithoutNullStreams } from 'node:child_process';\nimport { existsSync } from 'node:fs';\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport type { MaintenanceJob, MaintenanceJobKind, MaintenanceJobRunResult } from './maintenance-jobs.js';\nimport { sanitizeCredentials } from '../memory/secret-filter.js';\n\nexport const MAINTENANCE_RESULT_PREFIX = '__MEMORIX_MAINTENANCE_RESULT__';\n\nexport const ISOLATED_MAINTENANCE_JOB_KINDS: readonly MaintenanceJobKind[] = [\n 'retention-archive',\n 'consolidation',\n 'codegraph-refresh',\n 'observation-qualify',\n 'claim-derive',\n 'claim-requalification',\n 'knowledge-compile',\n 'knowledge-lint',\n 'workflow-index',\n];\nconst DEFAULT_TIMEOUT_MS = 5 * 60_000;\nconst MAX_CHILD_OUTPUT_BYTES = 1_000_000;\n\nexport interface IsolatedMaintenanceRequest {\n job: MaintenanceJob;\n projectRoot: string;\n dataDir: string;\n}\n\nexport interface IsolatedMaintenanceOptions {\n runnerPath?: string;\n timeoutMs?: number;\n env?: NodeJS.ProcessEnv;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return Boolean(value) && typeof value === 'object' && !Array.isArray(value);\n}\n\nfunction isMaintenanceResult(value: unknown): value is MaintenanceJobRunResult {\n if (!isRecord(value)) return false;\n if (value.action === 'complete') return true;\n return value.action === 'reschedule' && typeof value.delayMs === 'number';\n}\n\nfunction childError(prefix: string, detail: string): Error {\n const cleaned = sanitizeCredentials(detail.trim()).slice(0, 4_000);\n return new Error(cleaned ? `${prefix}: ${cleaned}` : prefix);\n}\n\n/**\n * Resolve the runner beside the compiled package entry. The CLI bundle lives\n * in dist/cli while the library entry lives directly in dist.\n */\nexport function resolveMaintenanceRunnerPath(moduleUrl = import.meta.url): string {\n const moduleDir = path.dirname(fileURLToPath(moduleUrl));\n const distDir = path.basename(moduleDir) === 'cli'\n ? path.dirname(moduleDir)\n : path.basename(moduleDir) === 'runtime' && path.basename(path.dirname(moduleDir)) === 'src'\n ? path.join(path.dirname(path.dirname(moduleDir)), 'dist')\n : moduleDir;\n return path.join(distDir, 'maintenance-runner.js');\n}\n\nexport function parseMaintenanceRunnerOutput(output: string): MaintenanceJobRunResult {\n const line = output\n .split(/\\r?\\n/)\n .reverse()\n .find((candidate) => candidate.startsWith(MAINTENANCE_RESULT_PREFIX));\n if (!line) {\n throw childError('Maintenance runner did not return a result', output);\n }\n\n try {\n const parsed = JSON.parse(line.slice(MAINTENANCE_RESULT_PREFIX.length));\n if (!isMaintenanceResult(parsed)) {\n throw new Error('result shape is invalid');\n }\n return parsed;\n } catch (error) {\n throw childError(\n 'Maintenance runner returned an invalid result',\n error instanceof Error ? error.message : String(error),\n );\n }\n}\n\nfunction validateRequest(request: IsolatedMaintenanceRequest): void {\n if (!ISOLATED_MAINTENANCE_JOB_KINDS.includes(request.job.kind)) {\n throw new Error(`Maintenance job ${request.job.kind} cannot run in an isolated worker`);\n }\n if (!path.isAbsolute(request.projectRoot)) {\n throw new Error('Maintenance runner requires an absolute project root');\n }\n if (!path.isAbsolute(request.dataDir)) {\n throw new Error('Maintenance runner requires an absolute data directory');\n }\n}\n\nfunction collectOutput(\n stream: NodeJS.ReadableStream,\n limit: number,\n onOverflow: () => void,\n): Promise<string> {\n return new Promise((resolve, reject) => {\n let value = '';\n let size = 0;\n stream.setEncoding('utf8');\n stream.on('data', (chunk: string) => {\n size += Buffer.byteLength(chunk);\n if (size > limit) {\n onOverflow();\n reject(new Error('maintenance runner output exceeded its safety limit'));\n return;\n }\n value += chunk;\n });\n stream.on('error', reject);\n stream.on('end', () => resolve(value));\n });\n}\n\n/**\n * Runs CPU/disk-heavy maintenance out of the MCP process. The parent keeps\n * the durable queue lease; the child gets only one job and returns one result.\n */\nexport async function runMaintenanceInChildProcess(\n request: IsolatedMaintenanceRequest,\n options: IsolatedMaintenanceOptions = {},\n): Promise<MaintenanceJobRunResult> {\n validateRequest(request);\n const runnerPath = options.runnerPath ?? resolveMaintenanceRunnerPath();\n if (!existsSync(runnerPath)) {\n throw new Error(`Maintenance runner is unavailable at ${runnerPath}. Reinstall or rebuild Memorix.`);\n }\n\n const timeoutMs = Number.isFinite(options.timeoutMs)\n ? Math.max(1_000, Math.floor(options.timeoutMs!))\n : DEFAULT_TIMEOUT_MS;\n const env = { ...process.env, ...options.env };\n\n return new Promise<MaintenanceJobRunResult>((resolve, reject) => {\n let settled = false;\n let child: ChildProcessWithoutNullStreams;\n try {\n child = spawn(process.execPath, [runnerPath], {\n cwd: request.projectRoot,\n env,\n stdio: ['pipe', 'pipe', 'pipe'],\n windowsHide: true,\n });\n } catch (error) {\n reject(error);\n return;\n }\n\n const settle = (fn: () => void): void => {\n if (settled) return;\n settled = true;\n clearTimeout(timeout);\n fn();\n };\n const terminateForOutput = (): void => {\n child.kill();\n };\n const stdout = collectOutput(child.stdout, MAX_CHILD_OUTPUT_BYTES, terminateForOutput);\n const stderr = collectOutput(child.stderr, MAX_CHILD_OUTPUT_BYTES, terminateForOutput);\n const timeout = setTimeout(() => {\n child.kill();\n settle(() => reject(new Error(`Maintenance runner timed out after ${timeoutMs}ms`)));\n }, timeoutMs);\n\n child.once('error', (error) => settle(() => reject(error)));\n child.once('close', async (code, signal) => {\n try {\n const [out, err] = await Promise.all([stdout, stderr]);\n if (code !== 0) {\n settle(() => reject(childError(\n `Maintenance runner exited with ${signal ? `signal ${signal}` : `code ${code ?? 'unknown'}`}`,\n err || out,\n )));\n return;\n }\n settle(() => resolve(parseMaintenanceRunnerOutput(out)));\n } catch (error) {\n settle(() => reject(error));\n }\n });\n\n child.stdin.end(JSON.stringify(request));\n });\n}\n","import type {\n MaintenanceJobHandler,\n MaintenanceJobRunResult,\n} from './maintenance-jobs.js';\nimport { runMaintenanceInChildProcess } from './isolated-maintenance.js';\nimport {\n enqueueClaimRequalification,\n enqueueKnowledgeFollowups,\n enqueueObservationQualification,\n type MaintenanceQueue,\n} from './lifecycle.js';\nimport { withTimeout } from '../timeout.js';\n\nconst DEFAULT_VECTOR_BATCH_SIZE = 12;\nconst DEFAULT_RETENTION_BATCH_SIZE = 100;\nconst DEFAULT_CONSOLIDATION_BATCH_SIZE = 200;\nconst DEFAULT_CODEGRAPH_MAX_FILES = 5_000;\nconst DEFAULT_CLAIM_DERIVATION_BATCH_SIZE = 100;\nconst DEFAULT_OBSERVATION_QUALIFICATION_BATCH_SIZE = 100;\nconst VECTOR_RETRY_DELAY_MS = 5_000;\nconst DEDUP_PER_PAIR_TIMEOUT_MS = 5_000;\n\nfunction vectorBatchSize(payload: Record<string, unknown>): number {\n const value = payload.limit;\n if (typeof value !== 'number' || !Number.isFinite(value)) return DEFAULT_VECTOR_BATCH_SIZE;\n return Math.min(100, Math.max(1, Math.floor(value)));\n}\n\nfunction retentionBatchSize(payload: Record<string, unknown>): number {\n const value = payload.limit;\n if (typeof value !== 'number' || !Number.isFinite(value)) return DEFAULT_RETENTION_BATCH_SIZE;\n return Math.min(500, Math.max(1, Math.floor(value)));\n}\n\nfunction retentionCursor(payload: Record<string, unknown>): number {\n const value = payload.cursor;\n return typeof value === 'number' && Number.isFinite(value)\n ? Math.max(0, Math.floor(value))\n : 0;\n}\n\nfunction consolidationBatchSize(payload: Record<string, unknown>): number {\n const value = payload.limit;\n if (typeof value !== 'number' || !Number.isFinite(value)) return DEFAULT_CONSOLIDATION_BATCH_SIZE;\n return Math.min(500, Math.max(1, Math.floor(value)));\n}\n\nfunction consolidationCursor(payload: Record<string, unknown>): number {\n const value = payload.cursor;\n return typeof value === 'number' && Number.isFinite(value)\n ? Math.max(0, Math.floor(value))\n : 0;\n}\n\nfunction codeGraphMaxFiles(payload: Record<string, unknown>): number {\n const value = payload.maxFiles;\n if (typeof value !== 'number' || !Number.isFinite(value)) return DEFAULT_CODEGRAPH_MAX_FILES;\n return Math.min(20_000, Math.max(1, Math.floor(value)));\n}\n\nfunction claimDerivationBatchSize(payload: Record<string, unknown>): number {\n const value = payload.limit;\n if (typeof value !== 'number' || !Number.isFinite(value)) return DEFAULT_CLAIM_DERIVATION_BATCH_SIZE;\n return Math.min(500, Math.max(1, Math.floor(value)));\n}\n\nfunction claimDerivationCursor(payload: Record<string, unknown>): number {\n const value = payload.cursor;\n return typeof value === 'number' && Number.isFinite(value)\n ? Math.max(0, Math.floor(value))\n : 0;\n}\n\nfunction observationQualificationBatchSize(payload: Record<string, unknown>): number {\n const value = payload.limit;\n if (typeof value !== 'number' || !Number.isFinite(value)) return DEFAULT_OBSERVATION_QUALIFICATION_BATCH_SIZE;\n return Math.min(500, Math.max(1, Math.floor(value)));\n}\n\nfunction observationQualificationCursor(payload: Record<string, unknown>): number {\n const value = payload.cursor;\n return typeof value === 'number' && Number.isFinite(value)\n ? Math.max(0, Math.floor(value))\n : 0;\n}\n\nfunction observationId(payload: Record<string, unknown>): number | undefined {\n const value = payload.observationId;\n return typeof value === 'number' && Number.isSafeInteger(value) && value > 0\n ? value\n : undefined;\n}\n\nfunction workspaceMode(payload: Record<string, unknown>): 'local' | 'versioned' | undefined {\n return payload.workspaceMode === 'local' || payload.workspaceMode === 'versioned'\n ? payload.workspaceMode\n : undefined;\n}\n\nasync function loadWorkspaceForMaintenance(\n projectId: string,\n projectDir: string,\n mode?: 'local' | 'versioned',\n) {\n const { loadKnowledgeWorkspace } = await import('../knowledge/workspace.js');\n if (mode) return loadKnowledgeWorkspace({ projectId, dataDir: projectDir, mode });\n const [versioned, local] = await Promise.all([\n loadKnowledgeWorkspace({ projectId, dataDir: projectDir, mode: 'versioned' }),\n loadKnowledgeWorkspace({ projectId, dataDir: projectDir, mode: 'local' }),\n ]);\n return versioned ?? local;\n}\n\nasync function runAutomaticConsolidation(\n projectId: string,\n projectDir: string,\n options: { afterId: number; limit: number },\n): Promise<{ nextCursor?: number }> {\n const { isLLMEnabled } = await import('../llm/provider.js');\n if (!isLLMEnabled()) {\n const { executeConsolidation } = await import('../memory/consolidation.js');\n const result = await executeConsolidation(projectDir, projectId, {\n threshold: 0.55,\n afterId: options.afterId,\n limit: options.limit,\n });\n return result.nextCursor === undefined ? {} : { nextCursor: result.nextCursor };\n }\n\n const [{ getObservationStore }, { deduplicateMemory }] = await Promise.all([\n import('../store/obs-store.js'),\n import('../llm/memory-manager.js'),\n ]);\n const store = getObservationStore();\n const page = await store.loadByProject(projectId, {\n status: 'active',\n afterId: options.afterId,\n limit: options.limit + 1,\n });\n const hasMore = page.length > options.limit;\n const allObservations = hasMore ? page.slice(0, options.limit) : page;\n const nextCursor = hasMore && allObservations.length > 0\n ? allObservations[allObservations.length - 1].id\n : undefined;\n if (allObservations.length <= 10) {\n return nextCursor === undefined ? {} : { nextCursor };\n }\n\n const grouped = new Map<string, typeof allObservations>();\n for (const observation of allObservations) {\n const key = `${observation.entityName}::${observation.type}`;\n const group = grouped.get(key) ?? [];\n group.push(observation);\n grouped.set(key, group);\n }\n\n const toResolve: number[] = [];\n const maxDedupCalls = 15;\n let dedupCalls = 0;\n for (const group of grouped.values()) {\n if (group.length < 2 || dedupCalls >= maxDedupCalls) continue;\n group.sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime());\n for (let index = 0; index < group.length - 1 && index < 3 && dedupCalls < maxDedupCalls; index++) {\n try {\n dedupCalls++;\n const older = group[index];\n const newer = group[index + 1];\n const decision = await withTimeout(\n deduplicateMemory(\n { title: newer.title, narrative: newer.narrative, facts: newer.facts },\n [{ id: older.id, title: older.title, narrative: older.narrative, facts: older.facts.join('\\n') }],\n ),\n DEDUP_PER_PAIR_TIMEOUT_MS,\n `Dedup pair #${older.id}<->#${newer.id}`,\n );\n if (decision && (decision.action === 'UPDATE' || decision.action === 'NONE')) {\n toResolve.push(decision.action === 'UPDATE' ? older.id : newer.id);\n } else if (decision?.action === 'DELETE' && decision.targetId) {\n toResolve.push(decision.targetId);\n }\n } catch {\n // One slow or malformed LLM decision must not abandon the maintenance job.\n }\n }\n }\n if (toResolve.length > 0) {\n await store.atomic(async (tx) => {\n await Promise.all(\n [...new Set(toResolve)].map((id) => tx.setStatus(id, 'resolved', 'active')),\n );\n });\n }\n return nextCursor === undefined ? {} : { nextCursor };\n}\n\nexport function createProjectMaintenanceHandler(\n projectId: string,\n projectDir: string,\n projectRoot?: string,\n options: { maintenanceQueue?: MaintenanceQueue } = {},\n): MaintenanceJobHandler {\n return async (job): Promise<MaintenanceJobRunResult> => {\n if (job.projectId !== projectId) {\n return { action: 'reschedule', delayMs: VECTOR_RETRY_DELAY_MS };\n }\n\n if (job.kind === 'retention-archive') {\n const { archiveExpiredBatch } = await import('../memory/retention.js');\n const limit = retentionBatchSize(job.payload);\n const result = await archiveExpiredBatch(projectDir, {\n projectId,\n afterId: retentionCursor(job.payload),\n limit,\n });\n if (result.nextCursor !== undefined) {\n return {\n action: 'reschedule',\n delayMs: 0,\n resetAttempts: true,\n payload: { cursor: result.nextCursor, limit },\n };\n }\n return { action: 'complete' };\n }\n\n if (job.kind === 'consolidation') {\n const limit = consolidationBatchSize(job.payload);\n const result = await runAutomaticConsolidation(projectId, projectDir, {\n afterId: consolidationCursor(job.payload),\n limit,\n });\n if (result.nextCursor !== undefined) {\n return {\n action: 'reschedule',\n delayMs: 0,\n resetAttempts: true,\n payload: { cursor: result.nextCursor, limit },\n };\n }\n return { action: 'complete' };\n }\n\n if (job.kind === 'codegraph-refresh') {\n if (!projectRoot) {\n throw new Error(`CodeGraph refresh requires a project root for ${projectId}`);\n }\n const [\n { CodeGraphStore },\n { refreshProjectLite },\n { backfillMissingObservationCodeRefs },\n { getObservationStore },\n { getResolvedConfig },\n ] = await Promise.all([\n import('../codegraph/store.js'),\n import('../codegraph/lite-provider.js'),\n import('../codegraph/binder.js'),\n import('../store/obs-store.js'),\n import('../config/resolved-config.js'),\n ]);\n const store = new CodeGraphStore();\n await store.init(projectDir);\n const codegraphConfig = getResolvedConfig({ projectRoot }).codegraph;\n await refreshProjectLite(store, {\n projectId,\n projectRoot,\n exclude: codegraphConfig.excludePatterns,\n maxFiles: codeGraphMaxFiles(job.payload),\n maxFileBytes: codegraphConfig.maxFileBytes,\n });\n const activeObservations = await getObservationStore().loadByProject(projectId, { status: 'active' });\n await backfillMissingObservationCodeRefs(store, activeObservations);\n const snapshot = store.latestSnapshot(projectId);\n enqueueClaimRequalification({\n projectId,\n dataDir: projectDir,\n source: 'codegraph-refresh',\n ...(snapshot?.id ? { snapshotId: snapshot.id } : {}),\n ...(options.maintenanceQueue ? { queue: options.maintenanceQueue } : {}),\n });\n enqueueObservationQualification({\n projectId,\n dataDir: projectDir,\n source: 'codegraph-refresh',\n ...(options.maintenanceQueue ? { queue: options.maintenanceQueue } : {}),\n });\n return { action: 'complete' };\n }\n\n if (job.kind === 'observation-qualify') {\n const [\n { CodeGraphStore },\n { bindObservationToCode },\n { getObservationStore },\n { qualifyCandidateFromCurrentCode },\n { updateObservationAdmission },\n ] = await Promise.all([\n import('../codegraph/store.js'),\n import('../codegraph/binder.js'),\n import('../store/obs-store.js'),\n import('../memory/admission.js'),\n import('../memory/observations.js'),\n ]);\n const codeStore = new CodeGraphStore();\n await codeStore.init(projectDir);\n const limit = observationQualificationBatchSize(job.payload);\n const page = await getObservationStore().loadByProject(projectId, {\n status: 'active',\n afterId: observationQualificationCursor(job.payload),\n limit: limit + 1,\n });\n const hasMore = page.length > limit;\n const observations = hasMore ? page.slice(0, limit) : page;\n const indexedAtMs = Date.parse(codeStore.status(projectId).indexedAt ?? '');\n\n for (const observation of observations) {\n if (observation.admissionState !== 'candidate') continue;\n // A candidate may only earn delivery after a Code Memory scan that\n // happened at or after it was captured. A stale snapshot is evidence\n // about an earlier project state, not a reason to inject this record.\n if (!Number.isFinite(indexedAtMs) || indexedAtMs < Date.parse(observation.createdAt)) continue;\n await bindObservationToCode(codeStore, observation);\n const currentCodeReferenceCount = codeStore\n .listObservationRefs(projectId, observation.id)\n .filter((reference) => reference.status === 'current')\n .length;\n const qualification = qualifyCandidateFromCurrentCode({\n observation,\n currentCodeReferenceCount,\n });\n if (!qualification) continue;\n await updateObservationAdmission({\n observationId: observation.id,\n projectId,\n expectedState: 'candidate',\n // Automatic capture earns project visibility only after a current\n // Code Memory link exists. Explicit/private records retain scope.\n ...(observation.sourceDetail === 'hook' ? { visibility: 'project' as const } : {}),\n ...qualification,\n });\n }\n\n if (hasMore && observations.length > 0) {\n return {\n action: 'reschedule',\n delayMs: 0,\n resetAttempts: true,\n payload: {\n ...job.payload,\n cursor: observations[observations.length - 1].id,\n limit,\n },\n };\n }\n return { action: 'complete' };\n }\n\n if (job.kind === 'claim-derive') {\n const id = observationId(job.payload);\n if (!id) throw new Error('Claim derivation requires a positive observationId');\n const [\n { CodeGraphStore },\n { ClaimStore },\n { bindObservationToCode },\n { deriveLowRiskClaimsFromObservation },\n { getObservationStore },\n ] = await Promise.all([\n import('../codegraph/store.js'),\n import('../knowledge/claim-store.js'),\n import('../codegraph/binder.js'),\n import('../knowledge/claims.js'),\n import('../store/obs-store.js'),\n ]);\n const observation = await getObservationStore().getById(id);\n if (!observation || observation.projectId !== projectId) return { action: 'complete' };\n const codeStore = new CodeGraphStore();\n const claimStore = new ClaimStore();\n await Promise.all([codeStore.init(projectDir), claimStore.init(projectDir)]);\n await bindObservationToCode(codeStore, observation);\n const derived = deriveLowRiskClaimsFromObservation(claimStore, observation, codeStore);\n if (derived.length > 0) {\n enqueueKnowledgeFollowups({\n projectId,\n dataDir: projectDir,\n source: 'claim-derive:' + id,\n includeCompile: true,\n ...(options.maintenanceQueue ? { queue: options.maintenanceQueue } : {}),\n });\n }\n return { action: 'complete' };\n }\n\n if (job.kind === 'claim-requalification') {\n const [\n { CodeGraphStore },\n { ClaimStore },\n { bindObservationToCode },\n { deriveLowRiskClaimsFromObservation, requalifyClaimsForCodeState },\n { getObservationStore },\n ] = await Promise.all([\n import('../codegraph/store.js'),\n import('../knowledge/claim-store.js'),\n import('../codegraph/binder.js'),\n import('../knowledge/claims.js'),\n import('../store/obs-store.js'),\n ]);\n const codeStore = new CodeGraphStore();\n const claimStore = new ClaimStore();\n await Promise.all([codeStore.init(projectDir), claimStore.init(projectDir)]);\n const limit = claimDerivationBatchSize(job.payload);\n const observations = await getObservationStore().loadByProject(projectId, {\n status: 'active',\n afterId: claimDerivationCursor(job.payload),\n limit,\n });\n let derivedCount = 0;\n for (const observation of observations) {\n await bindObservationToCode(codeStore, observation);\n derivedCount += deriveLowRiskClaimsFromObservation(claimStore, observation, codeStore).length;\n }\n requalifyClaimsForCodeState(claimStore, codeStore, projectId);\n if (observations.length === limit) {\n return {\n action: 'reschedule',\n delayMs: 0,\n resetAttempts: true,\n payload: {\n ...job.payload,\n cursor: observations[observations.length - 1].id,\n limit,\n },\n };\n }\n enqueueKnowledgeFollowups({\n projectId,\n dataDir: projectDir,\n source: 'claim-requalification',\n includeCompile: derivedCount > 0,\n ...(options.maintenanceQueue ? { queue: options.maintenanceQueue } : {}),\n });\n return { action: 'complete' };\n }\n\n if (job.kind === 'knowledge-compile') {\n const workspace = await loadWorkspaceForMaintenance(projectId, projectDir, workspaceMode(job.payload));\n if (!workspace) return { action: 'complete' };\n if (workspace.mode === 'versioned' && job.payload.allowVersionedWrite !== true) {\n return { action: 'complete' };\n }\n const [{ ClaimStore }, { compileKnowledgeWorkspace }] = await Promise.all([\n import('../knowledge/claim-store.js'),\n import('../knowledge/wiki.js'),\n ]);\n const claims = new ClaimStore();\n await claims.init(projectDir);\n await compileKnowledgeWorkspace({ workspace, claims });\n enqueueKnowledgeFollowups({\n projectId,\n dataDir: projectDir,\n source: 'knowledge-compile',\n ...(options.maintenanceQueue ? { queue: options.maintenanceQueue } : {}),\n });\n return { action: 'complete' };\n }\n\n if (job.kind === 'workflow-index') {\n const workspace = await loadWorkspaceForMaintenance(projectId, projectDir, workspaceMode(job.payload));\n if (!workspace) return { action: 'complete' };\n const { syncCanonicalWorkflows } = await import('../knowledge/workflows.js');\n await syncCanonicalWorkflows(workspace);\n return { action: 'complete' };\n }\n\n if (job.kind === 'knowledge-lint') {\n const workspace = await loadWorkspaceForMaintenance(projectId, projectDir, workspaceMode(job.payload));\n if (!workspace) return { action: 'complete' };\n const [\n { ClaimStore },\n { CodeGraphStore },\n { lintKnowledgeWorkspace },\n ] = await Promise.all([\n import('../knowledge/claim-store.js'),\n import('../codegraph/store.js'),\n import('../knowledge/wiki.js'),\n ]);\n const claims = new ClaimStore();\n const codeStore = new CodeGraphStore();\n await Promise.all([claims.init(projectDir), codeStore.init(projectDir)]);\n await lintKnowledgeWorkspace({ workspace, claims, codeStore });\n return { action: 'complete' };\n }\n\n if (job.kind !== 'vector-backfill') {\n throw new Error(`No runtime handler is registered for maintenance job: ${job.kind}`);\n }\n\n const { isEmbeddingExplicitlyDisabled } = await import('../embedding/provider.js');\n if (isEmbeddingExplicitlyDisabled()) return { action: 'complete' };\n\n const { backfillVectorEmbeddings, getVectorStatus } = await import('../memory/observations.js');\n const before = getVectorStatus(projectId);\n if (before.missing === 0) return { action: 'complete' };\n\n const result = await backfillVectorEmbeddings({\n projectId,\n limit: vectorBatchSize(job.payload),\n });\n const after = getVectorStatus(projectId);\n if (after.missing === 0) return { action: 'complete' };\n\n if (result.failed > 0 && result.succeeded === 0) {\n throw new Error(`vector backfill made no progress (${result.failed}/${result.attempted} failed)`);\n }\n\n return {\n action: 'reschedule',\n delayMs: result.attempted === 0 ? VECTOR_RETRY_DELAY_MS : 0,\n resetAttempts: result.succeeded > 0,\n };\n };\n}\n\n/**\n * Keep vector writes with the active in-memory search index. Everything that\n * can scan disk or consolidate a large corpus runs in a separate process so\n * an MCP request never shares its event loop with maintenance work.\n */\nexport function createProjectMaintenanceDispatcher(\n projectId: string,\n projectDir: string,\n projectRoot: string,\n isolatedRunner: typeof runMaintenanceInChildProcess = runMaintenanceInChildProcess,\n): MaintenanceJobHandler {\n const inProcessHandler = createProjectMaintenanceHandler(projectId, projectDir, projectRoot);\n return async (job): Promise<MaintenanceJobRunResult> => {\n if (job.kind === 'vector-backfill') {\n return (await inProcessHandler(job)) ?? { action: 'complete' };\n }\n return isolatedRunner({ job, projectRoot, dataDir: projectDir });\n };\n}\n"],"mappings":"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","names":["db","path","path","db","existsSync","readFileSync","homedir","createRequire","require","matter","existsSync","readFileSync","path","id","name","existsSync","readFileSync","homedir","existsSync","readFileSync","homedir","configCache","path","homedir","existsSync","provider","provider","provider","path","fs","nextId","count","observations","result","SqliteBackend","store","fs","path","projectDir","path","fs","_store","join","homedir","hash","cache","MAX_CACHE_SIZE","createHash","readFile","writeFile","mkdir","join","homedir","textHash","loadDiskCache","CACHE_FILE","cache","CACHE_DIR","diskCacheDirty","hash","MAX_CACHE_SIZE","MAX_RETRIES","errorText","embedding","provider_exports","now","getEmbeddingMode","getEmbeddingApiKey","getEmbeddingBaseUrl","getEmbeddingModel","FastEmbedProvider","TransformersProvider","APIEmbeddingProvider","init_provider","fs","path","HIGH_VALUE_TYPES","getDb","insert","remove","observationId","COMMAND_LIKE_QUERY","provider","initPromise","observations","now","resolveAliases","initLLM","isLLMEnabled","rerankResults","withFreshIndex","getAllObservations","init_provider","randomUUID","now","updated","createHash","path","observationId","randomUUID","writeFile","observationId","path","path","observations","getObservationCount","now","MaintenanceJobStore","CodeGraphStore","bindObservationToCode","removeObservation","slug","provider","count","init_provider","randomUUID","now","workspaceId","remove","insert","createHash","fs","path","relative","observations","raw","now","projectDir","execFile","createHash","promisify","execFileAsync","count","path","normalizeCodePath","createHash","readdirSync","readFileSync","statSync","join","path","id","createHash","randomUUID","optionalText","createHash","randomUUID","now","createHash","fs","path","createHash","fs","path","hash","slug","relative","matter","randomUUID","optionalText","workspaceId","createHash","fs","path","matter","hash","now","optionalText","storeFor","markdownFiles","sourcePath","isWithin","relative","existsSync","path","fileURLToPath","projectDir","loadKnowledgeWorkspace","isLLMEnabled","executeConsolidation","getObservationStore","deduplicateMemory","archiveExpiredBatch","result","CodeGraphStore","refreshProjectLite","backfillMissingObservationCodeRefs","getResolvedConfig","bindObservationToCode","qualifyCandidateFromCurrentCode","updateObservationAdmission","observations","ClaimStore","deriveLowRiskClaimsFromObservation","requalifyClaimsForCodeState","compileKnowledgeWorkspace","syncCanonicalWorkflows","lintKnowledgeWorkspace","isEmbeddingExplicitlyDisabled","backfillVectorEmbeddings","getVectorStatus"]}