@prmichaelsen/remember-mcp 3.14.11 → 3.14.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/agent/milestones/milestone-18-performance-tuning.md +45 -0
  3. package/agent/progress.yaml +86 -2
  4. package/agent/tasks/task-77-parallelize-checkiffriend.md +62 -0
  5. package/agent/tasks/task-78-cache-checkiffriend.md +78 -0
  6. package/agent/tasks/task-79-memoize-core-services.md +75 -0
  7. package/agent/tasks/task-80-parallelize-startup-health-checks.md +57 -0
  8. package/agent/tasks/task-81-optimize-ghost-config-block-unblock.md +64 -0
  9. package/agent/tasks/task-82-native-weaviate-offset.md +69 -0
  10. package/agent/tasks/task-83-eliminate-redundant-validatetoken.md +53 -0
  11. package/agent/tasks/task-84-static-imports-server-factory.md +52 -0
  12. package/dist/core-services.d.ts +3 -1
  13. package/dist/server-factory.js +250 -482
  14. package/dist/server.js +29 -140
  15. package/dist/services/access-control.d.ts +5 -5
  16. package/dist/services/ghost-config.service.d.ts +2 -0
  17. package/package.json +1 -1
  18. package/src/core-services.ts +16 -2
  19. package/src/server-factory.ts +5 -3
  20. package/src/server.ts +5 -3
  21. package/src/services/access-control.spec.ts +11 -11
  22. package/src/services/access-control.ts +74 -8
  23. package/src/services/ghost-config.service.spec.ts +22 -15
  24. package/src/services/ghost-config.service.ts +9 -15
  25. package/src/tools/query-memory.ts +1 -2
  26. package/src/tools/search-memory.ts +5 -8
  27. package/dist/services/trust-enforcement.d.ts +0 -83
  28. package/dist/services/trust-enforcement.spec.d.ts +0 -2
  29. package/dist/utils/weaviate-filters.d.ts +0 -56
  30. package/dist/utils/weaviate-filters.spec.d.ts +0 -8
  31. package/src/services/trust-enforcement.spec.ts +0 -309
  32. package/src/services/trust-enforcement.ts +0 -197
  33. package/src/utils/weaviate-filters.spec.ts +0 -312
  34. package/src/utils/weaviate-filters.ts +0 -236
@@ -515,6 +515,21 @@ var init_logger = __esm({
515
515
  });
516
516
 
517
517
  // src/firestore/init.ts
518
+ var init_exports = {};
519
+ __export(init_exports, {
520
+ FieldValue: () => FieldValue,
521
+ addDocument: () => addDocument,
522
+ batchWrite: () => batchWrite,
523
+ deleteDocument: () => deleteDocument,
524
+ getDocument: () => getDocument,
525
+ initFirestore: () => initFirestore,
526
+ isFirestoreInitialized: () => isFirestoreInitialized,
527
+ queryDocuments: () => queryDocuments,
528
+ setDocument: () => setDocument,
529
+ testFirestoreConnection: () => testFirestoreConnection,
530
+ updateDocument: () => updateDocument,
531
+ verifyIdToken: () => verifyIdToken
532
+ });
518
533
  import { initializeApp } from "@prmichaelsen/firebase-admin-sdk-v8";
519
534
  import {
520
535
  getDocument,
@@ -555,370 +570,35 @@ function initFirestore() {
555
570
  throw error;
556
571
  }
557
572
  }
