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