@prmichaelsen/remember-mcp 3.14.21 → 3.15.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/server.js CHANGED
@@ -1730,6 +1730,9 @@ function canModerateAny(authContext) {
1730
1730
  return authContext.credentials.group_memberships.some((m) => m.permissions.can_moderate);
1731
1731
  }
1732
1732
 
1733
+ // node_modules/@prmichaelsen/remember-core/dist/database/weaviate/v2-collections.js
1734
+ import { configure } from "weaviate-client";
1735
+
1733
1736
  // node_modules/@prmichaelsen/remember-core/dist/database/firestore/init.js
1734
1737
  import { initializeApp as initializeApp2 } from "@prmichaelsen/firebase-admin-sdk-v8";
1735
1738
  import { getDocument as getDocument2, setDocument as setDocument2, addDocument as addDocument2, updateDocument as updateDocument2, deleteDocument as deleteDocument2, queryDocuments as queryDocuments2, batchWrite as batchWrite2, FieldValue as FieldValue2, verifyIdToken as verifyIdToken2 } from "@prmichaelsen/firebase-admin-sdk-v8";
@@ -1758,6 +1761,313 @@ function getUserPreferencesPath(userId) {
1758
1761
  function getCollectionRegistryPath() {
1759
1762
  return `${BASE}.collection_registry`;
1760
1763
  }
1764
+ function getMemoryIndexPath() {
1765
+ return `${BASE}.memory_index`;
1766
+ }
1767
+
1768
+ // node_modules/@prmichaelsen/remember-core/dist/database/collection-registry.js
1769
+ async function registerCollection(entry) {
1770
+ const path = getCollectionRegistryPath();
1771
+ await setDocument2(path, entry.collection_name, entry);
1772
+ }
1773
+
1774
+ // node_modules/@prmichaelsen/remember-core/dist/database/weaviate/v2-collections.js
1775
+ var collectionCache = /* @__PURE__ */ new Map();
1776
+ var COLLECTION_CACHE_TTL_MS = 6e4;
1777
+ function isCollectionCached(collectionName) {
1778
+ const expiresAt = collectionCache.get(collectionName);
1779
+ if (expiresAt !== void 0 && Date.now() < expiresAt)
1780
+ return true;
1781
+ collectionCache.delete(collectionName);
1782
+ return false;
1783
+ }
1784
+ function cacheCollection(collectionName) {
1785
+ collectionCache.set(collectionName, Date.now() + COLLECTION_CACHE_TTL_MS);
1786
+ }
1787
+ var COMMON_MEMORY_PROPERTIES = [
1788
+ // Core content
1789
+ { name: "content", dataType: configure.dataType.TEXT },
1790
+ { name: "content_type", dataType: configure.dataType.TEXT },
1791
+ { name: "title", dataType: configure.dataType.TEXT },
1792
+ { name: "summary", dataType: configure.dataType.TEXT },
1793
+ { name: "type", dataType: configure.dataType.TEXT },
1794
+ // v1 compat (v2: content_type)
1795
+ // Tracking arrays (v2 feature)
1796
+ { name: "space_ids", dataType: configure.dataType.TEXT_ARRAY },
1797
+ { name: "group_ids", dataType: configure.dataType.TEXT_ARRAY },
1798
+ // Metadata
1799
+ { name: "created_at", dataType: configure.dataType.DATE },
1800
+ { name: "updated_at", dataType: configure.dataType.DATE },
1801
+ { name: "version", dataType: configure.dataType.INT },
1802
+ // User context
1803
+ { name: "user_id", dataType: configure.dataType.TEXT },
1804
+ // Document type (memory, relationship, comment)
1805
+ { name: "doc_type", dataType: configure.dataType.TEXT },
1806
+ // Memory-specific fields
1807
+ { name: "tags", dataType: configure.dataType.TEXT_ARRAY },
1808
+ { name: "weight", dataType: configure.dataType.NUMBER },
1809
+ { name: "trust_score", dataType: configure.dataType.NUMBER },
1810
+ { name: "trust", dataType: configure.dataType.NUMBER },
1811
+ // v1 compat (v2: trust_score)
1812
+ { name: "base_weight", dataType: configure.dataType.NUMBER },
1813
+ { name: "computed_weight", dataType: configure.dataType.NUMBER },
1814
+ { name: "confidence", dataType: configure.dataType.NUMBER },
1815
+ { name: "strength", dataType: configure.dataType.NUMBER },
1816
+ // Location data (v2 names)
1817
+ { name: "location_name", dataType: configure.dataType.TEXT },
1818
+ { name: "location_lat", dataType: configure.dataType.NUMBER },
1819
+ { name: "location_lon", dataType: configure.dataType.NUMBER },
1820
+ // Location data (v1 compat)
1821
+ { name: "location_gps_lat", dataType: configure.dataType.NUMBER },
1822
+ { name: "location_gps_lng", dataType: configure.dataType.NUMBER },
1823
+ { name: "location_address", dataType: configure.dataType.TEXT },
1824
+ { name: "location_city", dataType: configure.dataType.TEXT },
1825
+ { name: "location_country", dataType: configure.dataType.TEXT },
1826
+ { name: "location_source", dataType: configure.dataType.TEXT },
1827
+ // Locale
1828
+ { name: "locale_language", dataType: configure.dataType.TEXT },
1829
+ { name: "locale_timezone", dataType: configure.dataType.TEXT },
1830
+ // Context
1831
+ { name: "context_app", dataType: configure.dataType.TEXT },
1832
+ { name: "context_url", dataType: configure.dataType.TEXT },
1833
+ { name: "context_conversation_id", dataType: configure.dataType.TEXT },
1834
+ { name: "context_summary", dataType: configure.dataType.TEXT },
1835
+ { name: "context_timestamp", dataType: configure.dataType.DATE },
1836
+ // Relationships (v2 names)
1837
+ { name: "relationship_ids", dataType: configure.dataType.TEXT_ARRAY },
1838
+ { name: "relationship_type", dataType: configure.dataType.TEXT },
1839
+ { name: "related_memory_ids", dataType: configure.dataType.TEXT_ARRAY },
1840
+ { name: "observation", dataType: configure.dataType.TEXT },
1841
+ { name: "source", dataType: configure.dataType.TEXT },
1842
+ // Relationships (v1 compat)
1843
+ { name: "relationships", dataType: configure.dataType.TEXT_ARRAY },
1844
+ { name: "memory_ids", dataType: configure.dataType.TEXT_ARRAY },
1845
+ { name: "relationship_count", dataType: configure.dataType.INT },
1846
+ // Rating aggregates (denormalized from Firestore individual ratings)
1847
+ { name: "rating_sum", dataType: configure.dataType.INT },
1848
+ { name: "rating_count", dataType: configure.dataType.INT },
1849
+ { name: "rating_bayesian", dataType: configure.dataType.NUMBER },
1850
+ // Access tracking
1851
+ { name: "access_count", dataType: configure.dataType.NUMBER },
1852
+ { name: "last_accessed_at", dataType: configure.dataType.DATE },
1853
+ // References & templates
1854
+ { name: "references", dataType: configure.dataType.TEXT_ARRAY },
1855
+ { name: "template_id", dataType: configure.dataType.TEXT },
1856
+ // Comments (Phase 1)
1857
+ { name: "parent_id", dataType: configure.dataType.TEXT },
1858
+ { name: "thread_root_id", dataType: configure.dataType.TEXT },
1859
+ { name: "moderation_flags", dataType: configure.dataType.TEXT_ARRAY },
1860
+ // Agent follow-up tracking
1861
+ { name: "follow_up_at", dataType: configure.dataType.DATE },
1862
+ // Soft delete
1863
+ { name: "deleted_at", dataType: configure.dataType.DATE },
1864
+ { name: "deleted_by", dataType: configure.dataType.TEXT },
1865
+ { name: "deletion_reason", dataType: configure.dataType.TEXT }
1866
+ ];
1867
+ var PUBLISHED_MEMORY_PROPERTIES = [
1868
+ // Publication metadata
1869
+ { name: "published_at", dataType: configure.dataType.DATE },
1870
+ { name: "revised_at", dataType: configure.dataType.DATE },
1871
+ // Attribution
1872
+ { name: "author_id", dataType: configure.dataType.TEXT },
1873
+ { name: "ghost_id", dataType: configure.dataType.TEXT },
1874
+ { name: "attribution", dataType: configure.dataType.TEXT },
1875
+ // Discovery
1876
+ { name: "discovery_count", dataType: configure.dataType.INT },
1877
+ // Revision tracking
1878
+ { name: "revision_count", dataType: configure.dataType.INT },
1879
+ { name: "original_memory_id", dataType: configure.dataType.TEXT },
1880
+ // Moderation (nullable — null defaults to approved)
1881
+ { name: "moderation_status", dataType: configure.dataType.TEXT },
1882
+ { name: "moderated_by", dataType: configure.dataType.TEXT },
1883
+ { name: "moderated_at", dataType: configure.dataType.DATE },
1884
+ // Memory-level ACL (nullable — null defaults to owner_only semantics)
1885
+ { name: "write_mode", dataType: configure.dataType.TEXT },
1886
+ { name: "owner_id", dataType: configure.dataType.TEXT },
1887
+ { name: "overwrite_allowed_ids", dataType: configure.dataType.TEXT_ARRAY },
1888
+ { name: "last_revised_by", dataType: configure.dataType.TEXT },
1889
+ // Legacy compatibility (deprecated but kept for migration)
1890
+ { name: "spaces", dataType: configure.dataType.TEXT_ARRAY },
1891
+ { name: "space_id", dataType: configure.dataType.TEXT },
1892
+ { name: "space_memory_id", dataType: configure.dataType.TEXT }
1893
+ ];
1894
+ function createSpaceCollectionSchema() {
1895
+ const collectionName = "Memory_spaces_public";
1896
+ return {
1897
+ name: collectionName,
1898
+ description: "Shared memory collection for all public spaces",
1899
+ vectorizers: configure.vectorizer.text2VecOpenAI({
1900
+ model: "text-embedding-3-small",
1901
+ dimensions: 1536,
1902
+ vectorizeCollectionName: false
1903
+ }),
1904
+ properties: [
1905
+ ...COMMON_MEMORY_PROPERTIES,
1906
+ ...PUBLISHED_MEMORY_PROPERTIES
1907
+ ],
1908
+ invertedIndex: configure.invertedIndex({
1909
+ indexNullState: true,
1910
+ indexPropertyLength: true,
1911
+ indexTimestamps: true
1912
+ })
1913
+ };
1914
+ }
1915
+ function createGroupCollectionSchema(groupId) {
1916
+ const collectionName = `Memory_groups_${groupId}`;
1917
+ return {
1918
+ name: collectionName,
1919
+ description: `Group memory collection for group: ${groupId}`,
1920
+ vectorizers: configure.vectorizer.text2VecOpenAI({
1921
+ model: "text-embedding-3-small",
1922
+ dimensions: 1536,
1923
+ vectorizeCollectionName: false
1924
+ }),
1925
+ properties: [
1926
+ ...COMMON_MEMORY_PROPERTIES,
1927
+ ...PUBLISHED_MEMORY_PROPERTIES
1928
+ ],
1929
+ invertedIndex: configure.invertedIndex({
1930
+ indexNullState: true,
1931
+ indexPropertyLength: true,
1932
+ indexTimestamps: true
1933
+ })
1934
+ };
1935
+ }
1936
+ async function reconcileCollectionProperties(client2, collectionName, expectedProperties) {
1937
+ const collection = client2.collections.get(collectionName);
1938
+ const config3 = await collection.config.get();
1939
+ const existingNames = new Set(config3.properties.map((p) => p.name));
1940
+ let added = 0;
1941
+ for (const prop of expectedProperties) {
1942
+ if (!existingNames.has(prop.name)) {
1943
+ await collection.config.addProperty(prop);
1944
+ added++;
1945
+ }
1946
+ }
1947
+ return added;
1948
+ }
1949
+ async function ensureGroupCollection(client2, groupId) {
1950
+ const collectionName = `Memory_groups_${groupId}`;
1951
+ if (isCollectionCached(collectionName))
1952
+ return false;
1953
+ const exists = await client2.collections.exists(collectionName);
1954
+ if (exists) {
1955
+ await reconcileCollectionProperties(client2, collectionName, [...COMMON_MEMORY_PROPERTIES, ...PUBLISHED_MEMORY_PROPERTIES]);
1956
+ cacheCollection(collectionName);
1957
+ return false;
1958
+ }
1959
+ const schema = createGroupCollectionSchema(groupId);
1960
+ await client2.collections.create(schema);
1961
+ await registerCollection({
1962
+ collection_name: collectionName,
1963
+ collection_type: "groups",
1964
+ owner_id: groupId,
1965
+ created_at: (/* @__PURE__ */ new Date()).toISOString()
1966
+ });
1967
+ cacheCollection(collectionName);
1968
+ return true;
1969
+ }
1970
+ function getCollectionType(collectionName) {
1971
+ if (collectionName.startsWith("Memory_users_"))
1972
+ return "users";
1973
+ if (collectionName === "Memory_spaces_public")
1974
+ return "spaces";
1975
+ if (collectionName.startsWith("Memory_groups_"))
1976
+ return "groups";
1977
+ throw new Error(`Unknown collection type for: ${collectionName}`);
1978
+ }
1979
+
1980
+ // node_modules/@prmichaelsen/remember-core/dist/utils/dedupe.js
1981
+ function tagWithSource(objects, collectionName) {
1982
+ return objects.map((obj) => ({ ...obj, _collectionName: collectionName }));
1983
+ }
1984
+ function getTier(collectionName) {
1985
+ try {
1986
+ const type = getCollectionType(collectionName);
1987
+ switch (type) {
1988
+ case "spaces":
1989
+ return 1;
1990
+ case "groups":
1991
+ return 2;
1992
+ case "users":
1993
+ return 3;
1994
+ }
1995
+ } catch {
1996
+ return 4;
1997
+ }
1998
+ }
1999
+ function extractGroupId(collectionName) {
2000
+ if (collectionName.startsWith("Memory_groups_")) {
2001
+ return collectionName.replace("Memory_groups_", "");
2002
+ }
2003
+ return null;
2004
+ }
2005
+ function shouldPrefer(aCollection, bCollection, viewingGroupId) {
2006
+ const aTier = getTier(aCollection);
2007
+ const bTier = getTier(bCollection);
2008
+ if (aTier !== bTier)
2009
+ return aTier < bTier;
2010
+ if (viewingGroupId) {
2011
+ const aGroup = extractGroupId(aCollection);
2012
+ const bGroup = extractGroupId(bCollection);
2013
+ if (aGroup === viewingGroupId && bGroup !== viewingGroupId)
2014
+ return true;
2015
+ if (bGroup === viewingGroupId && aGroup !== viewingGroupId)
2016
+ return false;
2017
+ }
2018
+ return aCollection <= bCollection;
2019
+ }
2020
+ function dedupeBySourceId(objects, options = {}) {
2021
+ if (options.enabled === false)
2022
+ return objects;
2023
+ const sourceMap = /* @__PURE__ */ new Map();
2024
+ const results = [];
2025
+ const deduped = /* @__PURE__ */ new Set();
2026
+ for (let i = 0; i < objects.length; i++) {
2027
+ const obj = objects[i];
2028
+ const sourceId = obj.properties.original_memory_id;
2029
+ if (!sourceId) {
2030
+ results.push({ obj, index: i });
2031
+ continue;
2032
+ }
2033
+ const existing = sourceMap.get(sourceId);
2034
+ if (!existing) {
2035
+ const tagged = { ...obj, _also_in: [] };
2036
+ sourceMap.set(sourceId, { winner: tagged, index: i });
2037
+ results.push({ obj: tagged, index: i });
2038
+ continue;
2039
+ }
2040
+ if (shouldPrefer(obj._collectionName, existing.winner._collectionName, options.viewingGroupId)) {
2041
+ existing.winner._also_in.push({
2042
+ source: obj._collectionName,
2043
+ id: obj.uuid
2044
+ });
2045
+ const loser = existing.winner;
2046
+ const newWinner = {
2047
+ ...obj,
2048
+ _also_in: [
2049
+ ...existing.winner._also_in.filter((a) => a.id !== obj.uuid),
2050
+ { source: loser._collectionName, id: loser.uuid }
2051
+ ]
2052
+ };
2053
+ deduped.add(loser.uuid);
2054
+ deduped.delete(obj.uuid);
2055
+ sourceMap.set(sourceId, { winner: newWinner, index: i });
2056
+ const oldSlot = results.find((r) => r.obj.uuid === loser.uuid);
2057
+ if (oldSlot) {
2058
+ oldSlot.obj = newWinner;
2059
+ oldSlot.index = i;
2060
+ }
2061
+ } else {
2062
+ existing.winner._also_in.push({
2063
+ source: obj._collectionName,
2064
+ id: obj.uuid
2065
+ });
2066
+ deduped.add(obj.uuid);
2067
+ }
2068
+ }
2069
+ return results.filter((r) => !deduped.has(r.obj.uuid)).map((r) => r.obj);
2070
+ }
1761
2071
 
1762
2072
  // node_modules/@prmichaelsen/remember-core/dist/services/preferences.service.js
1763
2073
  var PreferencesDatabaseService = class {
@@ -2147,20 +2457,18 @@ var MemoryService = class {
2147
2457
  * Requires `memoryIndex` and `weaviateClient` in constructor options.
2148
2458
  */
2149
2459
  async resolveById(memoryId) {
2150
- if (!this.options?.weaviateClient) {
2460
+ if (!this.options.weaviateClient) {
2151
2461
  throw new Error("resolveById requires weaviateClient in options");
2152
2462
  }
2153
- if (this.options?.memoryIndex) {
2154
- const collectionName = await this.options.memoryIndex.lookup(memoryId);
2155
- if (collectionName) {
2156
- const col = this.options.weaviateClient.collections.get(collectionName);
2157
- const memory = await fetchMemoryWithAllProperties(col, memoryId);
2158
- if (memory?.properties) {
2159
- return {
2160
- memory: normalizeDoc({ id: memory.uuid, ...memory.properties }),
2161
- collectionName
2162
- };
2163
- }
2463
+ const collectionName = await this.options.memoryIndex.lookup(memoryId);
2464
+ if (collectionName) {
2465
+ const col = this.options.weaviateClient.collections.get(collectionName);
2466
+ const memory = await fetchMemoryWithAllProperties(col, memoryId);
2467
+ if (memory?.properties) {
2468
+ return {
2469
+ memory: normalizeDoc({ id: memory.uuid, ...memory.properties }),
2470
+ collectionName
2471
+ };
2164
2472
  }
2165
2473
  }
2166
2474
  return { memory: null, collectionName: null };
@@ -2206,13 +2514,11 @@ var MemoryService = class {
2206
2514
  };
2207
2515
  const memoryId = await this.collection.data.insert({ properties });
2208
2516
  this.logger.info("Memory created", { memoryId, userId: this.userId });
2209
- if (this.options?.memoryIndex) {
2210
- try {
2211
- const collectionName = this.collection.name;
2212
- await this.options.memoryIndex.index(memoryId, collectionName);
2213
- } catch (err2) {
2214
- this.logger.warn?.(`[MemoryService] Index write failed for ${memoryId}: ${err2}`);
2215
- }
2517
+ try {
2518
+ const collectionName = this.collection.name;
2519
+ await this.options.memoryIndex.index(memoryId, collectionName);
2520
+ } catch (err2) {
2521
+ this.logger.warn?.(`[MemoryService] Index write failed for ${memoryId}: ${err2}`);
2216
2522
  }
2217
2523
  return { memory_id: memoryId, created_at: now };
2218
2524
  }
@@ -2885,212 +3191,6 @@ var RelationshipService = class {
2885
3191
  // node_modules/@prmichaelsen/remember-core/dist/services/space.service.js
2886
3192
  import { Filters as Filters4 } from "weaviate-client";
2887
3193
 
2888
- // node_modules/@prmichaelsen/remember-core/dist/database/weaviate/v2-collections.js
2889
- import { configure } from "weaviate-client";
2890
-
2891
- // node_modules/@prmichaelsen/remember-core/dist/database/collection-registry.js
2892
- async function registerCollection(entry) {
2893
- const path = getCollectionRegistryPath();
2894
- await setDocument2(path, entry.collection_name, entry);
2895
- }
2896
-
2897
- // node_modules/@prmichaelsen/remember-core/dist/database/weaviate/v2-collections.js
2898
- var collectionCache = /* @__PURE__ */ new Map();
2899
- var COLLECTION_CACHE_TTL_MS = 6e4;
2900
- function isCollectionCached(collectionName) {
2901
- const expiresAt = collectionCache.get(collectionName);
2902
- if (expiresAt !== void 0 && Date.now() < expiresAt)
2903
- return true;
2904
- collectionCache.delete(collectionName);
2905
- return false;
2906
- }
2907
- function cacheCollection(collectionName) {
2908
- collectionCache.set(collectionName, Date.now() + COLLECTION_CACHE_TTL_MS);
2909
- }
2910
- var COMMON_MEMORY_PROPERTIES = [
2911
- // Core content
2912
- { name: "content", dataType: configure.dataType.TEXT },
2913
- { name: "content_type", dataType: configure.dataType.TEXT },
2914
- { name: "title", dataType: configure.dataType.TEXT },
2915
- { name: "summary", dataType: configure.dataType.TEXT },
2916
- { name: "type", dataType: configure.dataType.TEXT },
2917
- // v1 compat (v2: content_type)
2918
- // Tracking arrays (v2 feature)
2919
- { name: "space_ids", dataType: configure.dataType.TEXT_ARRAY },
2920
- { name: "group_ids", dataType: configure.dataType.TEXT_ARRAY },
2921
- // Metadata
2922
- { name: "created_at", dataType: configure.dataType.DATE },
2923
- { name: "updated_at", dataType: configure.dataType.DATE },
2924
- { name: "version", dataType: configure.dataType.INT },
2925
- // User context
2926
- { name: "user_id", dataType: configure.dataType.TEXT },
2927
- // Document type (memory, relationship, comment)
2928
- { name: "doc_type", dataType: configure.dataType.TEXT },
2929
- // Memory-specific fields
2930
- { name: "tags", dataType: configure.dataType.TEXT_ARRAY },
2931
- { name: "weight", dataType: configure.dataType.NUMBER },
2932
- { name: "trust_score", dataType: configure.dataType.NUMBER },
2933
- { name: "trust", dataType: configure.dataType.NUMBER },
2934
- // v1 compat (v2: trust_score)
2935
- { name: "base_weight", dataType: configure.dataType.NUMBER },
2936
- { name: "computed_weight", dataType: configure.dataType.NUMBER },
2937
- { name: "confidence", dataType: configure.dataType.NUMBER },
2938
- { name: "strength", dataType: configure.dataType.NUMBER },
2939
- // Location data (v2 names)
2940
- { name: "location_name", dataType: configure.dataType.TEXT },
2941
- { name: "location_lat", dataType: configure.dataType.NUMBER },
2942
- { name: "location_lon", dataType: configure.dataType.NUMBER },
2943
- // Location data (v1 compat)
2944
- { name: "location_gps_lat", dataType: configure.dataType.NUMBER },
2945
- { name: "location_gps_lng", dataType: configure.dataType.NUMBER },
2946
- { name: "location_address", dataType: configure.dataType.TEXT },
2947
- { name: "location_city", dataType: configure.dataType.TEXT },
2948
- { name: "location_country", dataType: configure.dataType.TEXT },
2949
- { name: "location_source", dataType: configure.dataType.TEXT },
2950
- // Locale
2951
- { name: "locale_language", dataType: configure.dataType.TEXT },
2952
- { name: "locale_timezone", dataType: configure.dataType.TEXT },
2953
- // Context
2954
- { name: "context_app", dataType: configure.dataType.TEXT },
2955
- { name: "context_url", dataType: configure.dataType.TEXT },
2956
- { name: "context_conversation_id", dataType: configure.dataType.TEXT },
2957
- { name: "context_summary", dataType: configure.dataType.TEXT },
2958
- { name: "context_timestamp", dataType: configure.dataType.DATE },
2959
- // Relationships (v2 names)
2960
- { name: "relationship_ids", dataType: configure.dataType.TEXT_ARRAY },
2961
- { name: "relationship_type", dataType: configure.dataType.TEXT },
2962
- { name: "related_memory_ids", dataType: configure.dataType.TEXT_ARRAY },
2963
- { name: "observation", dataType: configure.dataType.TEXT },
2964
- { name: "source", dataType: configure.dataType.TEXT },
2965
- // Relationships (v1 compat)
2966
- { name: "relationships", dataType: configure.dataType.TEXT_ARRAY },
2967
- { name: "memory_ids", dataType: configure.dataType.TEXT_ARRAY },
2968
- { name: "relationship_count", dataType: configure.dataType.INT },
2969
- // Rating aggregates (denormalized from Firestore individual ratings)
2970
- { name: "rating_sum", dataType: configure.dataType.INT },
2971
- { name: "rating_count", dataType: configure.dataType.INT },
2972
- { name: "rating_bayesian", dataType: configure.dataType.NUMBER },
2973
- // Access tracking
2974
- { name: "access_count", dataType: configure.dataType.NUMBER },
2975
- { name: "last_accessed_at", dataType: configure.dataType.DATE },
2976
- // References & templates
2977
- { name: "references", dataType: configure.dataType.TEXT_ARRAY },
2978
- { name: "template_id", dataType: configure.dataType.TEXT },
2979
- // Comments (Phase 1)
2980
- { name: "parent_id", dataType: configure.dataType.TEXT },
2981
- { name: "thread_root_id", dataType: configure.dataType.TEXT },
2982
- { name: "moderation_flags", dataType: configure.dataType.TEXT_ARRAY },
2983
- // Agent follow-up tracking
2984
- { name: "follow_up_at", dataType: configure.dataType.DATE },
2985
- // Soft delete
2986
- { name: "deleted_at", dataType: configure.dataType.DATE },
2987
- { name: "deleted_by", dataType: configure.dataType.TEXT },
2988
- { name: "deletion_reason", dataType: configure.dataType.TEXT }
2989
- ];
2990
- var PUBLISHED_MEMORY_PROPERTIES = [
2991
- // Publication metadata
2992
- { name: "published_at", dataType: configure.dataType.DATE },
2993
- { name: "revised_at", dataType: configure.dataType.DATE },
2994
- // Attribution
2995
- { name: "author_id", dataType: configure.dataType.TEXT },
2996
- { name: "ghost_id", dataType: configure.dataType.TEXT },
2997
- { name: "attribution", dataType: configure.dataType.TEXT },
2998
- // Discovery
2999
- { name: "discovery_count", dataType: configure.dataType.INT },
3000
- // Revision tracking
3001
- { name: "revision_count", dataType: configure.dataType.INT },
3002
- { name: "original_memory_id", dataType: configure.dataType.TEXT },
3003
- // Moderation (nullable — null defaults to approved)
3004
- { name: "moderation_status", dataType: configure.dataType.TEXT },
3005
- { name: "moderated_by", dataType: configure.dataType.TEXT },
3006
- { name: "moderated_at", dataType: configure.dataType.DATE },
3007
- // Memory-level ACL (nullable — null defaults to owner_only semantics)
3008
- { name: "write_mode", dataType: configure.dataType.TEXT },
3009
- { name: "owner_id", dataType: configure.dataType.TEXT },
3010
- { name: "overwrite_allowed_ids", dataType: configure.dataType.TEXT_ARRAY },
3011
- { name: "last_revised_by", dataType: configure.dataType.TEXT },
3012
- // Legacy compatibility (deprecated but kept for migration)
3013
- { name: "spaces", dataType: configure.dataType.TEXT_ARRAY },
3014
- { name: "space_id", dataType: configure.dataType.TEXT },
3015
- { name: "space_memory_id", dataType: configure.dataType.TEXT }
3016
- ];
3017
- function createSpaceCollectionSchema() {
3018
- const collectionName = "Memory_spaces_public";
3019
- return {
3020
- name: collectionName,
3021
- description: "Shared memory collection for all public spaces",
3022
- vectorizers: configure.vectorizer.text2VecOpenAI({
3023
- model: "text-embedding-3-small",
3024
- dimensions: 1536,
3025
- vectorizeCollectionName: false
3026
- }),
3027
- properties: [
3028
- ...COMMON_MEMORY_PROPERTIES,
3029
- ...PUBLISHED_MEMORY_PROPERTIES
3030
- ],
3031
- invertedIndex: configure.invertedIndex({
3032
- indexNullState: true,
3033
- indexPropertyLength: true,
3034
- indexTimestamps: true
3035
- })
3036
- };
3037
- }
3038
- function createGroupCollectionSchema(groupId) {
3039
- const collectionName = `Memory_groups_${groupId}`;
3040
- return {
3041
- name: collectionName,
3042
- description: `Group memory collection for group: ${groupId}`,
3043
- vectorizers: configure.vectorizer.text2VecOpenAI({
3044
- model: "text-embedding-3-small",
3045
- dimensions: 1536,
3046
- vectorizeCollectionName: false
3047
- }),
3048
- properties: [
3049
- ...COMMON_MEMORY_PROPERTIES,
3050
- ...PUBLISHED_MEMORY_PROPERTIES
3051
- ],
3052
- invertedIndex: configure.invertedIndex({
3053
- indexNullState: true,
3054
- indexPropertyLength: true,
3055
- indexTimestamps: true
3056
- })
3057
- };
3058
- }
3059
- async function reconcileCollectionProperties(client2, collectionName, expectedProperties) {
3060
- const collection = client2.collections.get(collectionName);
3061
- const config3 = await collection.config.get();
3062
- const existingNames = new Set(config3.properties.map((p) => p.name));
3063
- let added = 0;
3064
- for (const prop of expectedProperties) {
3065
- if (!existingNames.has(prop.name)) {
3066
- await collection.config.addProperty(prop);
3067
- added++;
3068
- }
3069
- }
3070
- return added;
3071
- }
3072
- async function ensureGroupCollection(client2, groupId) {
3073
- const collectionName = `Memory_groups_${groupId}`;
3074
- if (isCollectionCached(collectionName))
3075
- return false;
3076
- const exists = await client2.collections.exists(collectionName);
3077
- if (exists) {
3078
- await reconcileCollectionProperties(client2, collectionName, [...COMMON_MEMORY_PROPERTIES, ...PUBLISHED_MEMORY_PROPERTIES]);
3079
- cacheCollection(collectionName);
3080
- return false;
3081
- }
3082
- const schema = createGroupCollectionSchema(groupId);
3083
- await client2.collections.create(schema);
3084
- await registerCollection({
3085
- collection_name: collectionName,
3086
- collection_type: "groups",
3087
- owner_id: groupId,
3088
- created_at: (/* @__PURE__ */ new Date()).toISOString()
3089
- });
3090
- cacheCollection(collectionName);
3091
- return true;
3092
- }
3093
-
3094
3194
  // node_modules/@prmichaelsen/remember-core/dist/database/weaviate/space-schema.js
3095
3195
  var PUBLIC_COLLECTION_NAME = "Memory_spaces_public";
3096
3196
  function isValidSpaceId(spaceId) {
@@ -3146,14 +3246,18 @@ var SpaceService = class {
3146
3246
  userId;
3147
3247
  confirmationTokenService;
3148
3248
  logger;
3249
+ memoryIndexService;
3149
3250
  moderationClient;
3150
- constructor(weaviateClient, userCollection, userId, confirmationTokenService, logger2, options) {
3251
+ memoryIndex;
3252
+ constructor(weaviateClient, userCollection, userId, confirmationTokenService, logger2, memoryIndexService2, options) {
3151
3253
  this.weaviateClient = weaviateClient;
3152
3254
  this.userCollection = userCollection;
3153
3255
  this.userId = userId;
3154
3256
  this.confirmationTokenService = confirmationTokenService;
3155
3257
  this.logger = logger2;
3258
+ this.memoryIndexService = memoryIndexService2;
3156
3259
  this.moderationClient = options?.moderationClient;
3260
+ this.memoryIndex = memoryIndexService2;
3157
3261
  }
3158
3262
  // ── Content moderation helper ────────────────────────────────────────
3159
3263
  async checkModeration(content) {
@@ -3404,7 +3508,7 @@ var SpaceService = class {
3404
3508
  }
3405
3509
  const combinedFilters = filterList.length > 0 ? Filters4.and(...filterList) : void 0;
3406
3510
  const spaceObjects = await this.executeSearch(spacesCollection, input.query, searchType, combinedFilters, fetchLimit);
3407
- allObjects.push(...spaceObjects);
3511
+ allObjects.push(...tagWithSource(spaceObjects, spacesCollectionName));
3408
3512
  }
3409
3513
  for (const groupId of groups) {
3410
3514
  const groupCollectionName = getCollectionName(CollectionType.GROUPS, groupId);
@@ -3415,24 +3519,26 @@ var SpaceService = class {
3415
3519
  const filterList = this.buildBaseFilters(groupCollection, input);
3416
3520
  const combinedFilters = filterList.length > 0 ? Filters4.and(...filterList) : void 0;
3417
3521
  const groupObjects = await this.executeSearch(groupCollection, input.query, searchType, combinedFilters, fetchLimit);
3418
- allObjects.push(...groupObjects);
3522
+ allObjects.push(...tagWithSource(groupObjects, groupCollectionName));
3419
3523
  }
3420
3524
  const seen = /* @__PURE__ */ new Set();
3421
- const deduplicated = allObjects.filter((obj) => {
3525
+ const uuidDeduped = allObjects.filter((obj) => {
3422
3526
  if (seen.has(obj.uuid))
3423
3527
  return false;
3424
3528
  seen.add(obj.uuid);
3425
3529
  return true;
3426
3530
  });
3427
- deduplicated.sort((a, b) => {
3531
+ const contentDeduped = dedupeBySourceId(uuidDeduped, input.dedupe);
3532
+ contentDeduped.sort((a, b) => {
3428
3533
  const scoreA = a.metadata?.score ?? 0;
3429
3534
  const scoreB = b.metadata?.score ?? 0;
3430
3535
  return scoreB - scoreA;
3431
3536
  });
3432
- const paginated = deduplicated.slice(offset, offset + limit);
3537
+ const paginated = contentDeduped.slice(offset, offset + limit);
3433
3538
  const memories = paginated.map((obj) => ({
3434
3539
  id: obj.uuid,
3435
- ...obj.properties
3540
+ ...obj.properties,
3541
+ ...obj._also_in?.length ? { also_in: obj._also_in } : {}
3436
3542
  }));
3437
3543
  const isAllPublic = spaces.length === 0 && groups.length === 0;
3438
3544
  return {
@@ -3551,7 +3657,8 @@ var SpaceService = class {
3551
3657
  discovery_count: 0,
3552
3658
  attribution: "user",
3553
3659
  moderation_status: spaceModerationStatus,
3554
- tags: mergedTags
3660
+ tags: mergedTags,
3661
+ original_memory_id: request.payload.memory_id
3555
3662
  };
3556
3663
  delete publishedMemory._additional;
3557
3664
  if (existingSpaceMemory) {
@@ -3559,6 +3666,11 @@ var SpaceService = class {
3559
3666
  } else {
3560
3667
  await publicCollection.data.insert({ id: weaviateId, properties: publishedMemory });
3561
3668
  }
3669
+ try {
3670
+ await this.memoryIndex.index(weaviateId, "Memory_spaces_public");
3671
+ } catch (err2) {
3672
+ this.logger.warn?.(`[SpaceService] Index write failed for ${weaviateId}: ${err2}`);
3673
+ }
3562
3674
  successfulPublications.push(`spaces: ${spaces.join(", ")}`);
3563
3675
  } catch (err2) {
3564
3676
  failedPublications.push(`spaces: ${err2 instanceof Error ? err2.message : String(err2)}`);
@@ -3587,7 +3699,8 @@ var SpaceService = class {
3587
3699
  discovery_count: 0,
3588
3700
  attribution: "user",
3589
3701
  moderation_status: groupModerationStatus,
3590
- tags: mergedTags
3702
+ tags: mergedTags,
3703
+ original_memory_id: request.payload.memory_id
3591
3704
  };
3592
3705
  delete groupMemory._additional;
3593
3706
  if (existingGroupMemory) {
@@ -3595,6 +3708,11 @@ var SpaceService = class {
3595
3708
  } else {
3596
3709
  await groupCollection.data.insert({ id: weaviateId, properties: groupMemory });
3597
3710
  }
3711
+ try {
3712
+ await this.memoryIndex.index(weaviateId, groupCollectionName);
3713
+ } catch (err2) {
3714
+ this.logger.warn?.(`[SpaceService] Index write failed for ${weaviateId} in ${groupCollectionName}: ${err2}`);
3715
+ }
3598
3716
  successfulPublications.push(`group: ${groupId}`);
3599
3717
  } catch (err2) {
3600
3718
  failedPublications.push(`group ${groupId}: ${err2 instanceof Error ? err2.message : String(err2)}`);
@@ -3835,6 +3953,39 @@ var REM_STATE_COLLECTION = `${BASE}.rem_state`;
3835
3953
  // node_modules/@prmichaelsen/remember-core/dist/services/rem.clustering.js
3836
3954
  import { Filters as Filters5 } from "weaviate-client";
3837
3955
 
3956
+ // node_modules/@prmichaelsen/remember-core/dist/services/memory-index.service.js
3957
+ var MemoryIndexService = class {
3958
+ logger;
3959
+ collectionPath;
3960
+ constructor(logger2) {
3961
+ this.logger = logger2;
3962
+ this.collectionPath = getMemoryIndexPath();
3963
+ }
3964
+ /**
3965
+ * Index a memory UUID → collection name mapping.
3966
+ * Uses set() for idempotency (safe to re-index).
3967
+ */
3968
+ async index(memoryUuid, collectionName) {
3969
+ const entry = {
3970
+ collection_name: collectionName,
3971
+ created_at: (/* @__PURE__ */ new Date()).toISOString()
3972
+ };
3973
+ await setDocument2(this.collectionPath, memoryUuid, entry);
3974
+ this.logger.debug?.(`[MemoryIndex] Indexed ${memoryUuid} \u2192 ${collectionName}`);
3975
+ }
3976
+ /**
3977
+ * Look up the collection name for a memory UUID.
3978
+ * Returns null if the memory is not indexed.
3979
+ */
3980
+ async lookup(memoryUuid) {
3981
+ const doc = await getDocument2(this.collectionPath, memoryUuid);
3982
+ if (!doc)
3983
+ return null;
3984
+ const entry = doc;
3985
+ return entry.collection_name ?? null;
3986
+ }
3987
+ };
3988
+
3838
3989
  // node_modules/@prmichaelsen/remember-core/dist/services/moderation.service.js
3839
3990
  import { createHash as createHash2 } from "crypto";
3840
3991
  function buildModerationPrompt(content) {
@@ -4057,6 +4208,7 @@ var coreLogger = createLogger("info");
4057
4208
  var tokenService = new ConfirmationTokenService(coreLogger);
4058
4209
  var preferencesService = new PreferencesDatabaseService(coreLogger);
4059
4210
  var moderationClient = process.env.ANTHROPIC_API_KEY ? createModerationClient({ apiKey: process.env.ANTHROPIC_API_KEY }) : void 0;
4211
+ var memoryIndexService = new MemoryIndexService(coreLogger);
4060
4212
  var coreServicesCache = /* @__PURE__ */ new Map();
4061
4213
  function createCoreServices(userId) {
4062
4214
  const cached = coreServicesCache.get(userId);
@@ -4065,9 +4217,12 @@ function createCoreServices(userId) {
4065
4217
  const collection = getMemoryCollection(userId);
4066
4218
  const weaviateClient = getWeaviateClient();
4067
4219
  const services = {
4068
- memory: new MemoryService(collection, userId, coreLogger),
4220
+ memory: new MemoryService(collection, userId, coreLogger, {
4221
+ memoryIndex: memoryIndexService,
4222
+ weaviateClient
4223
+ }),
4069
4224
  relationship: new RelationshipService(collection, userId, coreLogger),
4070
- space: new SpaceService(weaviateClient, collection, userId, tokenService, coreLogger, { moderationClient }),
4225
+ space: new SpaceService(weaviateClient, collection, userId, tokenService, coreLogger, memoryIndexService, { moderationClient }),
4071
4226
  preferences: preferencesService,
4072
4227
  token: tokenService
4073
4228
  };