@prmichaelsen/remember-mcp 3.15.0 → 3.15.2

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";
@@ -1758,6 +1761,310 @@ function getMemoryIndexPath() {
1758
1761
  return `${BASE}.memory_index`;
1759
1762
  }
1760
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
+ }
2067
+
1761
2068
  // node_modules/@prmichaelsen/remember-core/dist/services/preferences.service.js
1762
2069
  var PreferencesDatabaseService = class {
1763
2070
  logger;
@@ -2880,212 +3187,6 @@ var RelationshipService = class {
2880
3187
  // node_modules/@prmichaelsen/remember-core/dist/services/space.service.js
2881
3188
  import { Filters as Filters4 } from "weaviate-client";
2882
3189
 
2883
- // node_modules/@prmichaelsen/remember-core/dist/database/weaviate/v2-collections.js
2884
- import { configure } from "weaviate-client";
2885
-
2886
- // node_modules/@prmichaelsen/remember-core/dist/database/collection-registry.js
2887
- async function registerCollection(entry) {
2888
- const path = getCollectionRegistryPath();
2889
- await setDocument2(path, entry.collection_name, entry);
2890
- }
2891
-
2892
- // node_modules/@prmichaelsen/remember-core/dist/database/weaviate/v2-collections.js
2893
- var collectionCache = /* @__PURE__ */ new Map();
2894
- var COLLECTION_CACHE_TTL_MS = 6e4;
2895
- function isCollectionCached(collectionName) {
2896
- const expiresAt = collectionCache.get(collectionName);
2897
- if (expiresAt !== void 0 && Date.now() < expiresAt)
2898
- return true;
2899
- collectionCache.delete(collectionName);
2900
- return false;
2901
- }
2902
- function cacheCollection(collectionName) {
2903
- collectionCache.set(collectionName, Date.now() + COLLECTION_CACHE_TTL_MS);
2904
- }
2905
- var COMMON_MEMORY_PROPERTIES = [
2906
- // Core content
2907
- { name: "content", dataType: configure.dataType.TEXT },
2908
- { name: "content_type", dataType: configure.dataType.TEXT },
2909
- { name: "title", dataType: configure.dataType.TEXT },
2910
- { name: "summary", dataType: configure.dataType.TEXT },
2911
- { name: "type", dataType: configure.dataType.TEXT },
2912
- // v1 compat (v2: content_type)
2913
- // Tracking arrays (v2 feature)
2914
- { name: "space_ids", dataType: configure.dataType.TEXT_ARRAY },
2915
- { name: "group_ids", dataType: configure.dataType.TEXT_ARRAY },
2916
- // Metadata
2917
- { name: "created_at", dataType: configure.dataType.DATE },
2918
- { name: "updated_at", dataType: configure.dataType.DATE },
2919
- { name: "version", dataType: configure.dataType.INT },
2920
- // User context
2921
- { name: "user_id", dataType: configure.dataType.TEXT },
2922
- // Document type (memory, relationship, comment)
2923
- { name: "doc_type", dataType: configure.dataType.TEXT },
2924
- // Memory-specific fields
2925
- { name: "tags", dataType: configure.dataType.TEXT_ARRAY },
2926
- { name: "weight", dataType: configure.dataType.NUMBER },
2927
- { name: "trust_score", dataType: configure.dataType.NUMBER },
2928
- { name: "trust", dataType: configure.dataType.NUMBER },
2929
- // v1 compat (v2: trust_score)
2930
- { name: "base_weight", dataType: configure.dataType.NUMBER },
2931
- { name: "computed_weight", dataType: configure.dataType.NUMBER },
2932
- { name: "confidence", dataType: configure.dataType.NUMBER },
2933
- { name: "strength", dataType: configure.dataType.NUMBER },
2934
- // Location data (v2 names)
2935
- { name: "location_name", dataType: configure.dataType.TEXT },
2936
- { name: "location_lat", dataType: configure.dataType.NUMBER },
2937
- { name: "location_lon", dataType: configure.dataType.NUMBER },
2938
- // Location data (v1 compat)
2939
- { name: "location_gps_lat", dataType: configure.dataType.NUMBER },
2940
- { name: "location_gps_lng", dataType: configure.dataType.NUMBER },
2941
- { name: "location_address", dataType: configure.dataType.TEXT },
2942
- { name: "location_city", dataType: configure.dataType.TEXT },
2943
- { name: "location_country", dataType: configure.dataType.TEXT },
2944
- { name: "location_source", dataType: configure.dataType.TEXT },
2945
- // Locale
2946
- { name: "locale_language", dataType: configure.dataType.TEXT },
2947
- { name: "locale_timezone", dataType: configure.dataType.TEXT },
2948
- // Context
2949
- { name: "context_app", dataType: configure.dataType.TEXT },
2950
- { name: "context_url", dataType: configure.dataType.TEXT },
2951
- { name: "context_conversation_id", dataType: configure.dataType.TEXT },
2952
- { name: "context_summary", dataType: configure.dataType.TEXT },
2953
- { name: "context_timestamp", dataType: configure.dataType.DATE },
2954
- // Relationships (v2 names)
2955
- { name: "relationship_ids", dataType: configure.dataType.TEXT_ARRAY },
2956
- { name: "relationship_type", dataType: configure.dataType.TEXT },
2957
- { name: "related_memory_ids", dataType: configure.dataType.TEXT_ARRAY },
2958
- { name: "observation", dataType: configure.dataType.TEXT },
2959
- { name: "source", dataType: configure.dataType.TEXT },
2960
- // Relationships (v1 compat)
2961
- { name: "relationships", dataType: configure.dataType.TEXT_ARRAY },
2962
- { name: "memory_ids", dataType: configure.dataType.TEXT_ARRAY },
2963
- { name: "relationship_count", dataType: configure.dataType.INT },
2964
- // Rating aggregates (denormalized from Firestore individual ratings)
2965
- { name: "rating_sum", dataType: configure.dataType.INT },
2966
- { name: "rating_count", dataType: configure.dataType.INT },
2967
- { name: "rating_bayesian", dataType: configure.dataType.NUMBER },
2968
- // Access tracking
2969
- { name: "access_count", dataType: configure.dataType.NUMBER },
2970
- { name: "last_accessed_at", dataType: configure.dataType.DATE },
2971
- // References & templates
2972
- { name: "references", dataType: configure.dataType.TEXT_ARRAY },
2973
- { name: "template_id", dataType: configure.dataType.TEXT },
2974
- // Comments (Phase 1)
2975
- { name: "parent_id", dataType: configure.dataType.TEXT },
2976
- { name: "thread_root_id", dataType: configure.dataType.TEXT },
2977
- { name: "moderation_flags", dataType: configure.dataType.TEXT_ARRAY },
2978
- // Agent follow-up tracking
2979
- { name: "follow_up_at", dataType: configure.dataType.DATE },
2980
- // Soft delete
2981
- { name: "deleted_at", dataType: configure.dataType.DATE },
2982
- { name: "deleted_by", dataType: configure.dataType.TEXT },
2983
- { name: "deletion_reason", dataType: configure.dataType.TEXT }
2984
- ];
2985
- var PUBLISHED_MEMORY_PROPERTIES = [
2986
- // Publication metadata
2987
- { name: "published_at", dataType: configure.dataType.DATE },
2988
- { name: "revised_at", dataType: configure.dataType.DATE },
2989
- // Attribution
2990
- { name: "author_id", dataType: configure.dataType.TEXT },
2991
- { name: "ghost_id", dataType: configure.dataType.TEXT },
2992
- { name: "attribution", dataType: configure.dataType.TEXT },
2993
- // Discovery
2994
- { name: "discovery_count", dataType: configure.dataType.INT },
2995
- // Revision tracking
2996
- { name: "revision_count", dataType: configure.dataType.INT },
2997
- { name: "original_memory_id", dataType: configure.dataType.TEXT },
2998
- // Moderation (nullable — null defaults to approved)
2999
- { name: "moderation_status", dataType: configure.dataType.TEXT },
3000
- { name: "moderated_by", dataType: configure.dataType.TEXT },
3001
- { name: "moderated_at", dataType: configure.dataType.DATE },
3002
- // Memory-level ACL (nullable — null defaults to owner_only semantics)
3003
- { name: "write_mode", dataType: configure.dataType.TEXT },
3004
- { name: "owner_id", dataType: configure.dataType.TEXT },
3005
- { name: "overwrite_allowed_ids", dataType: configure.dataType.TEXT_ARRAY },
3006
- { name: "last_revised_by", dataType: configure.dataType.TEXT },
3007
- // Legacy compatibility (deprecated but kept for migration)
3008
- { name: "spaces", dataType: configure.dataType.TEXT_ARRAY },
3009
- { name: "space_id", dataType: configure.dataType.TEXT },
3010
- { name: "space_memory_id", dataType: configure.dataType.TEXT }
3011
- ];
3012
- function createSpaceCollectionSchema() {
3013
- const collectionName = "Memory_spaces_public";
3014
- return {
3015
- name: collectionName,
3016
- description: "Shared memory collection for all public spaces",
3017
- vectorizers: configure.vectorizer.text2VecOpenAI({
3018
- model: "text-embedding-3-small",
3019
- dimensions: 1536,
3020
- vectorizeCollectionName: false
3021
- }),
3022
- properties: [
3023
- ...COMMON_MEMORY_PROPERTIES,
3024
- ...PUBLISHED_MEMORY_PROPERTIES
3025
- ],
3026
- invertedIndex: configure.invertedIndex({
3027
- indexNullState: true,
3028
- indexPropertyLength: true,
3029
- indexTimestamps: true
3030
- })
3031
- };
3032
- }
3033
- function createGroupCollectionSchema(groupId) {
3034
- const collectionName = `Memory_groups_${groupId}`;
3035
- return {
3036
- name: collectionName,
3037
- description: `Group memory collection for group: ${groupId}`,
3038
- vectorizers: configure.vectorizer.text2VecOpenAI({
3039
- model: "text-embedding-3-small",
3040
- dimensions: 1536,
3041
- vectorizeCollectionName: false
3042
- }),
3043
- properties: [
3044
- ...COMMON_MEMORY_PROPERTIES,
3045
- ...PUBLISHED_MEMORY_PROPERTIES
3046
- ],
3047
- invertedIndex: configure.invertedIndex({
3048
- indexNullState: true,
3049
- indexPropertyLength: true,
3050
- indexTimestamps: true
3051
- })
3052
- };
3053
- }
3054
- async function reconcileCollectionProperties(client2, collectionName, expectedProperties) {
3055
- const collection = client2.collections.get(collectionName);
3056
- const config2 = await collection.config.get();
3057
- const existingNames = new Set(config2.properties.map((p) => p.name));
3058
- let added = 0;
3059
- for (const prop of expectedProperties) {
3060
- if (!existingNames.has(prop.name)) {
3061
- await collection.config.addProperty(prop);
3062
- added++;
3063
- }
3064
- }
3065
- return added;
3066
- }
3067
- async function ensureGroupCollection(client2, groupId) {
3068
- const collectionName = `Memory_groups_${groupId}`;
3069
- if (isCollectionCached(collectionName))
3070
- return false;
3071
- const exists = await client2.collections.exists(collectionName);
3072
- if (exists) {
3073
- await reconcileCollectionProperties(client2, collectionName, [...COMMON_MEMORY_PROPERTIES, ...PUBLISHED_MEMORY_PROPERTIES]);
3074
- cacheCollection(collectionName);
3075
- return false;
3076
- }
3077
- const schema = createGroupCollectionSchema(groupId);
3078
- await client2.collections.create(schema);
3079
- await registerCollection({
3080
- collection_name: collectionName,
3081
- collection_type: "groups",
3082
- owner_id: groupId,
3083
- created_at: (/* @__PURE__ */ new Date()).toISOString()
3084
- });
3085
- cacheCollection(collectionName);
3086
- return true;
3087
- }
3088
-
3089
3190
  // node_modules/@prmichaelsen/remember-core/dist/database/weaviate/space-schema.js
3090
3191
  var PUBLIC_COLLECTION_NAME = "Memory_spaces_public";
3091
3192
  function isValidSpaceId(spaceId) {
@@ -3403,7 +3504,7 @@ var SpaceService = class {
3403
3504
  }
3404
3505
  const combinedFilters = filterList.length > 0 ? Filters4.and(...filterList) : void 0;
3405
3506
  const spaceObjects = await this.executeSearch(spacesCollection, input.query, searchType, combinedFilters, fetchLimit);
3406
- allObjects.push(...spaceObjects);
3507
+ allObjects.push(...tagWithSource(spaceObjects, spacesCollectionName));
3407
3508
  }
3408
3509
  for (const groupId of groups) {
3409
3510
  const groupCollectionName = getCollectionName(CollectionType.GROUPS, groupId);
@@ -3414,24 +3515,26 @@ var SpaceService = class {
3414
3515
  const filterList = this.buildBaseFilters(groupCollection, input);
3415
3516
  const combinedFilters = filterList.length > 0 ? Filters4.and(...filterList) : void 0;
3416
3517
  const groupObjects = await this.executeSearch(groupCollection, input.query, searchType, combinedFilters, fetchLimit);
3417
- allObjects.push(...groupObjects);
3518
+ allObjects.push(...tagWithSource(groupObjects, groupCollectionName));
3418
3519
  }
3419
3520
  const seen = /* @__PURE__ */ new Set();
3420
- const deduplicated = allObjects.filter((obj) => {
3521
+ const uuidDeduped = allObjects.filter((obj) => {
3421
3522
  if (seen.has(obj.uuid))
3422
3523
  return false;
3423
3524
  seen.add(obj.uuid);
3424
3525
  return true;
3425
3526
  });
3426
- deduplicated.sort((a, b) => {
3527
+ const contentDeduped = dedupeBySourceId(uuidDeduped, input.dedupe);
3528
+ contentDeduped.sort((a, b) => {
3427
3529
  const scoreA = a.metadata?.score ?? 0;
3428
3530
  const scoreB = b.metadata?.score ?? 0;
3429
3531
  return scoreB - scoreA;
3430
3532
  });
3431
- const paginated = deduplicated.slice(offset, offset + limit);
3533
+ const paginated = contentDeduped.slice(offset, offset + limit);
3432
3534
  const memories = paginated.map((obj) => ({
3433
3535
  id: obj.uuid,
3434
- ...obj.properties
3536
+ ...obj.properties,
3537
+ ...obj._also_in?.length ? { also_in: obj._also_in } : {}
3435
3538
  }));
3436
3539
  const isAllPublic = spaces.length === 0 && groups.length === 0;
3437
3540
  return {
@@ -3550,7 +3653,8 @@ var SpaceService = class {
3550
3653
  discovery_count: 0,
3551
3654
  attribution: "user",
3552
3655
  moderation_status: spaceModerationStatus,
3553
- tags: mergedTags
3656
+ tags: mergedTags,
3657
+ original_memory_id: request.payload.memory_id
3554
3658
  };
3555
3659
  delete publishedMemory._additional;
3556
3660
  if (existingSpaceMemory) {
@@ -3591,7 +3695,8 @@ var SpaceService = class {
3591
3695
  discovery_count: 0,
3592
3696
  attribution: "user",
3593
3697
  moderation_status: groupModerationStatus,
3594
- tags: mergedTags
3698
+ tags: mergedTags,
3699
+ original_memory_id: request.payload.memory_id
3595
3700
  };
3596
3701
  delete groupMemory._additional;
3597
3702
  if (existingGroupMemory) {
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";
@@ -1762,6 +1765,310 @@ function getMemoryIndexPath() {
1762
1765
  return `${BASE}.memory_index`;
1763
1766
  }
1764
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
+ }
2071
+
1765
2072
  // node_modules/@prmichaelsen/remember-core/dist/services/preferences.service.js
1766
2073
  var PreferencesDatabaseService = class {
1767
2074
  logger;
@@ -2884,212 +3191,6 @@ var RelationshipService = class {
2884
3191
  // node_modules/@prmichaelsen/remember-core/dist/services/space.service.js
2885
3192
  import { Filters as Filters4 } from "weaviate-client";
2886
3193
 
2887
- // node_modules/@prmichaelsen/remember-core/dist/database/weaviate/v2-collections.js
2888
- import { configure } from "weaviate-client";
2889
-
2890
- // node_modules/@prmichaelsen/remember-core/dist/database/collection-registry.js
2891
- async function registerCollection(entry) {
2892
- const path = getCollectionRegistryPath();
2893
- await setDocument2(path, entry.collection_name, entry);
2894
- }
2895
-
2896
- // node_modules/@prmichaelsen/remember-core/dist/database/weaviate/v2-collections.js
2897
- var collectionCache = /* @__PURE__ */ new Map();
2898
- var COLLECTION_CACHE_TTL_MS = 6e4;
2899
- function isCollectionCached(collectionName) {
2900
- const expiresAt = collectionCache.get(collectionName);
2901
- if (expiresAt !== void 0 && Date.now() < expiresAt)
2902
- return true;
2903
- collectionCache.delete(collectionName);
2904
- return false;
2905
- }
2906
- function cacheCollection(collectionName) {
2907
- collectionCache.set(collectionName, Date.now() + COLLECTION_CACHE_TTL_MS);
2908
- }
2909
- var COMMON_MEMORY_PROPERTIES = [
2910
- // Core content
2911
- { name: "content", dataType: configure.dataType.TEXT },
2912
- { name: "content_type", dataType: configure.dataType.TEXT },
2913
- { name: "title", dataType: configure.dataType.TEXT },
2914
- { name: "summary", dataType: configure.dataType.TEXT },
2915
- { name: "type", dataType: configure.dataType.TEXT },
2916
- // v1 compat (v2: content_type)
2917
- // Tracking arrays (v2 feature)
2918
- { name: "space_ids", dataType: configure.dataType.TEXT_ARRAY },
2919
- { name: "group_ids", dataType: configure.dataType.TEXT_ARRAY },
2920
- // Metadata
2921
- { name: "created_at", dataType: configure.dataType.DATE },
2922
- { name: "updated_at", dataType: configure.dataType.DATE },
2923
- { name: "version", dataType: configure.dataType.INT },
2924
- // User context
2925
- { name: "user_id", dataType: configure.dataType.TEXT },
2926
- // Document type (memory, relationship, comment)
2927
- { name: "doc_type", dataType: configure.dataType.TEXT },
2928
- // Memory-specific fields
2929
- { name: "tags", dataType: configure.dataType.TEXT_ARRAY },
2930
- { name: "weight", dataType: configure.dataType.NUMBER },
2931
- { name: "trust_score", dataType: configure.dataType.NUMBER },
2932
- { name: "trust", dataType: configure.dataType.NUMBER },
2933
- // v1 compat (v2: trust_score)
2934
- { name: "base_weight", dataType: configure.dataType.NUMBER },
2935
- { name: "computed_weight", dataType: configure.dataType.NUMBER },
2936
- { name: "confidence", dataType: configure.dataType.NUMBER },
2937
- { name: "strength", dataType: configure.dataType.NUMBER },
2938
- // Location data (v2 names)
2939
- { name: "location_name", dataType: configure.dataType.TEXT },
2940
- { name: "location_lat", dataType: configure.dataType.NUMBER },
2941
- { name: "location_lon", dataType: configure.dataType.NUMBER },
2942
- // Location data (v1 compat)
2943
- { name: "location_gps_lat", dataType: configure.dataType.NUMBER },
2944
- { name: "location_gps_lng", dataType: configure.dataType.NUMBER },
2945
- { name: "location_address", dataType: configure.dataType.TEXT },
2946
- { name: "location_city", dataType: configure.dataType.TEXT },
2947
- { name: "location_country", dataType: configure.dataType.TEXT },
2948
- { name: "location_source", dataType: configure.dataType.TEXT },
2949
- // Locale
2950
- { name: "locale_language", dataType: configure.dataType.TEXT },
2951
- { name: "locale_timezone", dataType: configure.dataType.TEXT },
2952
- // Context
2953
- { name: "context_app", dataType: configure.dataType.TEXT },
2954
- { name: "context_url", dataType: configure.dataType.TEXT },
2955
- { name: "context_conversation_id", dataType: configure.dataType.TEXT },
2956
- { name: "context_summary", dataType: configure.dataType.TEXT },
2957
- { name: "context_timestamp", dataType: configure.dataType.DATE },
2958
- // Relationships (v2 names)
2959
- { name: "relationship_ids", dataType: configure.dataType.TEXT_ARRAY },
2960
- { name: "relationship_type", dataType: configure.dataType.TEXT },
2961
- { name: "related_memory_ids", dataType: configure.dataType.TEXT_ARRAY },
2962
- { name: "observation", dataType: configure.dataType.TEXT },
2963
- { name: "source", dataType: configure.dataType.TEXT },
2964
- // Relationships (v1 compat)
2965
- { name: "relationships", dataType: configure.dataType.TEXT_ARRAY },
2966
- { name: "memory_ids", dataType: configure.dataType.TEXT_ARRAY },
2967
- { name: "relationship_count", dataType: configure.dataType.INT },
2968
- // Rating aggregates (denormalized from Firestore individual ratings)
2969
- { name: "rating_sum", dataType: configure.dataType.INT },
2970
- { name: "rating_count", dataType: configure.dataType.INT },
2971
- { name: "rating_bayesian", dataType: configure.dataType.NUMBER },
2972
- // Access tracking
2973
- { name: "access_count", dataType: configure.dataType.NUMBER },
2974
- { name: "last_accessed_at", dataType: configure.dataType.DATE },
2975
- // References & templates
2976
- { name: "references", dataType: configure.dataType.TEXT_ARRAY },
2977
- { name: "template_id", dataType: configure.dataType.TEXT },
2978
- // Comments (Phase 1)
2979
- { name: "parent_id", dataType: configure.dataType.TEXT },
2980
- { name: "thread_root_id", dataType: configure.dataType.TEXT },
2981
- { name: "moderation_flags", dataType: configure.dataType.TEXT_ARRAY },
2982
- // Agent follow-up tracking
2983
- { name: "follow_up_at", dataType: configure.dataType.DATE },
2984
- // Soft delete
2985
- { name: "deleted_at", dataType: configure.dataType.DATE },
2986
- { name: "deleted_by", dataType: configure.dataType.TEXT },
2987
- { name: "deletion_reason", dataType: configure.dataType.TEXT }
2988
- ];
2989
- var PUBLISHED_MEMORY_PROPERTIES = [
2990
- // Publication metadata
2991
- { name: "published_at", dataType: configure.dataType.DATE },
2992
- { name: "revised_at", dataType: configure.dataType.DATE },
2993
- // Attribution
2994
- { name: "author_id", dataType: configure.dataType.TEXT },
2995
- { name: "ghost_id", dataType: configure.dataType.TEXT },
2996
- { name: "attribution", dataType: configure.dataType.TEXT },
2997
- // Discovery
2998
- { name: "discovery_count", dataType: configure.dataType.INT },
2999
- // Revision tracking
3000
- { name: "revision_count", dataType: configure.dataType.INT },
3001
- { name: "original_memory_id", dataType: configure.dataType.TEXT },
3002
- // Moderation (nullable — null defaults to approved)
3003
- { name: "moderation_status", dataType: configure.dataType.TEXT },
3004
- { name: "moderated_by", dataType: configure.dataType.TEXT },
3005
- { name: "moderated_at", dataType: configure.dataType.DATE },
3006
- // Memory-level ACL (nullable — null defaults to owner_only semantics)
3007
- { name: "write_mode", dataType: configure.dataType.TEXT },
3008
- { name: "owner_id", dataType: configure.dataType.TEXT },
3009
- { name: "overwrite_allowed_ids", dataType: configure.dataType.TEXT_ARRAY },
3010
- { name: "last_revised_by", dataType: configure.dataType.TEXT },
3011
- // Legacy compatibility (deprecated but kept for migration)
3012
- { name: "spaces", dataType: configure.dataType.TEXT_ARRAY },
3013
- { name: "space_id", dataType: configure.dataType.TEXT },
3014
- { name: "space_memory_id", dataType: configure.dataType.TEXT }
3015
- ];
3016
- function createSpaceCollectionSchema() {
3017
- const collectionName = "Memory_spaces_public";
3018
- return {
3019
- name: collectionName,
3020
- description: "Shared memory collection for all public spaces",
3021
- vectorizers: configure.vectorizer.text2VecOpenAI({
3022
- model: "text-embedding-3-small",
3023
- dimensions: 1536,
3024
- vectorizeCollectionName: false
3025
- }),
3026
- properties: [
3027
- ...COMMON_MEMORY_PROPERTIES,
3028
- ...PUBLISHED_MEMORY_PROPERTIES
3029
- ],
3030
- invertedIndex: configure.invertedIndex({
3031
- indexNullState: true,
3032
- indexPropertyLength: true,
3033
- indexTimestamps: true
3034
- })
3035
- };
3036
- }
3037
- function createGroupCollectionSchema(groupId) {
3038
- const collectionName = `Memory_groups_${groupId}`;
3039
- return {
3040
- name: collectionName,
3041
- description: `Group memory collection for group: ${groupId}`,
3042
- vectorizers: configure.vectorizer.text2VecOpenAI({
3043
- model: "text-embedding-3-small",
3044
- dimensions: 1536,
3045
- vectorizeCollectionName: false
3046
- }),
3047
- properties: [
3048
- ...COMMON_MEMORY_PROPERTIES,
3049
- ...PUBLISHED_MEMORY_PROPERTIES
3050
- ],
3051
- invertedIndex: configure.invertedIndex({
3052
- indexNullState: true,
3053
- indexPropertyLength: true,
3054
- indexTimestamps: true
3055
- })
3056
- };
3057
- }
3058
- async function reconcileCollectionProperties(client2, collectionName, expectedProperties) {
3059
- const collection = client2.collections.get(collectionName);
3060
- const config3 = await collection.config.get();
3061
- const existingNames = new Set(config3.properties.map((p) => p.name));
3062
- let added = 0;
3063
- for (const prop of expectedProperties) {
3064
- if (!existingNames.has(prop.name)) {
3065
- await collection.config.addProperty(prop);
3066
- added++;
3067
- }
3068
- }
3069
- return added;
3070
- }
3071
- async function ensureGroupCollection(client2, groupId) {
3072
- const collectionName = `Memory_groups_${groupId}`;
3073
- if (isCollectionCached(collectionName))
3074
- return false;
3075
- const exists = await client2.collections.exists(collectionName);
3076
- if (exists) {
3077
- await reconcileCollectionProperties(client2, collectionName, [...COMMON_MEMORY_PROPERTIES, ...PUBLISHED_MEMORY_PROPERTIES]);
3078
- cacheCollection(collectionName);
3079
- return false;
3080
- }
3081
- const schema = createGroupCollectionSchema(groupId);
3082
- await client2.collections.create(schema);
3083
- await registerCollection({
3084
- collection_name: collectionName,
3085
- collection_type: "groups",
3086
- owner_id: groupId,
3087
- created_at: (/* @__PURE__ */ new Date()).toISOString()
3088
- });
3089
- cacheCollection(collectionName);
3090
- return true;
3091
- }
3092
-
3093
3194
  // node_modules/@prmichaelsen/remember-core/dist/database/weaviate/space-schema.js
3094
3195
  var PUBLIC_COLLECTION_NAME = "Memory_spaces_public";
3095
3196
  function isValidSpaceId(spaceId) {
@@ -3407,7 +3508,7 @@ var SpaceService = class {
3407
3508
  }
3408
3509
  const combinedFilters = filterList.length > 0 ? Filters4.and(...filterList) : void 0;
3409
3510
  const spaceObjects = await this.executeSearch(spacesCollection, input.query, searchType, combinedFilters, fetchLimit);
3410
- allObjects.push(...spaceObjects);
3511
+ allObjects.push(...tagWithSource(spaceObjects, spacesCollectionName));
3411
3512
  }
3412
3513
  for (const groupId of groups) {
3413
3514
  const groupCollectionName = getCollectionName(CollectionType.GROUPS, groupId);
@@ -3418,24 +3519,26 @@ var SpaceService = class {
3418
3519
  const filterList = this.buildBaseFilters(groupCollection, input);
3419
3520
  const combinedFilters = filterList.length > 0 ? Filters4.and(...filterList) : void 0;
3420
3521
  const groupObjects = await this.executeSearch(groupCollection, input.query, searchType, combinedFilters, fetchLimit);
3421
- allObjects.push(...groupObjects);
3522
+ allObjects.push(...tagWithSource(groupObjects, groupCollectionName));
3422
3523
  }
3423
3524
  const seen = /* @__PURE__ */ new Set();
3424
- const deduplicated = allObjects.filter((obj) => {
3525
+ const uuidDeduped = allObjects.filter((obj) => {
3425
3526
  if (seen.has(obj.uuid))
3426
3527
  return false;
3427
3528
  seen.add(obj.uuid);
3428
3529
  return true;
3429
3530
  });
3430
- deduplicated.sort((a, b) => {
3531
+ const contentDeduped = dedupeBySourceId(uuidDeduped, input.dedupe);
3532
+ contentDeduped.sort((a, b) => {
3431
3533
  const scoreA = a.metadata?.score ?? 0;
3432
3534
  const scoreB = b.metadata?.score ?? 0;
3433
3535
  return scoreB - scoreA;
3434
3536
  });
3435
- const paginated = deduplicated.slice(offset, offset + limit);
3537
+ const paginated = contentDeduped.slice(offset, offset + limit);
3436
3538
  const memories = paginated.map((obj) => ({
3437
3539
  id: obj.uuid,
3438
- ...obj.properties
3540
+ ...obj.properties,
3541
+ ...obj._also_in?.length ? { also_in: obj._also_in } : {}
3439
3542
  }));
3440
3543
  const isAllPublic = spaces.length === 0 && groups.length === 0;
3441
3544
  return {
@@ -3554,7 +3657,8 @@ var SpaceService = class {
3554
3657
  discovery_count: 0,
3555
3658
  attribution: "user",
3556
3659
  moderation_status: spaceModerationStatus,
3557
- tags: mergedTags
3660
+ tags: mergedTags,
3661
+ original_memory_id: request.payload.memory_id
3558
3662
  };
3559
3663
  delete publishedMemory._additional;
3560
3664
  if (existingSpaceMemory) {
@@ -3595,7 +3699,8 @@ var SpaceService = class {
3595
3699
  discovery_count: 0,
3596
3700
  attribution: "user",
3597
3701
  moderation_status: groupModerationStatus,
3598
- tags: mergedTags
3702
+ tags: mergedTags,
3703
+ original_memory_id: request.payload.memory_id
3599
3704
  };
3600
3705
  delete groupMemory._additional;
3601
3706
  if (existingGroupMemory) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prmichaelsen/remember-mcp",
3
- "version": "3.15.0",
3
+ "version": "3.15.2",
4
4
  "description": "Multi-tenant memory system MCP server with vector search and relationships",
5
5
  "main": "dist/server.js",
6
6
  "type": "module",
@@ -47,10 +47,12 @@
47
47
  "author": "Patrick Michaelsen",
48
48
  "license": "MIT",
49
49
  "dependencies": {
50
+ "@google-cloud/documentai": "^9.5.0",
51
+ "@google-cloud/vision": "^5.3.4",
50
52
  "@modelcontextprotocol/sdk": "^1.0.4",
51
53
  "@prmichaelsen/firebase-admin-sdk-v8": "^2.2.0",
52
54
  "@prmichaelsen/mcp-auth": "^7.0.4",
53
- "@prmichaelsen/remember-core": "^0.33.1",
55
+ "@prmichaelsen/remember-core": "^0.34.12",
54
56
  "dotenv": "^16.4.5",
55
57
  "uuid": "^13.0.0",
56
58
  "weaviate-client": "^3.2.0"