memorix 1.9.3 → 1.9.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.
Files changed (65) hide show
  1. package/CHANGELOG.md +49 -1
  2. package/README.md +7 -6
  3. package/README.zh-CN.md +7 -6
  4. package/dist/cli/index.js +930 -330
  5. package/dist/index.d.ts +3 -1
  6. package/dist/index.js +289 -109
  7. package/dist/maintenance-runner.js +179 -117
  8. package/dist/media-audio-runner.js +92 -30
  9. package/dist/media-video-runner.js +92 -30
  10. package/dist/memcode-runtime/CHANGELOG.md +49 -1
  11. package/dist/sdk.d.ts +1 -0
  12. package/dist/sdk.js +1050 -847
  13. package/dist/types.d.ts +1 -1
  14. package/dist/vector-backfill-runner.js +92 -30
  15. package/docs/AGENT_OPERATOR_PLAYBOOK.md +47 -3
  16. package/docs/API_REFERENCE.md +3 -1
  17. package/docs/CONFIGURATION.md +15 -1
  18. package/docs/DEVELOPMENT.md +1 -1
  19. package/docs/DOCKER.md +23 -3
  20. package/docs/INTEGRATIONS.md +1 -1
  21. package/docs/KNOWN_ISSUES_AND_ROADMAP.md +26 -1
  22. package/docs/MULTI-DEVICE-SYNC-RESEARCH.md +4 -0
  23. package/docs/README.md +1 -1
  24. package/docs/SETUP.md +55 -0
  25. package/package.json +2 -2
  26. package/plugins/antigravity/memorix/plugin.json +1 -1
  27. package/plugins/claude/memorix/.claude-plugin/plugin.json +1 -1
  28. package/plugins/codebuddy/memorix/.codebuddy-plugin/plugin.json +1 -1
  29. package/plugins/codex/memorix/.codex-plugin/plugin.json +1 -1
  30. package/plugins/copilot/memorix/plugin.json +1 -1
  31. package/plugins/gemini/memorix/gemini-extension.json +1 -1
  32. package/plugins/hermes/memorix/plugin.yaml +1 -1
  33. package/plugins/omp/memorix/package.json +1 -1
  34. package/plugins/openclaw/memorix/.codex-plugin/plugin.json +1 -1
  35. package/plugins/pi/memorix/package.json +1 -1
  36. package/server.json +2 -2
  37. package/src/cli/command-guide.ts +2 -2
  38. package/src/cli/commands/agent-integrations.ts +57 -0
  39. package/src/cli/commands/background.ts +11 -2
  40. package/src/cli/commands/media.ts +2 -0
  41. package/src/cli/commands/serve-http.ts +193 -42
  42. package/src/cli/commands/setup.ts +77 -10
  43. package/src/cli/commands/sync-store.ts +47 -12
  44. package/src/cli/commands/sync.ts +26 -0
  45. package/src/dashboard/server.ts +10 -12
  46. package/src/integrations/registry.ts +1 -1
  47. package/src/media/minimax.ts +26 -2
  48. package/src/media/video-jobs.ts +9 -1
  49. package/src/memory/graph.ts +10 -8
  50. package/src/memory/session.ts +1 -1
  51. package/src/sdk.ts +24 -0
  52. package/src/server/mcp-binding-store.ts +14 -3
  53. package/src/server.ts +5 -3
  54. package/src/store/file-lock.ts +28 -3
  55. package/src/store/graph-store.ts +178 -46
  56. package/src/store/persistence.ts +14 -9
  57. package/src/store/sqlite-db.ts +6 -3
  58. package/src/store/sqlite-store.ts +32 -27
  59. package/src/sync/engine.ts +9 -7
  60. package/src/sync/namespace.ts +23 -0
  61. package/src/sync/policy.ts +19 -4
  62. package/src/sync/store-port.ts +43 -13
  63. package/src/sync/types.ts +2 -0
  64. package/src/types.ts +1 -1
  65. package/src/workspace/mcp-adapters/grok.ts +32 -0