558
- var initialized;
559
- var init_init = __esm({
560
- "src/firestore/init.ts"() {
561
- "use strict";
562
- init_config();
563
- init_logger();
564
- initialized = false;
565
- }
566
- });
567
-
568
- // src/services/trust-enforcement.ts
569
- function buildTrustFilter2(collection, accessorTrustLevel) {
570
- return collection.filter.byProperty("trust_score").lessThanOrEqual(accessorTrustLevel);
571
- }
572
- function isTrustSufficient2(memoryTrust, accessorTrust) {
573
- return accessorTrust >= memoryTrust;
573
+ function isFirestoreInitialized() {
574
+ return initialized;
574
575
  }
575
- var init_trust_enforcement = __esm({
576
- "src/services/trust-enforcement.ts"() {
577
- "use strict";
578
- }
579
- });
580
-
581
- // src/firestore/paths.ts
582
- function getBasePrefix2() {
583
- const environment = process.env.ENVIRONMENT;
584
- if (environment && environment !== "production" && environment !== "prod") {
585
- return `${environment}.${APP_NAME2}`;
586
- }
587
- const isDevelopment = process.env.NODE_ENV === "development";
588
- if (isDevelopment) {
589
- const customPrefix = process.env.DB_PREFIX;
590
- if (customPrefix) {
591
- return customPrefix;
592
- }
593
- return `e0.${APP_NAME2}`;
594
- }
595
- return APP_NAME2;
596
- }
597
- var APP_NAME2, BASE2;
598
- var init_paths = __esm({
599
- "src/firestore/paths.ts"() {
600
- "use strict";
601
- APP_NAME2 = "remember-mcp";
602
- BASE2 = getBasePrefix2();
603
- }
604
- });
605
-
606
- // src/types/ghost-config.ts
607
- var DEFAULT_GHOST_CONFIG2;
608
- var init_ghost_config = __esm({
609
- "src/types/ghost-config.ts"() {
610
- "use strict";
611
- DEFAULT_GHOST_CONFIG2 = {
612
- enabled: false,
613
- public_ghost_enabled: false,
614
- default_friend_trust: 0.25,
615
- default_public_trust: 0,
616
- per_user_trust: {},
617
- blocked_users: [],
618
- enforcement_mode: "query"
619
- };
620
- }
621
- });
622
-
623
- // src/services/ghost-config.service.ts
624
- var ghost_config_service_exports = {};
625
- __export(ghost_config_service_exports, {
626
- FirestoreGhostConfigProvider: () => FirestoreGhostConfigProvider2,
627
- blockUser: () => blockUser2,
628
- getGhostConfig: () => getGhostConfig2,
629
- isGhostEnabled: () => isGhostEnabled2,
630
- removeUserTrust: () => removeUserTrust2,
631
- setGhostConfigFields: () => setGhostConfigFields2,
632
- setUserTrust: () => setUserTrust2,
633
- unblockUser: () => unblockUser2,
634
- validateGhostConfigUpdate: () => validateGhostConfigUpdate2
635
- });
636
- function getGhostConfigPath(ownerUserId) {
637
- return {
638
- collectionPath: `${BASE2}.users/${ownerUserId}/ghost_config`,
639
- docId: "settings"
640
- };
641
- }
642
- async function getGhostConfig2(ownerUserId) {
576
+ async function testFirestoreConnection() {
643
577
  try {
644
- const { collectionPath, docId } = getGhostConfigPath(ownerUserId);
645
- const doc = await getDocument(collectionPath, docId);
646
- if (!doc) {
647
- return { ...DEFAULT_GHOST_CONFIG2 };
578
+ if (!initialized) {
579
+ throw new Error("Firestore not initialized");
648
580
  }
649
- return { ...DEFAULT_GHOST_CONFIG2, ...doc };
581
+ const { getDocument: getDocument3 } = await import("@prmichaelsen/firebase-admin-sdk-v8");
582
+ await getDocument3("_health_check", "test");
583
+ logger.info("Firestore connection test successful", {
584
+ module: "firestore-init"
585
+ });
586
+ return true;
650
587
  } catch (error) {
651
- logger.error("Failed to get ghost config", {
652
- service: SERVICE,
653
- ownerUserId,
588
+ logger.error("Firestore connection test failed", {
589
+ module: "firestore-init",
654
590
  error: error instanceof Error ? error.message : String(error)
655
591
  });
656
- return { ...DEFAULT_GHOST_CONFIG2 };
657
- }
658
- }
659
- async function setGhostConfigFields2(ownerUserId, config2) {
660
- const { collectionPath, docId } = getGhostConfigPath(ownerUserId);
661
- await setDocument(collectionPath, docId, config2, { merge: true });
662
- logger.info("Ghost config updated", {
663
- service: SERVICE,
664
- ownerUserId,
665
- updatedKeys: Object.keys(config2)
666
- });
667
- return getGhostConfig2(ownerUserId);
668
- }
669
- async function setUserTrust2(ownerUserId, targetUserId, trustLevel) {
670
- if (trustLevel < 0 || trustLevel > 1) {
671
- throw new Error(`Trust level must be between 0 and 1, got ${trustLevel}`);
672
- }
673
- const current = await getGhostConfig2(ownerUserId);
674
- const per_user_trust = { ...current.per_user_trust, [targetUserId]: trustLevel };
675
- const { collectionPath, docId } = getGhostConfigPath(ownerUserId);
676
- await setDocument(collectionPath, docId, { per_user_trust }, { merge: true });
677
- logger.info("User trust level set", {
678
- service: SERVICE,
679
- ownerUserId,
680
- targetUserId,
681
- trustLevel
682
- });
683
- }
684
- async function removeUserTrust2(ownerUserId, targetUserId) {
685
- const current = await getGhostConfig2(ownerUserId);
686
- const per_user_trust = { ...current.per_user_trust };
687
- delete per_user_trust[targetUserId];
688
- const { collectionPath, docId } = getGhostConfigPath(ownerUserId);
689
- await setDocument(collectionPath, docId, { per_user_trust }, { merge: true });
690
- logger.info("User trust override removed", {
691
- service: SERVICE,
692
- ownerUserId,
693
- targetUserId
694
- });
695
- }
696
- async function blockUser2(ownerUserId, targetUserId) {
697
- const current = await getGhostConfig2(ownerUserId);
698
- if (current.blocked_users.includes(targetUserId)) {
699
- return;
700
- }
701
- const blocked_users = [...current.blocked_users, targetUserId];
702
- const { collectionPath, docId } = getGhostConfigPath(ownerUserId);
703
- await setDocument(collectionPath, docId, { blocked_users }, { merge: true });
704
- logger.info("User blocked from ghost access", {
705
- service: SERVICE,
706
- ownerUserId,
707
- targetUserId
708
- });
709
- }
710
- async function unblockUser2(ownerUserId, targetUserId) {
711
- const current = await getGhostConfig2(ownerUserId);
712
- if (!current.blocked_users.includes(targetUserId)) {
713
- return;
714
- }
715
- const blocked_users = current.blocked_users.filter((id) => id !== targetUserId);
716
- const { collectionPath, docId } = getGhostConfigPath(ownerUserId);
717
- await setDocument(collectionPath, docId, { blocked_users }, { merge: true });
718
- logger.info("User unblocked from ghost access", {
719
- service: SERVICE,
720
- ownerUserId,
721
- targetUserId
722
- });
723
- }
724
- async function isGhostEnabled2(ownerUserId) {
725
- const config2 = await getGhostConfig2(ownerUserId);
726
- return config2.enabled;
727
- }
728
- function validateGhostConfigUpdate2(config2) {
729
- if (config2.default_friend_trust !== void 0) {
730
- if (config2.default_friend_trust < 0 || config2.default_friend_trust > 1) {
731
- throw new Error(`default_friend_trust must be between 0 and 1, got ${config2.default_friend_trust}`);
732
- }
733
- }
734
- if (config2.default_public_trust !== void 0) {
735
- if (config2.default_public_trust < 0 || config2.default_public_trust > 1) {
736
- throw new Error(`default_public_trust must be between 0 and 1, got ${config2.default_public_trust}`);
737
- }
738
- }
739
- if (config2.enforcement_mode !== void 0) {
740
- const valid = ["query", "prompt", "hybrid"];
741
- if (!valid.includes(config2.enforcement_mode)) {
742
- throw new Error(`enforcement_mode must be one of ${valid.join(", ")}, got ${config2.enforcement_mode}`);
743
- }
744
- }
745
- if (config2.per_user_trust !== void 0) {
746
- for (const [userId, level] of Object.entries(config2.per_user_trust)) {
747
- if (level < 0 || level > 1) {
748
- throw new Error(`Trust level for ${userId} must be between 0 and 1, got ${level}`);
749
- }
750
- }
592
+ return false;
751
593
  }
752
594
  }
753
- var SERVICE, FirestoreGhostConfigProvider2;
754
- var init_ghost_config_service = __esm({
755
- "src/services/ghost-config.service.ts"() {
595
+ var initialized;
596
+ var init_init = __esm({
597
+ "src/firestore/init.ts"() {
756
598
  "use strict";
757
- init_init();
758
- init_paths();
599
+ init_config();
759
600
  init_logger();
760
- init_ghost_config();
761
- SERVICE = "GhostConfigService";
762
- FirestoreGhostConfigProvider2 = class {
763
- async getGhostConfig(ownerUserId) {
764
- const config2 = await getGhostConfig2(ownerUserId);
765
- if (!config2.enabled) {
766
- return null;
767
- }
768
- return config2;
769
- }
770
- };
771
- }
772
- });
773
-
774
- // src/services/access-control.ts
775
- var access_control_exports = {};
776
- __export(access_control_exports, {
777
- InMemoryEscalationStore: () => InMemoryEscalationStore2,
778
- StubGhostConfigProvider: () => StubGhostConfigProvider2,
779
- checkMemoryAccess: () => checkMemoryAccess2,
780
- formatAccessResultMessage: () => formatAccessResultMessage2,
781
- handleInsufficientTrust: () => handleInsufficientTrust2,
782
- isMemoryBlocked: () => isMemoryBlocked2,
783
- resetBlock: () => resetBlock2,
784
- resolveAccessorTrustLevel: () => resolveAccessorTrustLevel2
785
- });
786
- async function checkMemoryAccess2(accessorUserId, memory, ghostConfigProvider, escalationStore) {
787
- const ownerUserId = memory.user_id;
788
- const memoryId = memory.id;
789
- if (accessorUserId === ownerUserId) {
790
- return { status: "granted", memory, access_level: "owner" };
791
- }
792
- const ghostConfig = await ghostConfigProvider.getGhostConfig(ownerUserId);
793
- if (!ghostConfig || !ghostConfig.enabled) {
794
- return { status: "no_permission", owner_user_id: ownerUserId, accessor_user_id: accessorUserId };
795
- }
796
- if (ghostConfig.blocked_users.includes(accessorUserId)) {
797
- return { status: "no_permission", owner_user_id: ownerUserId, accessor_user_id: accessorUserId };
798
- }
799
- const block = await escalationStore.getBlock(ownerUserId, accessorUserId, memoryId);
800
- if (block) {
801
- return {
802
- status: "blocked",
803
- memory_id: memoryId,
804
- reason: block.reason,
805
- blocked_at: block.blocked_at
806
- };
807
- }
808
- const accessorTrust = resolveAccessorTrustLevel2(ghostConfig, accessorUserId);
809
- const memoryTrust = memory.trust;
810
- if (!isTrustSufficient2(memoryTrust, accessorTrust)) {
811
- const result = await handleInsufficientTrust2(
812
- ownerUserId,
813
- accessorUserId,
814
- memoryId,
815
- memoryTrust,
816
- accessorTrust,
817
- escalationStore
818
- );
819
- return result;
820
- }
821
- return { status: "granted", memory, access_level: "trusted" };
822
- }
823
- async function handleInsufficientTrust2(ownerUserId, accessorUserId, memoryId, requiredTrust, actualTrust, escalationStore) {
824
- const attempt = await escalationStore.incrementAttempts(ownerUserId, accessorUserId, memoryId);
825
- if (attempt.count >= MAX_ATTEMPTS_BEFORE_BLOCK2) {
826
- const block = {
827
- blocked_at: (/* @__PURE__ */ new Date()).toISOString(),
828
- reason: `Access blocked after ${attempt.count} unauthorized attempts`,
829
- attempt_count: attempt.count
830
- };
831
- await escalationStore.setBlock(ownerUserId, accessorUserId, memoryId, block);
832
- return {
833
- status: "blocked",
834
- memory_id: memoryId,
835
- reason: block.reason,
836
- blocked_at: block.blocked_at
837
- };
838
- }
839
- return {
840
- status: "insufficient_trust",
841
- memory_id: memoryId,
842
- required_trust: requiredTrust,
843
- actual_trust: Math.max(0, actualTrust - TRUST_PENALTY2),
844
- attempts_remaining: MAX_ATTEMPTS_BEFORE_BLOCK2 - attempt.count
845
- };
846
- }
847
- async function isMemoryBlocked2(ownerUserId, accessorUserId, memoryId, escalationStore) {
848
- const block = await escalationStore.getBlock(ownerUserId, accessorUserId, memoryId);
849
- return block !== null;
850
- }
851
- async function resetBlock2(ownerUserId, accessorUserId, memoryId, escalationStore) {
852
- await escalationStore.removeBlock(ownerUserId, accessorUserId, memoryId);
853
- }
854
- function resolveAccessorTrustLevel2(ghostConfig, accessorUserId) {
855
- if (accessorUserId in ghostConfig.per_user_trust) {
856
- return ghostConfig.per_user_trust[accessorUserId];
857
- }
858
- return ghostConfig.default_public_trust ?? 0;
859
- }
860
- function formatAccessResultMessage2(result) {
861
- switch (result.status) {
862
- case "granted":
863
- return result.access_level === "owner" ? "Access granted (owner)." : "Access granted (trusted).";
864
- case "insufficient_trust":
865
- return `Insufficient trust level. Required: ${result.required_trust.toFixed(2)}, actual: ${result.actual_trust.toFixed(2)}. ${result.attempts_remaining} attempt(s) remaining before access is blocked.`;
866
- case "blocked":
867
- return `Access blocked: ${result.reason}`;
868
- case "no_permission":
869
- return "No permission to access this user's memories.";
870
- case "not_found":
871
- return `Memory ${result.memory_id} not found.`;
872
- case "deleted":
873
- return `Memory ${result.memory_id} was deleted on ${result.deleted_at}.`;
874
- }
875
- }
876
- var StubGhostConfigProvider2, InMemoryEscalationStore2, TRUST_PENALTY2, MAX_ATTEMPTS_BEFORE_BLOCK2;
877
- var init_access_control = __esm({
878
- "src/services/access-control.ts"() {
879
- "use strict";
880
- init_trust_enforcement();
881
- StubGhostConfigProvider2 = class {
882
- configs = /* @__PURE__ */ new Map();
883
- async getGhostConfig(ownerUserId) {
884
- return this.configs.get(ownerUserId) ?? null;
885
- }
886
- /** Test helper: set a GhostConfig for a user */
887
- setGhostConfig(ownerUserId, config2) {
888
- this.configs.set(ownerUserId, config2);
889
- }
890
- };
891
- InMemoryEscalationStore2 = class {
892
- blocks = /* @__PURE__ */ new Map();
893
- attempts = /* @__PURE__ */ new Map();
894
- key(ownerUserId, accessorUserId, memoryId) {
895
- return `${ownerUserId}:${accessorUserId}:${memoryId}`;
896
- }
897
- async getBlock(ownerUserId, accessorUserId, memoryId) {
898
- return this.blocks.get(this.key(ownerUserId, accessorUserId, memoryId)) ?? null;
899
- }
900
- async setBlock(ownerUserId, accessorUserId, memoryId, block) {
901
- this.blocks.set(this.key(ownerUserId, accessorUserId, memoryId), block);
902
- }
903
- async removeBlock(ownerUserId, accessorUserId, memoryId) {
904
- this.blocks.delete(this.key(ownerUserId, accessorUserId, memoryId));
905
- }
906
- async getAttempts(ownerUserId, accessorUserId, memoryId) {
907
- return this.attempts.get(this.key(ownerUserId, accessorUserId, memoryId)) ?? null;
908
- }
909
- async incrementAttempts(ownerUserId, accessorUserId, memoryId) {
910
- const k = this.key(ownerUserId, accessorUserId, memoryId);
911
- const existing = this.attempts.get(k);
912
- const record = {
913
- count: (existing?.count ?? 0) + 1,
914
- last_attempt_at: (/* @__PURE__ */ new Date()).toISOString()
915
- };
916
- this.attempts.set(k, record);
917
- return record;
918
- }
919
- };
920
- TRUST_PENALTY2 = 0.1;
921
- MAX_ATTEMPTS_BEFORE_BLOCK2 = 3;
601
+ initialized = false;
922
602
  }
923
603
  });
924
604
 
@@ -3992,16 +3672,22 @@ function getMemoryCollection(userId) {
3992
3672
  var coreLogger = createLogger("info");
3993
3673
  var tokenService = new ConfirmationTokenService(coreLogger);
3994
3674
  var preferencesService = new PreferencesDatabaseService(coreLogger);
3675
+ var coreServicesCache = /* @__PURE__ */ new Map();
3995
3676
  function createCoreServices(userId) {
3677
+ const cached = coreServicesCache.get(userId);
3678
+ if (cached)
3679
+ return cached;
3996
3680
  const collection = getMemoryCollection(userId);
3997
3681
  const weaviateClient = getWeaviateClient();
3998
- return {
3682
+ const services = {
3999
3683
  memory: new MemoryService(collection, userId, coreLogger),
4000
3684
  relationship: new RelationshipService(collection, userId, coreLogger),
4001
3685
  space: new SpaceService(weaviateClient, collection, userId, tokenService, coreLogger),
4002
3686
  preferences: preferencesService,
4003
3687
  token: tokenService
4004
3688
  };
3689
+ coreServicesCache.set(userId, services);
3690
+ return services;
4005
3691
  }
4006
3692
 
4007
3693
  // src/tools/create-memory.ts
@@ -4131,114 +3817,6 @@ async function handleCreateMemory(args, userId, authContext, context) {
4131
3817
 
4132
3818
  // src/tools/search-memory.ts
4133
3819
  init_logger();
4134
-
4135
- // src/utils/weaviate-filters.ts
4136
- import { Filters as Filters6 } from "weaviate-client";
4137
- function buildCombinedSearchFilters2(collection, filters) {
4138
- const memoryFilters = buildDocTypeFilters2(collection, "memory", filters);
4139
- const relationshipFilters = buildDocTypeFilters2(collection, "relationship", filters);
4140
- const validFilters = [memoryFilters, relationshipFilters].filter((f) => f !== void 0 && f !== null);
4141
- if (validFilters.length === 0) {
4142
- return void 0;
4143
- } else if (validFilters.length === 1) {
4144
- return validFilters[0];
4145
- } else {
4146
- return combineFiltersWithOr2(validFilters);
4147
- }
4148
- }
4149
- function buildDocTypeFilters2(collection, docType, filters) {
4150
- const filterList = [];
4151
- filterList.push(
4152
- collection.filter.byProperty("doc_type").equal(docType)
4153
- );
4154
- if (docType === "memory" && filters?.types && filters.types.length > 0) {
4155
- if (filters.types.length === 1) {
4156
- filterList.push(
4157
- collection.filter.byProperty("content_type").equal(filters.types[0])
4158
- );
4159
- } else {
4160
- filterList.push(
4161
- collection.filter.byProperty("content_type").containsAny(filters.types)
4162
- );
4163
- }
4164
- }
4165
- if (filters?.weight_min !== void 0) {
4166
- filterList.push(
4167
- collection.filter.byProperty("weight").greaterThanOrEqual(filters.weight_min)
4168
- );
4169
- }
4170
- if (filters?.weight_max !== void 0) {
4171
- filterList.push(
4172
- collection.filter.byProperty("weight").lessThanOrEqual(filters.weight_max)
4173
- );
4174
- }
4175
- if (filters?.trust_min !== void 0) {
4176
- filterList.push(
4177
- collection.filter.byProperty("trust_score").greaterThanOrEqual(filters.trust_min)
4178
- );
4179
- }
4180
- if (filters?.trust_max !== void 0) {
4181
- filterList.push(
4182
- collection.filter.byProperty("trust_score").lessThanOrEqual(filters.trust_max)
4183
- );
4184
- }
4185
- if (filters?.date_from) {
4186
- filterList.push(
4187
- collection.filter.byProperty("created_at").greaterThanOrEqual(new Date(filters.date_from))
4188
- );
4189
- }
4190
- if (filters?.date_to) {
4191
- filterList.push(
4192
- collection.filter.byProperty("created_at").lessThanOrEqual(new Date(filters.date_to))
4193
- );
4194
- }
4195
- if (filters?.tags && filters.tags.length > 0) {
4196
- if (filters.tags.length === 1) {
4197
- filterList.push(
4198
- collection.filter.byProperty("tags").containsAny([filters.tags[0]])
4199
- );
4200
- } else {
4201
- filterList.push(
4202
- collection.filter.byProperty("tags").containsAny(filters.tags)
4203
- );
4204
- }
4205
- }
4206
- return combineFiltersWithAnd2(filterList);
4207
- }
4208
- function buildMemoryOnlyFilters2(collection, filters) {
4209
- return buildDocTypeFilters2(collection, "memory", filters);
4210
- }
4211
- function combineFiltersWithAnd2(filters) {
4212
- const validFilters = filters.filter((f) => f !== void 0 && f !== null);
4213
- if (validFilters.length === 0) {
4214
- return void 0;
4215
- }
4216
- if (validFilters.length === 1) {
4217
- return validFilters[0];
4218
- }
4219
- return Filters6.and(...validFilters);
4220
- }
4221
- function combineFiltersWithOr2(filters) {
4222
- const validFilters = filters.filter((f) => f !== void 0 && f !== null);
4223
- if (validFilters.length === 0) {
4224
- return void 0;
4225
- }
4226
- if (validFilters.length === 1) {
4227
- return validFilters[0];
4228
- }
4229
- return Filters6.or(...validFilters);
4230
- }
4231
- function buildDeletedFilter2(collection, deletedFilter = "exclude") {
4232
- if (deletedFilter === "exclude") {
4233
- return collection.filter.byProperty("deleted_at").isNull(true);
4234
- } else if (deletedFilter === "only") {
4235
- return collection.filter.byProperty("deleted_at").isNull(false);
4236
- }
4237
- return null;
4238
- }
4239
-
4240
- // src/tools/search-memory.ts
4241
- init_trust_enforcement();
4242
3820
  var searchMemoryTool = {
4243
3821
  name: "remember_search_memory",
4244
3822
  description: `Search memories AND relationships using hybrid semantic and keyword search.
@@ -4369,16 +3947,16 @@ async function handleSearchMemory(args, userId, authContext) {
4369
3947
  const alpha = args.alpha ?? 0.7;
4370
3948
  const limit = args.limit ?? 10;
4371
3949
  const offset = args.offset ?? 0;
4372
- const deletedFilter = buildDeletedFilter2(collection, args.deleted_filter || "exclude");
4373
- const trustFilter = ghostMode ? buildTrustFilter2(collection, ghostMode.accessor_trust_level) : null;
4374
- const searchFilters = includeRelationships ? buildCombinedSearchFilters2(collection, args.filters) : buildMemoryOnlyFilters2(collection, args.filters);
3950
+ const deletedFilter = buildDeletedFilter(collection, args.deleted_filter || "exclude");
3951
+ const trustFilter = ghostMode ? buildTrustFilter(collection, ghostMode.accessor_trust_level) : null;
3952
+ const searchFilters = includeRelationships ? buildCombinedSearchFilters(collection, args.filters) : buildMemoryOnlyFilters(collection, args.filters);
4375
3953
  const hasExplicitTypeFilter = args.filters?.types && args.filters.types.length > 0;
4376
3954
  const ghostExclusionFilter = !hasExplicitTypeFilter ? collection.filter.byProperty("content_type").notEqual("ghost") : null;
4377
- const combinedFilters = combineFiltersWithAnd2([deletedFilter, trustFilter, ghostExclusionFilter, searchFilters].filter((f) => f !== null));
3955
+ const combinedFilters = combineFiltersWithAnd([deletedFilter, trustFilter, ghostExclusionFilter, searchFilters].filter((f) => f !== null));
4378
3956
  const searchOptions = {
4379
3957
  alpha,
4380
- limit: limit + offset
4381
- // Get extra for offset
3958
+ limit,
3959
+ offset
4382
3960
  };
4383
3961
  if (combinedFilters) {
4384
3962
  searchOptions.filters = combinedFilters;
@@ -4390,10 +3968,9 @@ async function handleSearchMemory(args, userId, authContext) {
4390
3968
  deletedFilter: args.deleted_filter || "exclude"
4391
3969
  });
4392
3970
  const results = await collection.query.hybrid(args.query, searchOptions);
4393
- const paginatedResults = results.objects.slice(offset);
4394
3971
  const memories = [];
4395
3972
  const relationships = [];
4396
- for (const obj of paginatedResults) {
3973
+ for (const obj of results.objects) {
4397
3974
  const doc = {
4398
3975
  id: obj.uuid,
4399
3976
  ...obj.properties
@@ -4709,7 +4286,6 @@ async function handleFindSimilar(args, userId, authContext) {
4709
4286
 
4710
4287
  // src/tools/query-memory.ts
4711
4288
  init_logger();
4712
- init_trust_enforcement();
4713
4289
  var queryMemoryTool = {
4714
4290
  name: "remember_query_memory",
4715
4291
  description: `Query memories using natural language for RAG (Retrieval-Augmented Generation).
@@ -4837,12 +4413,12 @@ async function handleQueryMemory(args, userId, authContext) {
4837
4413
  const minRelevance = args.min_relevance ?? 0.6;
4838
4414
  const includeContext = args.include_context ?? true;
4839
4415
  const format = args.format ?? "detailed";
4840
- const deletedFilter = buildDeletedFilter2(collection, args.deleted_filter || "exclude");
4841
- const trustFilter = ghostMode ? buildTrustFilter2(collection, ghostMode.accessor_trust_level) : null;
4842
- const searchFilters = buildCombinedSearchFilters2(collection, args.filters);
4416
+ const deletedFilter = buildDeletedFilter(collection, args.deleted_filter || "exclude");
4417
+ const trustFilter = ghostMode ? buildTrustFilter(collection, ghostMode.accessor_trust_level) : null;
4418
+ const searchFilters = buildCombinedSearchFilters(collection, args.filters);
4843
4419
  const hasExplicitTypeFilter = args.filters?.types && args.filters.types.length > 0;
4844
4420
  const ghostExclusionFilter = !hasExplicitTypeFilter ? collection.filter.byProperty("content_type").notEqual("ghost") : null;
4845
- const combinedFilters = combineFiltersWithAnd2([deletedFilter, trustFilter, ghostExclusionFilter, searchFilters].filter((f) => f !== null));
4421
+ const combinedFilters = combineFiltersWithAnd([deletedFilter, trustFilter, ghostExclusionFilter, searchFilters].filter((f) => f !== null));
4846
4422
  const searchOptions = {
4847
4423
  limit,
4848
4424
  distance: 1 - minRelevance,
@@ -5954,7 +5530,7 @@ async function handleDeny(args, userId, authContext) {
5954
5530
  }
5955
5531
 
5956
5532
  // src/tools/search-space.ts
5957
- import { Filters as Filters7 } from "weaviate-client";
5533
+ import { Filters as Filters6 } from "weaviate-client";
5958
5534
  var searchSpaceTool = {
5959
5535
  name: "remember_search_space",
5960
5536
  description: `Search shared spaces and/or groups to discover memories from other users.
@@ -6342,8 +5918,153 @@ async function handleModerate(args, userId, authContext) {
6342
5918
  }
6343
5919
  }
6344
5920
 
5921
+ // src/services/ghost-config.service.ts
5922
+ init_init();
5923
+
5924
+ // src/firestore/paths.ts
5925
+ var APP_NAME2 = "remember-mcp";
5926
+ function getBasePrefix2() {
5927
+ const environment = process.env.ENVIRONMENT;
5928
+ if (environment && environment !== "production" && environment !== "prod") {
5929
+ return `${environment}.${APP_NAME2}`;
5930
+ }
5931
+ const isDevelopment = process.env.NODE_ENV === "development";
5932
+ if (isDevelopment) {
5933
+ const customPrefix = process.env.DB_PREFIX;
5934
+ if (customPrefix) {
5935
+ return customPrefix;
5936
+ }
5937
+ return `e0.${APP_NAME2}`;
5938
+ }
5939
+ return APP_NAME2;
5940
+ }
5941
+ var BASE2 = getBasePrefix2();
5942
+
5943
+ // src/services/ghost-config.service.ts
5944
+ init_logger();
5945
+
5946
+ // src/types/ghost-config.ts
5947
+ var DEFAULT_GHOST_CONFIG2 = {
5948
+ enabled: false,
5949
+ public_ghost_enabled: false,
5950
+ default_friend_trust: 0.25,
5951
+ default_public_trust: 0,
5952
+ per_user_trust: {},
5953
+ blocked_users: [],
5954
+ enforcement_mode: "query"
5955
+ };
5956
+
5957
+ // src/services/ghost-config.service.ts
5958
+ var SERVICE = "GhostConfigService";
5959
+ function getGhostConfigPath(ownerUserId) {
5960
+ return {
5961
+ collectionPath: `${BASE2}.users/${ownerUserId}/ghost_config`,
5962
+ docId: "settings"
5963
+ };
5964
+ }
5965
+ async function getGhostConfig2(ownerUserId) {
5966
+ try {
5967
+ const { collectionPath, docId } = getGhostConfigPath(ownerUserId);
5968
+ const doc = await getDocument(collectionPath, docId);
5969
+ if (!doc) {
5970
+ return { ...DEFAULT_GHOST_CONFIG2 };
5971
+ }
5972
+ return { ...DEFAULT_GHOST_CONFIG2, ...doc };
5973
+ } catch (error) {
5974
+ logger.error("Failed to get ghost config", {
5975
+ service: SERVICE,
5976
+ ownerUserId,
5977
+ error: error instanceof Error ? error.message : String(error)
5978
+ });
5979
+ return { ...DEFAULT_GHOST_CONFIG2 };
5980
+ }
5981
+ }
5982
+ async function setGhostConfigFields2(ownerUserId, config2) {
5983
+ const { collectionPath, docId } = getGhostConfigPath(ownerUserId);
5984
+ await setDocument(collectionPath, docId, config2, { merge: true });
5985
+ logger.info("Ghost config updated", {
5986
+ service: SERVICE,
5987
+ ownerUserId,
5988
+ updatedKeys: Object.keys(config2)
5989
+ });
5990
+ return getGhostConfig2(ownerUserId);
5991
+ }
5992
+ async function setUserTrust2(ownerUserId, targetUserId, trustLevel) {
5993
+ if (trustLevel < 0 || trustLevel > 1) {
5994
+ throw new Error(`Trust level must be between 0 and 1, got ${trustLevel}`);
5995
+ }
5996
+ const current = await getGhostConfig2(ownerUserId);
5997
+ const per_user_trust = { ...current.per_user_trust, [targetUserId]: trustLevel };
5998
+ const { collectionPath, docId } = getGhostConfigPath(ownerUserId);
5999
+ await setDocument(collectionPath, docId, { per_user_trust }, { merge: true });
6000
+ logger.info("User trust level set", {
6001
+ service: SERVICE,
6002
+ ownerUserId,
6003
+ targetUserId,
6004
+ trustLevel
6005
+ });
6006
+ }
6007
+ async function removeUserTrust2(ownerUserId, targetUserId) {
6008
+ const current = await getGhostConfig2(ownerUserId);
6009
+ const per_user_trust = { ...current.per_user_trust };
6010
+ delete per_user_trust[targetUserId];
6011
+ const { collectionPath, docId } = getGhostConfigPath(ownerUserId);
6012
+ await setDocument(collectionPath, docId, { per_user_trust }, { merge: true });
6013
+ logger.info("User trust override removed", {
6014
+ service: SERVICE,
6015
+ ownerUserId,
6016
+ targetUserId
6017
+ });
6018
+ }
6019
+ async function blockUser2(ownerUserId, targetUserId) {
6020
+ const { collectionPath, docId } = getGhostConfigPath(ownerUserId);
6021
+ await setDocument(collectionPath, docId, {
6022
+ blocked_users: FieldValue.arrayUnion(targetUserId)
6023
+ }, { merge: true });
6024
+ logger.info("User blocked from ghost access", {
6025
+ service: SERVICE,
6026
+ ownerUserId,
6027
+ targetUserId
6028
+ });
6029
+ }
6030
+ async function unblockUser2(ownerUserId, targetUserId) {
6031
+ const { collectionPath, docId } = getGhostConfigPath(ownerUserId);
6032
+ await setDocument(collectionPath, docId, {
6033
+ blocked_users: FieldValue.arrayRemove(targetUserId)
6034
+ }, { merge: true });
6035
+ logger.info("User unblocked from ghost access", {
6036
+ service: SERVICE,
6037
+ ownerUserId,
6038
+ targetUserId
6039
+ });
6040
+ }
6041
+ function validateGhostConfigUpdate2(config2) {
6042
+ if (config2.default_friend_trust !== void 0) {
6043
+ if (config2.default_friend_trust < 0 || config2.default_friend_trust > 1) {
6044
+ throw new Error(`default_friend_trust must be between 0 and 1, got ${config2.default_friend_trust}`);
6045
+ }
6046
+ }
6047
+ if (config2.default_public_trust !== void 0) {
6048
+ if (config2.default_public_trust < 0 || config2.default_public_trust > 1) {
6049
+ throw new Error(`default_public_trust must be between 0 and 1, got ${config2.default_public_trust}`);
6050
+ }
6051
+ }
6052
+ if (config2.enforcement_mode !== void 0) {
6053
+ const valid = ["query", "prompt", "hybrid"];
6054
+ if (!valid.includes(config2.enforcement_mode)) {
6055
+ throw new Error(`enforcement_mode must be one of ${valid.join(", ")}, got ${config2.enforcement_mode}`);
6056
+ }
6057
+ }
6058
+ if (config2.per_user_trust !== void 0) {
6059
+ for (const [userId, level] of Object.entries(config2.per_user_trust)) {
6060
+ if (level < 0 || level > 1) {
6061
+ throw new Error(`Trust level for ${userId} must be between 0 and 1, got ${level}`);
6062
+ }
6063
+ }
6064
+ }
6065
+ }
6066
+
6345
6067
  // src/tools/ghost-config.ts
6346
- init_ghost_config_service();
6347
6068
  var ghostConfigTool = {
6348
6069
  name: "remember_ghost_config",
6349
6070
  description: `Manage ghost/persona configuration. Controls who can interact with your ghost and at what trust level.
@@ -6519,6 +6240,55 @@ async function handleGhostConfig(args, userId, authContext) {
6519
6240
  }
6520
6241
  }
6521
6242
 
6243
+ // src/services/access-control.ts
6244
+ async function resolveAccessorTrustLevel2(ghostConfig, ownerUserId, accessorUserId) {
6245
+ if (accessorUserId in ghostConfig.per_user_trust) {
6246
+ return ghostConfig.per_user_trust[accessorUserId];
6247
+ }
6248
+ const isFriend = await checkIfFriend(ownerUserId, accessorUserId);
6249
+ if (isFriend) {
6250
+ return ghostConfig.default_friend_trust ?? 0.25;
6251
+ }
6252
+ return ghostConfig.default_public_trust ?? 0;
6253
+ }
6254
+ var friendCache = /* @__PURE__ */ new Map();
6255
+ var FRIEND_CACHE_TTL_MS = 6e4;
6256
+ async function checkIfFriend(ownerUserId, accessorUserId) {
6257
+ const cacheKey = [ownerUserId, accessorUserId].sort().join(":");
6258
+ const cached = friendCache.get(cacheKey);
6259
+ if (cached && Date.now() < cached.expiresAt) {
6260
+ return cached.result;
6261
+ }
6262
+ try {
6263
+ const { queryDocuments: queryDocuments3 } = await Promise.resolve().then(() => (init_init(), init_exports));
6264
+ const BASE3 = process.env.FIRESTORE_BASE_PATH || "agentbase";
6265
+ const [forward, reverse] = await Promise.all([
6266
+ queryDocuments3(`${BASE3}.relationships`, {
6267
+ where: [
6268
+ { field: "from_user_id", op: "==", value: ownerUserId },
6269
+ { field: "to_user_id", op: "==", value: accessorUserId },
6270
+ { field: "friend", op: "==", value: true }
6271
+ ],
6272
+ limit: 1
6273
+ }),
6274
+ queryDocuments3(`${BASE3}.relationships`, {
6275
+ where: [
6276
+ { field: "from_user_id", op: "==", value: accessorUserId },
6277
+ { field: "to_user_id", op: "==", value: ownerUserId },
6278
+ { field: "friend", op: "==", value: true }
6279
+ ],
6280
+ limit: 1
6281
+ })
6282
+ ]);
6283
+ const result = forward.length > 0 || reverse.length > 0;
6284
+ friendCache.set(cacheKey, { result, expiresAt: Date.now() + FRIEND_CACHE_TTL_MS });
6285
+ return result;
6286
+ } catch (error) {
6287
+ console.error("[checkIfFriend] Error checking friend status:", error);
6288
+ return false;
6289
+ }
6290
+ }
6291
+
6522
6292
  // src/server-factory.ts
6523
6293
  var databasesInitialized = false;
6524
6294
  var initializationPromise = null;
@@ -6570,10 +6340,8 @@ async function createServer(accessToken, userId, options = {}) {
6570
6340
  );
6571
6341
  let resolvedGhostMode;
6572
6342
  if (options.ghostMode) {
6573
- const { getGhostConfig: getGhostConfig3 } = await Promise.resolve().then(() => (init_ghost_config_service(), ghost_config_service_exports));
6574
- const { resolveAccessorTrustLevel: resolveAccessorTrustLevel3 } = await Promise.resolve().then(() => (init_access_control(), access_control_exports));
6575
- const ghostConfig = await getGhostConfig3(options.ghostMode.owner_user_id);
6576
- const trustLevel = resolveAccessorTrustLevel3(ghostConfig, options.ghostMode.accessor_user_id);
6343
+ const ghostConfig = await getGhostConfig2(options.ghostMode.owner_user_id);
6344
+ const trustLevel = await resolveAccessorTrustLevel2(ghostConfig, options.ghostMode.owner_user_id, options.ghostMode.accessor_user_id);
6577
6345
  resolvedGhostMode = {
6578
6346
  owner_user_id: options.ghostMode.owner_user_id,
6579
6347
  accessor_user_id: options.ghostMode.accessor_user_id,