package/dist/index.js CHANGED
@@ -707,18 +707,21 @@ CREATE TABLE IF NOT EXISTS chat_transcript (
707
707
  `;
708
708
  CREATE_GRAPH_ENTITIES_TABLE = `
709
709
  CREATE TABLE IF NOT EXISTS graph_entities (
710
- name TEXT PRIMARY KEY,
710
+ projectId TEXT NOT NULL,
711
+ name TEXT NOT NULL,
711
712
  entityType TEXT NOT NULL DEFAULT '',
712
- observations TEXT NOT NULL DEFAULT '[]'
713
+ observations TEXT NOT NULL DEFAULT '[]',
714
+ PRIMARY KEY (projectId, name)
713
715
  );
714
716
  `;
715
717
  CREATE_GRAPH_RELATIONS_TABLE = `
716
718
  CREATE TABLE IF NOT EXISTS graph_relations (
717
719
  id INTEGER PRIMARY KEY AUTOINCREMENT,
720
+ projectId TEXT NOT NULL,
718
721
  from_entity TEXT NOT NULL,
719
722
  to_entity TEXT NOT NULL,
720
723
  relationType TEXT NOT NULL DEFAULT '',
721
- UNIQUE(from_entity, to_entity, relationType)
724
+ UNIQUE(projectId, from_entity, to_entity, relationType)
722
725
  );
723
726
  `;
724
727
  CREATE_CODE_FILES_TABLE = `
@@ -1518,6 +1521,21 @@ CREATE UNIQUE INDEX IF NOT EXISTS idx_maintenance_jobs_active_dedupe
1518
1521
  import { promises as fs2 } from "fs";
1519
1522
  import { randomUUID } from "crypto";
1520
1523
  import path4 from "path";
1524
+ function canReclaimStaleLock(raw) {
1525
+ try {
1526
+ const parsed = JSON.parse(raw);
1527
+ const pid = Number(parsed.pid);
1528
+ if (!Number.isSafeInteger(pid) || pid < 1) return true;
1529
+ try {
1530
+ process.kill(pid, 0);
1531
+ return false;
1532
+ } catch (error) {
1533
+ return error.code !== "EPERM";
1534
+ }
1535
+ } catch {
1536
+ return true;
1537
+ }
1538
+ }
1521
1539
  async function acquireLock(lockPath) {
1522
1540
  for (let i2 = 0; i2 < MAX_RETRIES; i2++) {
1523
1541
  try {
@@ -1531,9 +1549,12 @@ async function acquireLock(lockPath) {
1531
1549
  try {
1532
1550
  const stat5 = await fs2.stat(lockPath);
1533
1551
  if (Date.now() - stat5.mtimeMs > LOCK_STALE_MS) {
1534
- await fs2.unlink(lockPath).catch(() => {
1535
- });
1536
- continue;
1552
+ const raw2 = await fs2.readFile(lockPath, "utf8").catch(() => "");
1553
+ if (canReclaimStaleLock(raw2)) {
1554
+ await fs2.unlink(lockPath).catch(() => {
1555
+ });
1556
+ continue;
1557
+ }
1537
1558
  }
1538
1559
  } catch {
1539
1560
  continue;
@@ -1544,6 +1565,10 @@ async function acquireLock(lockPath) {
1544
1565
  }
1545
1566
  }
1546
1567
  }
1568
+ const raw = await fs2.readFile(lockPath, "utf8").catch(() => "");
1569
+ if (!canReclaimStaleLock(raw)) {
1570
+ throw new Error(`Failed to acquire lock: ${lockPath} (owner is still running)`);
1571
+ }
1547
1572
  await fs2.unlink(lockPath).catch(() => {
1548
1573
  });
1549
1574
  try {
@@ -1782,6 +1807,11 @@ async function listProjectDirs(baseDir) {
1782
1807
  }
1783
1808
  }
1784
1809
  async function migrateSubdirsToFlat(baseDir) {
1810
+ const base = baseDir ?? resolveDefaultDataDir();
1811
+ await fs4.mkdir(base, { recursive: true });
1812
+ return withFileLock(base, () => migrateSubdirsToFlatUnlocked(base));
1813
+ }
1814
+ async function migrateSubdirsToFlatUnlocked(baseDir) {
1785
1815
  const base = baseDir ?? resolveDefaultDataDir();
1786
1816
  await fs4.mkdir(base, { recursive: true });
1787
1817
  let entries;
@@ -1838,7 +1868,7 @@ async function migrateSubdirsToFlat(baseDir) {
1838
1868
  for (const { obs } of subdirData) {
1839
1869
  for (const o of obs) {
1840
1870
  const isDuplicate = allObs.some(
1841
- (existing) => existing.title === o.title && existing.createdAt === o.createdAt
1871
+ (existing) => existing.title === o.title && existing.createdAt === o.createdAt && existing.projectId === o.projectId
1842
1872
  );
1843
1873
  if (!isDuplicate) {
1844
1874
  allObs.push(o);
@@ -1871,18 +1901,14 @@ async function migrateSubdirsToFlat(baseDir) {
1871
1901
  mergedRelations.push(rel);
1872
1902
  }
1873
1903
  }
1874
- await fs4.writeFile(path6.join(base, "observations.json"), JSON.stringify(allObs, null, 2), "utf-8");
1875
- await fs4.writeFile(
1876
- path6.join(base, "counter.json"),
1877
- JSON.stringify({ nextId: allObs.length + 1 }),
1878
- "utf-8"
1879
- );
1904
+ await atomicWriteFile(path6.join(base, "observations.json"), JSON.stringify(allObs, null, 2));
1905
+ await atomicWriteFile(path6.join(base, "counter.json"), JSON.stringify({ nextId: allObs.length + 1 }));
1880
1906
  const graphLines = [
1881
1907
  ...[...entityMap.values()].map((e2) => JSON.stringify({ type: "entity", name: e2.name, entityType: e2.entityType, observations: e2.observations })),
1882
1908
  ...mergedRelations.map((r2) => JSON.stringify({ type: "relation", from: r2.from, to: r2.to, relationType: r2.relationType }))
1883
1909
  ];
1884
1910
  if (graphLines.length > 0) {
1885
- await fs4.writeFile(path6.join(base, "graph.jsonl"), graphLines.join("\n"), "utf-8");
1911
+ await atomicWriteFile(path6.join(base, "graph.jsonl"), graphLines.join("\n"));
1886
1912
  }
1887
1913
  let allSessions = [];
1888
1914
  try {
@@ -1900,7 +1926,7 @@ async function migrateSubdirsToFlat(baseDir) {
1900
1926
  }
1901
1927
  }
1902
1928
  if (allSessions.length > 0) {
1903
- await fs4.writeFile(path6.join(base, "sessions.json"), JSON.stringify(allSessions, null, 2), "utf-8");
1929
+ await atomicWriteFile(path6.join(base, "sessions.json"), JSON.stringify(allSessions, null, 2));
1904
1930
  }
1905
1931
  const backupDir = path6.join(base, ".migrated-subdirs");
1906
1932
  await fs4.mkdir(backupDir, { recursive: true });
@@ -1936,6 +1962,7 @@ var init_persistence = __esm({
1936
1962
  "src/store/persistence.ts"() {
1937
1963
  "use strict";
1938
1964
  init_esm_shims();
1965
+ init_file_lock();
1939
1966
  init_persistence_json();
1940
1967
  }
1941
1968
  });
@@ -1943,6 +1970,7 @@ var init_persistence = __esm({
1943
1970
  // src/store/graph-store.ts
1944
1971
  var graph_store_exports = {};
1945
1972
  __export(graph_store_exports, {
1973
+ DEFAULT_GRAPH_PROJECT_ID: () => DEFAULT_GRAPH_PROJECT_ID,
1946
1974
  GraphSqliteStore: () => GraphSqliteStore,
1947
1975
  getGraphStore: () => getGraphStore,
1948
1976
  initGraphStore: () => initGraphStore,
@@ -1972,37 +2000,106 @@ function entityToRow(entity) {
1972
2000
  observations: JSON.stringify(entity.observations ?? [])
1973
2001
  };
1974
2002
  }
1975
- async function initGraphStore(dataDir) {
1976
- if (_graphStore && _graphDataDir === dataDir) return _graphStore;
1977
- _graphStore = new GraphSqliteStore();
1978
- await _graphStore.init(dataDir);
1979
- _graphDataDir = dataDir;
1980
- return _graphStore;
2003
+ function ensureScopedGraphSchema(db2) {
2004
+ const entityColumns = db2.prepare("PRAGMA table_info(graph_entities)").all();
2005
+ if (!entityColumns.some((column) => column.name === "projectId")) {
2006
+ const migrate = db2.transaction(() => {
2007
+ db2.exec("ALTER TABLE graph_entities RENAME TO graph_entities_legacy_unscoped");
2008
+ db2.exec(CREATE_SCOPED_GRAPH_ENTITIES);
2009
+ db2.exec(`INSERT INTO graph_entities (projectId, name, entityType, observations)
2010
+ SELECT '${LEGACY_GRAPH_PROJECT_ID}', name, entityType, observations
2011
+ FROM graph_entities_legacy_unscoped`);
2012
+ db2.exec("DROP TABLE graph_entities_legacy_unscoped");
2013
+ });
2014
+ migrate();
2015
+ } else {
2016
+ db2.exec(CREATE_SCOPED_GRAPH_ENTITIES);
2017
+ }
2018
+ const relationColumns = db2.prepare("PRAGMA table_info(graph_relations)").all();
2019
+ if (!relationColumns.some((column) => column.name === "projectId")) {
2020
+ const migrate = db2.transaction(() => {
2021
+ db2.exec("ALTER TABLE graph_relations RENAME TO graph_relations_legacy_unscoped");
2022
+ db2.exec(CREATE_SCOPED_GRAPH_RELATIONS);
2023
+ db2.exec(`INSERT INTO graph_relations (projectId, from_entity, to_entity, relationType)
2024
+ SELECT '${LEGACY_GRAPH_PROJECT_ID}', from_entity, to_entity, relationType
2025
+ FROM graph_relations_legacy_unscoped`);
2026
+ db2.exec("DROP TABLE graph_relations_legacy_unscoped");
2027
+ });
2028
+ migrate();
2029
+ } else {
2030
+ db2.exec(CREATE_SCOPED_GRAPH_RELATIONS);
2031
+ }
1981
2032
  }
1982
- function getGraphStore() {
1983
- if (!_graphStore) throw new Error("[memorix] GraphStore not initialized \u2014 call initGraphStore() first");
1984
- return _graphStore;
2033
+ function graphStoreKey(dataDir, projectId) {
2034
+ return `${path7.resolve(dataDir)}\0${projectId}`;
2035
+ }
2036
+ async function initGraphStore(dataDir, projectId = DEFAULT_GRAPH_PROJECT_ID) {
2037
+ const key = graphStoreKey(dataDir, projectId);
2038
+ const existing = _graphStores.get(key);
2039
+ if (existing) {
2040
+ _graphStores.delete(key);
2041
+ _graphStores.set(key, existing);
2042
+ _activeGraphKey = key;
2043
+ return existing;
2044
+ }
2045
+ const store = new GraphSqliteStore();
2046
+ await store.init(dataDir, projectId);
2047
+ _graphStores.set(key, store);
2048
+ while (_graphStores.size > MAX_GRAPH_STORE_CACHE) {
2049
+ const oldest = _graphStores.keys().next().value;
2050
+ if (!oldest) break;
2051
+ _graphStores.delete(oldest);
2052
+ }
2053
+ _activeGraphKey = key;
2054
+ return store;
2055
+ }
2056
+ function getGraphStore(dataDir, projectId) {
2057
+ const key = dataDir && projectId ? graphStoreKey(dataDir, projectId) : _activeGraphKey;
2058
+ const store = key ? _graphStores.get(key) : void 0;
2059
+ if (!store) throw new Error("[memorix] GraphStore not initialized \u2014 call initGraphStore() first");
2060
+ return store;
1985
2061
  }
1986
2062
  function resetGraphStore() {
1987
- if (_graphStore) {
2063
+ for (const store of _graphStores.values()) {
1988
2064
  try {
1989
- _graphStore.close();
2065
+ store.close();
1990
2066
  } catch {
1991
2067
  }
1992
2068
  }
1993
- _graphStore = null;
1994
- _graphDataDir = null;
2069
+ _graphStores.clear();
2070
+ _activeGraphKey = null;
1995
2071
  }
1996
- var GraphSqliteStore, _graphStore, _graphDataDir;
2072
+ var DEFAULT_GRAPH_PROJECT_ID, LEGACY_GRAPH_PROJECT_ID, MAX_GRAPH_STORE_CACHE, CREATE_SCOPED_GRAPH_ENTITIES, CREATE_SCOPED_GRAPH_RELATIONS, GraphSqliteStore, _graphStores, _activeGraphKey;
1997
2073
  var init_graph_store = __esm({
1998
2074
  "src/store/graph-store.ts"() {
1999
2075
  "use strict";
2000
2076
  init_esm_shims();
2001
2077
  init_sqlite_db();
2002
2078
  init_persistence();
2079
+ DEFAULT_GRAPH_PROJECT_ID = "__default__";
2080
+ LEGACY_GRAPH_PROJECT_ID = "__legacy__";
2081
+ MAX_GRAPH_STORE_CACHE = 32;
2082
+ CREATE_SCOPED_GRAPH_ENTITIES = `
2083
+ CREATE TABLE IF NOT EXISTS graph_entities (
2084
+ projectId TEXT NOT NULL,
2085
+ name TEXT NOT NULL,
2086
+ entityType TEXT NOT NULL DEFAULT '',
2087
+ observations TEXT NOT NULL DEFAULT '[]',
2088
+ PRIMARY KEY (projectId, name)
2089
+ );`;
2090
+ CREATE_SCOPED_GRAPH_RELATIONS = `
2091
+ CREATE TABLE IF NOT EXISTS graph_relations (
2092
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
2093
+ projectId TEXT NOT NULL,
2094
+ from_entity TEXT NOT NULL,
2095
+ to_entity TEXT NOT NULL,
2096
+ relationType TEXT NOT NULL DEFAULT '',
2097
+ UNIQUE(projectId, from_entity, to_entity, relationType)
2098
+ );`;
2003
2099
  GraphSqliteStore = class {
2004
2100
  db = null;
2005
2101
  dataDir = "";
2102
+ projectId = DEFAULT_GRAPH_PROJECT_ID;
2006
2103
  stmtInsertEntity = null;
2007
2104
  stmtUpdateEntityObs = null;
2008
2105
  stmtDeleteEntity = null;
@@ -2012,45 +2109,89 @@ var init_graph_store = __esm({
2012
2109
  stmtDeleteRelation = null;
2013
2110
  stmtDeleteRelationsByEntity = null;
2014
2111
  stmtSelectAllRelations = null;
2015
- async init(dataDir) {
2112
+ async init(dataDir, projectId = DEFAULT_GRAPH_PROJECT_ID) {
2016
2113
  this.dataDir = dataDir;
2114
+ this.projectId = projectId;
2017
2115
  this.db = getDatabase(dataDir);
2116
+ ensureScopedGraphSchema(this.db);
2018
2117
  this.stmtInsertEntity = this.db.prepare(
2019
- `INSERT OR REPLACE INTO graph_entities (name, entityType, observations) VALUES (@name, @entityType, @observations)`
2118
+ `INSERT OR REPLACE INTO graph_entities (projectId, name, entityType, observations) VALUES (@projectId, @name, @entityType, @observations)`
2020
2119
  );
2021
2120
  this.stmtUpdateEntityObs = this.db.prepare(
2022
- `UPDATE graph_entities SET observations = @observations WHERE name = @name`
2121
+ `UPDATE graph_entities SET observations = @observations WHERE projectId = @projectId AND name = @name`
2023
2122
  );
2024
- this.stmtDeleteEntity = this.db.prepare(`DELETE FROM graph_entities WHERE name = ?`);
2025
- this.stmtSelectAllEntities = this.db.prepare(`SELECT * FROM graph_entities`);
2026
- this.stmtSelectEntityByName = this.db.prepare(`SELECT * FROM graph_entities WHERE name = ?`);
2123
+ this.stmtDeleteEntity = this.db.prepare(`DELETE FROM graph_entities WHERE projectId = ? AND name = ?`);
2124
+ this.stmtSelectAllEntities = this.db.prepare(`SELECT * FROM graph_entities WHERE projectId = ? ORDER BY name`);
2125
+ this.stmtSelectEntityByName = this.db.prepare(`SELECT * FROM graph_entities WHERE projectId = ? AND name = ?`);
2027
2126
  this.stmtInsertRelation = this.db.prepare(
2028
- `INSERT OR IGNORE INTO graph_relations (from_entity, to_entity, relationType) VALUES (@from, @to, @relationType)`
2127
+ `INSERT OR IGNORE INTO graph_relations (projectId, from_entity, to_entity, relationType) VALUES (@projectId, @from, @to, @relationType)`
2029
2128
  );
2030
2129
  this.stmtDeleteRelation = this.db.prepare(
2031
- `DELETE FROM graph_relations WHERE from_entity = ? AND to_entity = ? AND relationType = ?`
2130
+ `DELETE FROM graph_relations WHERE projectId = ? AND from_entity = ? AND to_entity = ? AND relationType = ?`
2032
2131
  );
2033
2132
  this.stmtDeleteRelationsByEntity = this.db.prepare(
2034
- `DELETE FROM graph_relations WHERE from_entity = ? OR to_entity = ?`
2133
+ `DELETE FROM graph_relations WHERE projectId = ? AND (from_entity = ? OR to_entity = ?)`
2035
2134
  );
2036
- this.stmtSelectAllRelations = this.db.prepare(`SELECT * FROM graph_relations`);
2135
+ this.stmtSelectAllRelations = this.db.prepare(`SELECT * FROM graph_relations WHERE projectId = ? ORDER BY id`);
2037
2136
  await this.migrateFromJsonlIfNeeded();
2038
2137
  }
2039
2138
  async migrateFromJsonlIfNeeded() {
2040
- const count2 = this.db.prepare(`SELECT COUNT(*) AS cnt FROM graph_entities`).get();
2139
+ const count2 = this.db.prepare(`SELECT COUNT(*) AS cnt FROM graph_entities WHERE projectId = ?`).get(this.projectId);
2140
+ const totalCount = this.db.prepare(`SELECT COUNT(*) AS cnt FROM graph_entities`).get();
2041
2141
  if (count2.cnt > 0) return;
2142
+ if (totalCount.cnt > 0) return;
2042
2143
  const jsonlPath = path7.join(this.dataDir, "graph.jsonl");
2043
2144
  if (!fs5.existsSync(jsonlPath)) return;
2044
2145
  try {
2045
2146
  const data = await loadGraphJsonl(this.dataDir);
2046
2147
  if (data.entities.length === 0 && data.relations.length === 0) return;
2047
2148
  console.error(`[memorix] Migrating graph from JSONL to SQLite (${data.entities.length} entities, ${data.relations.length} relations)...`);
2149
+ const observations2 = this.db.prepare("SELECT id, projectId FROM observations").all();
2150
+ const projectByObservationId = new Map(observations2.map((row) => [row.id, row.projectId]));
2151
+ const projectsByEntity = /* @__PURE__ */ new Map();
2152
+ for (const entity of data.entities) {
2153
+ const projects = /* @__PURE__ */ new Set();
2154
+ for (const content of entity.observations ?? []) {
2155
+ const match2 = /^\[#(\d+)\]/.exec(content);
2156
+ const projectId = match2 ? projectByObservationId.get(Number(match2[1])) : void 0;
2157
+ if (projectId) projects.add(projectId);
2158
+ }
2159
+ projectsByEntity.set(entity.name, projects);
2160
+ }
2161
+ let changed = true;
2162
+ while (changed) {
2163
+ changed = false;
2164
+ for (const relation of data.relations) {
2165
+ const from = projectsByEntity.get(relation.from) ?? /* @__PURE__ */ new Set();
2166
+ const to = projectsByEntity.get(relation.to) ?? /* @__PURE__ */ new Set();
2167
+ if (from.size > 0 && to.size === 0) {
2168
+ projectsByEntity.set(relation.to, new Set(from));
2169
+ changed = true;
2170
+ } else if (to.size > 0 && from.size === 0) {
2171
+ projectsByEntity.set(relation.from, new Set(to));
2172
+ changed = true;
2173
+ }
2174
+ }
2175
+ }
2176
+ const entityRows = data.entities.flatMap((entity) => {
2177
+ const projects = projectsByEntity.get(entity.name) ?? /* @__PURE__ */ new Set();
2178
+ const owners = projects.size > 0 ? [...projects] : [this.projectId];
2179
+ return owners.map((projectId) => ({ ...entityToRow(entity), projectId }));
2180
+ });
2181
+ const projectSet = new Set(entityRows.map((row) => String(row.projectId)));
2182
+ const relationRows = data.relations.flatMap((relation) => {
2183
+ const from = projectsByEntity.get(relation.from) ?? /* @__PURE__ */ new Set();
2184
+ const to = projectsByEntity.get(relation.to) ?? /* @__PURE__ */ new Set();
2185
+ const shared = [...from].filter((projectId) => to.has(projectId));
2186
+ const owners = shared.length > 0 ? shared : from.size === 0 && to.size === 0 ? [this.projectId] : [];
2187
+ return owners.filter((projectId) => projectSet.has(projectId)).map((projectId) => ({ projectId, from: relation.from, to: relation.to, relationType: relation.relationType }));
2188
+ });
2048
2189
  const insertAll = this.db.transaction(() => {
2049
- for (const entity of data.entities) {
2050
- this.stmtInsertEntity.run(entityToRow(entity));
2190
+ for (const entity of entityRows) {
2191
+ this.stmtInsertEntity.run(entity);
2051
2192
  }
2052
- for (const rel of data.relations) {
2053
- this.stmtInsertRelation.run({ from: rel.from, to: rel.to, relationType: rel.relationType });
2193
+ for (const relation of relationRows) {
2194
+ this.stmtInsertRelation.run(relation);
2054
2195
  }
2055
2196
  });
2056
2197
  insertAll();
@@ -2060,10 +2201,10 @@ var init_graph_store = __esm({
2060
2201
  }
2061
2202
  }
2062
2203
  loadEntities() {
2063
- return this.stmtSelectAllEntities.all().map(rowToEntity);
2204
+ return this.stmtSelectAllEntities.all(this.projectId).map(rowToEntity);
2064
2205
  }
2065
2206
  loadRelations() {
2066
- return this.stmtSelectAllRelations.all().map((row) => ({
2207
+ return this.stmtSelectAllRelations.all(this.projectId).map((row) => ({
2067
2208
  from: row.from_entity,
2068
2209
  to: row.to_entity,
2069
2210
  relationType: row.relationType
@@ -2072,7 +2213,7 @@ var init_graph_store = __esm({
2072
2213
  insertEntities(entities) {
2073
2214
  const insertAll = this.db.transaction(() => {
2074
2215
  for (const entity of entities) {
2075
- this.stmtInsertEntity.run(entityToRow(entity));
2216
+ this.stmtInsertEntity.run({ ...entityToRow(entity), projectId: this.projectId });
2076
2217
  }
2077
2218
  });
2078
2219
  insertAll();
@@ -2080,7 +2221,7 @@ var init_graph_store = __esm({
2080
2221
  insertRelations(relations) {
2081
2222
  const insertAll = this.db.transaction(() => {
2082
2223
  for (const rel of relations) {
2083
- this.stmtInsertRelation.run({ from: rel.from, to: rel.to, relationType: rel.relationType });
2224
+ this.stmtInsertRelation.run({ projectId: this.projectId, from: rel.from, to: rel.to, relationType: rel.relationType });
2084
2225
  }
2085
2226
  });
2086
2227
  insertAll();
@@ -2088,8 +2229,8 @@ var init_graph_store = __esm({
2088
2229
  deleteEntities(names) {
2089
2230
  const deleteAll = this.db.transaction(() => {
2090
2231
  for (const name of names) {
2091
- this.stmtDeleteRelationsByEntity.run(name, name);
2092
- this.stmtDeleteEntity.run(name);
2232
+ this.stmtDeleteRelationsByEntity.run(this.projectId, name, name);
2233
+ this.stmtDeleteEntity.run(this.projectId, name);
2093
2234
  }
2094
2235
  });
2095
2236
  deleteAll();
@@ -2097,7 +2238,7 @@ var init_graph_store = __esm({
2097
2238
  deleteRelations(relations) {
2098
2239
  const deleteAll = this.db.transaction(() => {
2099
2240
  for (const rel of relations) {
2100
- this.stmtDeleteRelation.run(rel.from, rel.to, rel.relationType);
2241
+ this.stmtDeleteRelation.run(this.projectId, rel.from, rel.to, rel.relationType);
2101
2242
  }
2102
2243
  });
2103
2244
  deleteAll();
@@ -2105,13 +2246,13 @@ var init_graph_store = __esm({
2105
2246
  addObservations(updates) {
2106
2247
  const updateAll = this.db.transaction(() => {
2107
2248
  for (const u of updates) {
2108
- const row = this.stmtSelectEntityByName.get(u.entityName);
2249
+ const row = this.stmtSelectEntityByName.get(this.projectId, u.entityName);
2109
2250
  if (!row) continue;
2110
2251
  const existing = safeJsonParse(row.observations, []);
2111
2252
  const newObs = u.contents.filter((c) => !existing.includes(c));
2112
2253
  if (newObs.length > 0) {
2113
2254
  existing.push(...newObs);
2114
- this.stmtUpdateEntityObs.run({ name: u.entityName, observations: JSON.stringify(existing) });
2255
+ this.stmtUpdateEntityObs.run({ projectId: this.projectId, name: u.entityName, observations: JSON.stringify(existing) });
2115
2256
  }
2116
2257
  }
2117
2258
  });
@@ -2120,11 +2261,11 @@ var init_graph_store = __esm({
2120
2261
  deleteObservations(deletions) {
2121
2262
  const deleteAll = this.db.transaction(() => {
2122
2263
  for (const d of deletions) {
2123
- const row = this.stmtSelectEntityByName.get(d.entityName);
2264
+ const row = this.stmtSelectEntityByName.get(this.projectId, d.entityName);
2124
2265
  if (!row) continue;
2125
2266
  const existing = safeJsonParse(row.observations, []);
2126
2267
  const filtered = existing.filter((o) => !d.observations.includes(o));
2127
- this.stmtUpdateEntityObs.run({ name: d.entityName, observations: JSON.stringify(filtered) });
2268
+ this.stmtUpdateEntityObs.run({ projectId: this.projectId, name: d.entityName, observations: JSON.stringify(filtered) });
2128
2269
  }
2129
2270
  });
2130
2271
  deleteAll();
@@ -2135,13 +2276,13 @@ var init_graph_store = __esm({
2135
2276
  */
2136
2277
  replaceAll(entities, relations) {
2137
2278
  const replaceAll = this.db.transaction(() => {
2138
- this.db.prepare("DELETE FROM graph_relations").run();
2139
- this.db.prepare("DELETE FROM graph_entities").run();
2279
+ this.db.prepare("DELETE FROM graph_relations WHERE projectId = ?").run(this.projectId);
2280
+ this.db.prepare("DELETE FROM graph_entities WHERE projectId = ?").run(this.projectId);
2140
2281
  for (const entity of entities) {
2141
- this.stmtInsertEntity.run(entityToRow(entity));
2282
+ this.stmtInsertEntity.run({ ...entityToRow(entity), projectId: this.projectId });
2142
2283
  }
2143
2284
  for (const rel of relations) {
2144
- this.stmtInsertRelation.run({ from: rel.from, to: rel.to, relationType: rel.relationType });
2285
+ this.stmtInsertRelation.run({ projectId: this.projectId, from: rel.from, to: rel.to, relationType: rel.relationType });
2145
2286
  }
2146
2287
  });
2147
2288
  replaceAll();
@@ -2149,8 +2290,8 @@ var init_graph_store = __esm({
2149
2290
  close() {
2150
2291
  }
2151
2292
  };
2152
- _graphStore = null;
2153
- _graphDataDir = null;
2293
+ _graphStores = /* @__PURE__ */ new Map();
2294
+ _activeGraphKey = null;
2154
2295
  }
2155
2296
  });
2156
2297
 
@@ -2165,11 +2306,14 @@ var init_graph = __esm({
2165
2306
  entities = [];
2166
2307
  relations = [];
2167
2308
  projectDir;
2309
+ projectId;
2310
+ store = null;
2168
2311
  initialized = false;
2169
2312
  /** Index: lowercase entity name → Entity for O(1) lookups */
2170
2313
  entityIndex = /* @__PURE__ */ new Map();
2171
- constructor(projectDir2) {
2314
+ constructor(projectDir2, projectId = "__default__") {
2172
2315
  this.projectDir = projectDir2;
2316
+ this.projectId = projectId;
2173
2317
  }
2174
2318
  /** Rebuild the entity name index */
2175
2319
  rebuildIndex() {
@@ -2181,10 +2325,9 @@ var init_graph = __esm({
2181
2325
  /** Load graph from SQLite on first access */
2182
2326
  async init() {
2183
2327
  if (this.initialized) return;
2184
- await initGraphStore(this.projectDir);
2185
- const store = getGraphStore();
2186
- this.entities = store.loadEntities();
2187
- this.relations = store.loadRelations();
2328
+ this.store = await initGraphStore(this.projectDir, this.projectId);
2329
+ this.entities = this.store.loadEntities();
2330
+ this.relations = this.store.loadRelations();
2188
2331
  this.rebuildIndex();
2189
2332
  this.initialized = true;
2190
2333
  }
@@ -2198,8 +2341,8 @@ var init_graph = __esm({
2198
2341
  }
2199
2342
  /** Persist current state to SQLite */
2200
2343
  async save() {
2201
- const store = getGraphStore();
2202
- store.replaceAll(this.entities, this.relations);
2344
+ if (!this.store) throw new Error("[memorix] KnowledgeGraphManager not initialized");
2345
+ this.store.replaceAll(this.entities, this.relations);
2203
2346
  }
2204
2347
  /** Create new entities (skip duplicates by name) */
2205
2348
  async createEntities(entities) {
@@ -6986,6 +7129,7 @@ var init_sqlite_store = __esm({
6986
7129
  init_sqlite_db();
6987
7130
  init_sqlite_reliability();
6988
7131
  init_sqlite_fts();
7132
+ init_file_lock();
6989
7133
  SqliteBackend = class {
6990
7134
  db = null;
6991
7135
  dataDir = "";
@@ -7149,38 +7293,43 @@ var init_sqlite_store = __esm({
7149
7293
  }
7150
7294
  // ── Migration ────────────────────────────────────────────────────
7151
7295
  async migrateFromJsonIfNeeded() {
7152
- const count2 = this.db.prepare(`SELECT COUNT(*) AS cnt FROM observations`).get();
7153
- if (count2.cnt > 0) return;
7154
7296
  const jsonPath = path10.join(this.dataDir, "observations.json");
7155
7297
  if (!fs7.existsSync(jsonPath)) return;
7156
- try {
7298
+ await withFileLock(this.dataDir, async () => {
7299
+ const count2 = this.db.prepare(`SELECT COUNT(*) AS cnt FROM observations`).get();
7300
+ if (count2.cnt > 0) return;
7157
7301
  const raw = fs7.readFileSync(jsonPath, "utf-8");
7158
- const observations2 = JSON.parse(raw);
7302
+ const parsed = JSON.parse(raw);
7303
+ if (!Array.isArray(parsed)) {
7304
+ throw new Error("[memorix] observations.json migration refused: expected a JSON array");
7305
+ }
7306
+ const observations2 = parsed;
7159
7307
  if (observations2.length === 0) return;
7308
+ if (observations2.some((obs) => !obs || !Number.isSafeInteger(obs.id) || obs.id < 1 || typeof obs.projectId !== "string")) {
7309
+ throw new Error("[memorix] observations.json migration refused: invalid observation record");
7310
+ }
7160
7311
  console.error(`[memorix] Migrating ${observations2.length} observations from JSON to SQLite...`);
7161
7312
  const insertMany = this.db.transaction((obsList) => {
7162
7313
  for (const obs of obsList) {
7163
7314
  this.stmtInsert.run(obsToRow(obs));
7164
7315
  }
7165
- });
7166
- insertMany(observations2);
7167
- const counterPath = path10.join(this.dataDir, "counter.json");
7168
- if (fs7.existsSync(counterPath)) {
7169
- try {
7316
+ const counterPath = path10.join(this.dataDir, "counter.json");
7317
+ let counterNextId;
7318
+ if (fs7.existsSync(counterPath)) {
7170
7319
  const counterData = JSON.parse(fs7.readFileSync(counterPath, "utf-8"));
7171
- const nextId2 = counterData.nextId ?? counterData.next_id ?? Math.max(...observations2.map((o) => o.id)) + 1;
7172
- this.rawSaveIdCounter(nextId2);
7173
- } catch {
7174
- this.rawSaveIdCounter(Math.max(...observations2.map((o) => o.id)) + 1);
7320
+ const candidate = counterData.nextId ?? counterData.next_id;
7321
+ if (candidate !== void 0 && (!Number.isSafeInteger(candidate) || Number(candidate) < 1)) {
7322
+ throw new Error("[memorix] counter.json migration refused: nextId must be a positive integer");
7323
+ }
7324
+ counterNextId = candidate === void 0 ? void 0 : Number(candidate);
7175
7325
  }
7176
- } else {
7177
- this.rawSaveIdCounter(Math.max(...observations2.map((o) => o.id)) + 1);
7178
- }
7179
- this.bumpGeneration();
7326
+ const maxId = Math.max(...obsList.map((obs) => obs.id));
7327
+ this.rawSaveIdCounter(Math.max(counterNextId ?? 1, maxId + 1));
7328
+ this.bumpGeneration();
7329
+ });
7330
+ insertMany(observations2);
7180
7331
  console.error(`[memorix] Migration complete. ${observations2.length} observations now in SQLite.`);
7181
- } catch (err) {
7182
- console.error(`[memorix] JSON\u2192SQLite migration failed (non-fatal, data preserved in JSON): ${err}`);
7183
- }
7332
+ });
7184
7333
  }
7185
7334
  // ── Public read ──────────────────────────────────────────────────
7186
7335
  async loadAll() {
@@ -145188,7 +145337,20 @@ function normalizeMiniMaxVideoRequest(input) {
145188
145337
  if (ratio !== "adaptive" && ratio !== "16:9" && ratio !== "9:16" && ratio !== "1:1") {
145189
145338
  throw new Error("MiniMax video ratio must be adaptive, 16:9, 9:16, or 1:1");
145190
145339
  }
145191
- return { region, model, prompt, resolution, duration, ratio };
145340
+ let firstFrameImageUrl;
145341
+ if (input.firstFrameImageUrl !== void 0) {
145342
+ firstFrameImageUrl = input.firstFrameImageUrl.trim();
145343
+ let parsed;
145344
+ try {
145345
+ parsed = new URL(firstFrameImageUrl);
145346
+ } catch {
145347
+ throw new Error("MiniMax first-frame image must be a public HTTPS URL");
145348
+ }
145349
+ if (parsed.protocol !== "https:" || parsed.username || parsed.password || sanitizeCredentials(firstFrameImageUrl) !== firstFrameImageUrl) {
145350
+ throw new Error("MiniMax first-frame image must be an HTTPS URL without credentials");
145351
+ }
145352
+ }
145353
+ return { region, model, prompt, resolution, duration, ratio, ...firstFrameImageUrl ? { firstFrameImageUrl } : {} };
145192
145354
  }
145193
145355
  function videoRequestConfig(input) {
145194
145356
  const normalized = normalizeMiniMaxVideoRequest(input);
@@ -145265,7 +145427,14 @@ async function createMiniMaxVideoTask(input, dependencies = {}) {
145265
145427
  headers: videoHeaders(config.apiKey),
145266
145428
  body: JSON.stringify({
145267
145429
  model: config.model,
145268
- content: [{ type: "text", text: config.prompt }],
145430
+ content: [
145431
+ { type: "text", text: config.prompt },
145432
+ ...config.firstFrameImageUrl ? [{
145433
+ type: "image_url",
145434
+ image_url: { url: config.firstFrameImageUrl },
145435
+ role: "first_frame"
145436
+ }] : []
145437
+ ],
145269
145438
  resolution: config.resolution,
145270
145439
  duration: config.duration,
145271
145440
  ratio: config.ratio
@@ -145513,10 +145682,19 @@ function parseStoredRequest(value) {
145513
145682
  const duration = value.duration;
145514
145683
  const ratio = value.ratio;
145515
145684
  const maxBytes = value.maxBytes;
145516
- if (provider2 !== "minimax" && provider2 !== "minimax-cn" || region !== "global" && region !== "cn" || model !== "MiniMax-H3" || typeof prompt !== "string" || resolution !== "2K" || duration !== 5 && duration !== 10 || ratio !== "adaptive" && ratio !== "16:9" && ratio !== "9:16" && ratio !== "1:1" || typeof maxBytes !== "number" || !Number.isSafeInteger(maxBytes) || maxBytes < 1) {
145685
+ if (provider2 !== "minimax" && provider2 !== "minimax-cn" || region !== "global" && region !== "cn" || model !== "MiniMax-H3" || typeof prompt !== "string" || value.firstFrameImageUrl !== void 0 && typeof value.firstFrameImageUrl !== "string" || resolution !== "2K" || duration !== 5 && duration !== 10 || ratio !== "adaptive" && ratio !== "16:9" && ratio !== "9:16" && ratio !== "1:1" || typeof maxBytes !== "number" || !Number.isSafeInteger(maxBytes) || maxBytes < 1) {
145517
145686
  throw new Error("Media video job has an invalid request payload");
145518
145687
  }
145519
- return { provider: provider2, region, model, prompt, resolution, duration, ratio, maxBytes };
145688
+ const normalized = normalizeMiniMaxVideoRequest({
145689
+ region,
145690
+ model,
145691
+ prompt,
145692
+ resolution,
145693
+ duration,
145694
+ ratio,
145695
+ firstFrameImageUrl: value.firstFrameImageUrl
145696
+ });
145697
+ return { provider: provider2, ...normalized, maxBytes };
145520
145698
  }
145521
145699
  function mediaJobIdFromMaintenance(job) {
145522
145700
  const mediaJobId = job.payload.mediaJobId;
@@ -145528,6 +145706,7 @@ function mediaJobIdFromMaintenance(job) {
145528
145706
  function toVideoRequest(request) {
145529
145707
  return {
145530
145708
  prompt: request.prompt,
145709
+ firstFrameImageUrl: request.firstFrameImageUrl,
145531
145710
  model: request.model,
145532
145711
  region: request.region,
145533
145712
  resolution: request.resolution,
@@ -145619,6 +145798,7 @@ function queueMiniMaxVideoGeneration(input) {
145619
145798
  region: normalized.region,
145620
145799
  model: normalized.model,
145621
145800
  prompt: normalized.prompt,
145801
+ ...normalized.firstFrameImageUrl ? { firstFrameImageUrl: normalized.firstFrameImageUrl } : {},
145622
145802
  resolution: normalized.resolution,
145623
145803
  duration: normalized.duration,
145624
145804
  ratio: normalized.ratio,
@@ -159771,7 +159951,7 @@ var init_request_context = __esm({
159771
159951
  function getMcpServerInfo() {
159772
159952
  return {
159773
159953
  name: "memorix",
159774
- version: true ? "1.9.3" : "1.0.1"
159954
+ version: true ? "1.9.5" : "1.0.1"
159775
159955
  };
159776
159956
  }
159777
159957
  function createMcpDiscoverResult(capabilities, serverInfo) {
@@ -160166,7 +160346,7 @@ async function getSessionContext(projectDir2, projectId, limit2 = 3, reader2) {
160166
160346
  let graphNeighbors = [];
160167
160347
  if (!reader2 && activeEntities.length > 0) {
160168
160348
  try {
160169
- const graphMgr = new KnowledgeGraphManager(projectDir2);
160349
+ const graphMgr = new KnowledgeGraphManager(projectDir2, projectId);
160170
160350
  await graphMgr.init();
160171
160351
  const { relations } = await graphMgr.readGraph();
160172
160352
  const activeSet = new Set(activeEntities.map((n) => n.toLowerCase()));
@@ -166508,8 +166688,7 @@ async function handleApi(req, res, dataDir, projectId, projectName, baseDir, pro
166508
166688
  break;
166509
166689
  }
166510
166690
  case "/graph": {
166511
- await initGraphStore(effectiveDataDir);
166512
- const gStore = getGraphStore();
166691
+ const gStore = await initGraphStore(effectiveDataDir, effectiveProjectId);
166513
166692
  const graph = { entities: gStore.loadEntities(), relations: gStore.loadRelations() };
166514
166693
  const graphObs = filterDashboardObservations(
166515
166694
  await getObservationStore().loadByProject(effectiveProjectId, { status: "active" }),
@@ -166553,8 +166732,8 @@ async function handleApi(req, res, dataDir, projectId, projectName, baseDir, pro
166553
166732
  break;
166554
166733
  }
166555
166734
  case "/stats": {
166556
- await initGraphStore(effectiveDataDir);
166557
- const graph = { entities: getGraphStore().loadEntities(), relations: getGraphStore().loadRelations() };
166735
+ const gStore = await initGraphStore(effectiveDataDir, effectiveProjectId);
166736
+ const graph = { entities: gStore.loadEntities(), relations: gStore.loadRelations() };
166558
166737
  const observations2 = filterDashboardObservations(
166559
166738
  await getObservationStore().loadByProject(effectiveProjectId, { status: "active" }),
166560
166739
  effectiveProjectId
@@ -166747,15 +166926,15 @@ async function handleApi(req, res, dataDir, projectId, projectName, baseDir, pro
166747
166926
  case "/knowledge-graph": {
166748
166927
  const { generateKnowledgeGraph: generateKnowledgeGraph2 } = await Promise.resolve().then(() => (init_knowledge_graph(), knowledge_graph_exports));
166749
166928
  const { initMiniSkillStore: initMiniSkillStore2, getMiniSkillStore: getMiniSkillStore2 } = await Promise.resolve().then(() => (init_mini_skill_store(), mini_skill_store_exports));
166750
- const { initGraphStore: initGraphStore2, getGraphStore: getGraphStore2 } = await Promise.resolve().then(() => (init_graph_store(), graph_store_exports));
166929
+ const { initGraphStore: initGraphStore2 } = await Promise.resolve().then(() => (init_graph_store(), graph_store_exports));
166751
166930
  await initMiniSkillStore2(effectiveDataDir);
166752
- await initGraphStore2(effectiveDataDir);
166931
+ const gStore = await initGraphStore2(effectiveDataDir, effectiveProjectId);
166753
166932
  const allObs = filterDashboardObservations(
166754
166933
  await getObservationStore().loadByProject(effectiveProjectId, { status: "active" }),
166755
166934
  effectiveProjectId
166756
166935
  );
166757
166936
  const skills = await getMiniSkillStore2().loadByProject(effectiveProjectId);
166758
- const fullGraph = { entities: getGraphStore2().loadEntities(), relations: getGraphStore2().loadRelations() };
166937
+ const fullGraph = { entities: gStore.loadEntities(), relations: gStore.loadRelations() };
166759
166938
  const scoped = scopeKnowledgeGraphToProject(fullGraph, allObs);
166760
166939
  const graph = generateKnowledgeGraph2({
166761
166940
  projectId: effectiveProjectId,
@@ -166952,8 +167131,7 @@ async function handleApi(req, res, dataDir, projectId, projectName, baseDir, pro
166952
167131
  } else {
166953
167132
  await obsStore.remove(obsId);
166954
167133
  try {
166955
- await initGraphStore(effectiveDataDir);
166956
- const gStore = getGraphStore();
167134
+ const gStore = await initGraphStore(effectiveDataDir, effectiveProjectId);
166957
167135
  const prefix = `[#${obsId}] `;
166958
167136
  const deletions = [];
166959
167137
  for (const entity of gStore.loadEntities()) {
@@ -166968,8 +167146,8 @@ async function handleApi(req, res, dataDir, projectId, projectName, baseDir, pro
166968
167146
  break;
166969
167147
  }
166970
167148
  if (apiPath === "/export") {
166971
- await initGraphStore(effectiveDataDir);
166972
- const fullGraph = { entities: getGraphStore().loadEntities(), relations: getGraphStore().loadRelations() };
167149
+ const gStore = await initGraphStore(effectiveDataDir, effectiveProjectId);
167150
+ const fullGraph = { entities: gStore.loadEntities(), relations: gStore.loadRelations() };
166973
167151
  const observations2 = filterDashboardObservations(
166974
167152
  await getObservationStore().loadByProject(effectiveProjectId, { status: "active" }),
166975
167153
  effectiveProjectId
@@ -170414,7 +170592,7 @@ async function createMemorixServer(cwd, existingServer, sharedTeam, options = {}
170414
170592
  const store = getObservationStore();
170415
170593
  console.error(`[memorix] ObservationStore backend: ${store.getBackendName()}, generation: ${store.getGeneration()}`);
170416
170594
  }
170417
- let graphManager = new KnowledgeGraphManager(projectDir2);
170595
+ let graphManager = new KnowledgeGraphManager(projectDir2, project.id);
170418
170596
  if (!deferProjectRuntimeInit) {
170419
170597
  await graphManager.init();
170420
170598
  await initObservations(projectDir2);
@@ -170426,7 +170604,7 @@ async function createMemorixServer(cwd, existingServer, sharedTeam, options = {}
170426
170604
  await initObservationStore(projectDir2);
170427
170605
  await initMiniSkillStore(projectDir2);
170428
170606
  await initSessionStore(projectDir2);
170429
- graphManager = new KnowledgeGraphManager(projectDir2);
170607
+ graphManager = new KnowledgeGraphManager(projectDir2, project.id);
170430
170608
  await graphManager.init();
170431
170609
  await initObservations(projectDir2);
170432
170610
  const indexed = await prepareSearchIndex();
@@ -174485,6 +174663,7 @@ ${lines.join("\n")}` }] };
174485
174663
  } : {},
174486
174664
  ...mediaGenerationEnabled ? {
174487
174665
  image: z627.string().optional().describe("Base64-encoded reference image for image-to-image generation."),
174666
+ firstFrameImageUrl: z627.string().optional().describe("Public HTTPS first-frame image URL for MiniMax video generation; stored with the queued job."),
174488
174667
  region: z627.enum(["global", "cn"]).optional().describe("MiniMax deployment region."),
174489
174668
  n: z627.number().int().min(1).max(4).optional().describe("Image output count."),
174490
174669
  ratio: z627.enum(["adaptive", "1:1", "16:9", "4:3", "3:2", "2:3", "3:4", "9:16", "21:9"]).optional().describe("Image or video aspect ratio."),
@@ -174494,7 +174673,7 @@ ${lines.join("\n")}` }] };
174494
174673
  } : {}
174495
174674
  }
174496
174675
  },
174497
- async ({ action, path: assetPath, assetId, jobId, kind, limit: limit2, title, narrative, prompt, image, model, provider: provider2, language, region, n, ratio, width, height, duration, maxPages, maxChars, attach }) => {
174676
+ async ({ action, path: assetPath, assetId, jobId, kind, limit: limit2, title, narrative, prompt, image, firstFrameImageUrl, model, provider: provider2, language, region, n, ratio, width, height, duration, maxPages, maxChars, attach }) => {
174498
174677
  const unresolved = requireResolvedProject("manage controlled media");
174499
174678
  if (unresolved) return unresolved;
174500
174679
  const safeError4 = (error) => sanitizeCredentials(
@@ -174664,6 +174843,7 @@ ${lines.join("\n")}` }] };
174664
174843
  dataDir: projectDir2,
174665
174844
  projectId: project.id,
174666
174845
  prompt,
174846
+ firstFrameImageUrl,
174667
174847
  ...model === "MiniMax-H3" ? { model } : {},
174668
174848
  ...region ? { region } : {},
174669
174849
  ...videoRatio ? { ratio: videoRatio } : {},
@@ -175480,7 +175660,7 @@ var init_serve_shared = __esm({
175480
175660
 
175481
175661
  // src/cli/version.ts
175482
175662
  function getCliVersion() {
175483
- return true ? "1.9.3" : pkg.version;
175663
+ return true ? "1.9.5" : pkg.version;
175484
175664
  }
175485
175665
  var init_version3 = __esm({
175486
175666
  "src/cli/version.ts"() {