@prmichaelsen/remember-mcp 2.8.0 → 3.12.0

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 (250) hide show
  1. package/AGENT.md +296 -250
  2. package/CHANGELOG.md +468 -0
  3. package/README.md +163 -46
  4. package/agent/commands/acp.clarification-create.md +382 -0
  5. package/agent/commands/acp.command-create.md +0 -1
  6. package/agent/commands/acp.design-create.md +0 -1
  7. package/agent/commands/acp.init.md +0 -1
  8. package/agent/commands/acp.package-create.md +0 -1
  9. package/agent/commands/acp.package-info.md +0 -1
  10. package/agent/commands/acp.package-install.md +0 -1
  11. package/agent/commands/acp.package-list.md +0 -1
  12. package/agent/commands/acp.package-publish.md +0 -1
  13. package/agent/commands/acp.package-remove.md +0 -1
  14. package/agent/commands/acp.package-search.md +0 -1
  15. package/agent/commands/acp.package-update.md +0 -1
  16. package/agent/commands/acp.package-validate.md +0 -1
  17. package/agent/commands/acp.pattern-create.md +0 -1
  18. package/agent/commands/acp.plan.md +0 -1
  19. package/agent/commands/acp.proceed.md +0 -1
  20. package/agent/commands/acp.project-create.md +0 -1
  21. package/agent/commands/acp.project-info.md +309 -0
  22. package/agent/commands/acp.project-list.md +0 -1
  23. package/agent/commands/acp.project-remove.md +379 -0
  24. package/agent/commands/acp.project-set.md +0 -1
  25. package/agent/commands/acp.project-update.md +296 -0
  26. package/agent/commands/acp.report.md +0 -1
  27. package/agent/commands/acp.resume.md +0 -1
  28. package/agent/commands/acp.status.md +0 -1
  29. package/agent/commands/acp.sync.md +0 -1
  30. package/agent/commands/acp.task-create.md +17 -10
  31. package/agent/commands/acp.update.md +0 -1
  32. package/agent/commands/acp.validate.md +0 -1
  33. package/agent/commands/acp.version-check-for-updates.md +0 -1
  34. package/agent/commands/acp.version-check.md +0 -1
  35. package/agent/commands/acp.version-update.md +0 -1
  36. package/agent/commands/command.template.md +0 -5
  37. package/agent/commands/git.commit.md +13 -2
  38. package/agent/commands/git.init.md +0 -1
  39. package/agent/design/comment-memory-type.md +2 -2
  40. package/agent/design/local.collaborative-memory-sync.md +265 -0
  41. package/agent/design/local.content-flags.md +210 -0
  42. package/agent/design/local.ghost-persona-system.md +273 -0
  43. package/agent/design/local.group-acl-integration.md +338 -0
  44. package/agent/design/local.memory-acl-schema.md +352 -0
  45. package/agent/design/local.memory-collection-pattern-v2.md +348 -0
  46. package/agent/design/local.moderation-and-space-config.md +257 -0
  47. package/agent/design/local.v2-api-reference.md +621 -0
  48. package/agent/design/local.v2-migration-guide.md +191 -0
  49. package/agent/design/local.v2-usage-examples.md +265 -0
  50. package/agent/design/permissions-storage-architecture.md +11 -3
  51. package/agent/design/soft-delete-system.md +291 -0
  52. package/agent/design/trust-escalation-prevention.md +9 -2
  53. package/agent/design/trust-system-implementation.md +12 -3
  54. package/agent/milestones/milestone-13-soft-delete-system.md +306 -0
  55. package/agent/milestones/milestone-14-memory-collection-v2.md +182 -0
  56. package/agent/milestones/milestone-15-moderation-space-config.md +126 -0
  57. package/agent/package.template.yaml +0 -17
  58. package/agent/progress.yaml +762 -49
  59. package/agent/scripts/acp.common.sh +2 -0
  60. package/agent/scripts/acp.install.sh +15 -85
  61. package/agent/scripts/acp.package-install-optimized.sh +454 -0
  62. package/agent/scripts/acp.package-install.sh +248 -380
  63. package/agent/scripts/acp.package-validate.sh +0 -99
  64. package/agent/scripts/acp.project-info.sh +218 -0
  65. package/agent/scripts/acp.project-remove.sh +302 -0
  66. package/agent/scripts/acp.project-update.sh +296 -0
  67. package/agent/scripts/acp.yaml-parser.sh +128 -10
  68. package/agent/tasks/milestone-14-memory-collection-v2/task-165-core-infrastructure-setup.md +171 -0
  69. package/agent/tasks/milestone-14-memory-collection-v2/task-166-update-remember-publish.md +191 -0
  70. package/agent/tasks/milestone-14-memory-collection-v2/task-167-update-remember-retract.md +186 -0
  71. package/agent/tasks/milestone-14-memory-collection-v2/task-168-implement-remember-revise.md +184 -0
  72. package/agent/tasks/milestone-14-memory-collection-v2/task-169-update-remember-search-space.md +179 -0
  73. package/agent/tasks/milestone-14-memory-collection-v2/task-170-update-remember-create-update.md +139 -0
  74. package/agent/tasks/milestone-14-memory-collection-v2/task-172-performance-testing-optimization.md +161 -0
  75. package/agent/tasks/milestone-14-memory-collection-v2/task-173-documentation-examples.md +258 -0
  76. package/agent/tasks/milestone-15-moderation-space-config/task-174-add-moderation-schema-fields.md +57 -0
  77. package/agent/tasks/milestone-15-moderation-space-config/task-175-create-space-config-service.md +64 -0
  78. package/agent/tasks/milestone-15-moderation-space-config/task-176-wire-moderation-publish-flow.md +45 -0
  79. package/agent/tasks/milestone-15-moderation-space-config/task-177-add-moderation-search-filters.md +70 -0
  80. package/agent/tasks/milestone-15-moderation-space-config/task-178-create-remember-moderate-tool.md +69 -0
  81. package/agent/tasks/milestone-15-moderation-space-config/task-179-documentation-integration-tests.md +58 -0
  82. package/agent/tasks/milestone-16-ghost-system/task-187-ghost-config-firestore.md +41 -0
  83. package/agent/tasks/milestone-16-ghost-system/task-188-trust-filter-integration.md +44 -0
  84. package/agent/tasks/milestone-16-ghost-system/task-189-ghost-memory-filtering.md +43 -0
  85. package/agent/tasks/milestone-16-ghost-system/task-190-ghost-config-tools.md +45 -0
  86. package/agent/tasks/milestone-16-ghost-system/task-191-escalation-firestore.md +38 -0
  87. package/agent/tasks/milestone-16-ghost-system/task-192-documentation-verification.md +39 -0
  88. package/agent/tasks/milestone-7-trust-permissions/task-180-access-result-permission-types.md +69 -0
  89. package/agent/tasks/milestone-7-trust-permissions/task-181-firestore-permissions-access-logs.md +56 -0
  90. package/agent/tasks/milestone-7-trust-permissions/task-182-trust-enforcement-service.md +68 -0
  91. package/agent/tasks/milestone-7-trust-permissions/task-183-access-control-service.md +70 -0
  92. package/agent/tasks/milestone-7-trust-permissions/task-184-permission-tools.md +79 -0
  93. package/agent/tasks/milestone-7-trust-permissions/task-185-wire-trust-into-search-query.md +55 -0
  94. package/agent/tasks/milestone-7-trust-permissions/task-186-documentation-verification.md +56 -0
  95. package/agent/tasks/task-70-add-soft-delete-schema-fields.md +165 -0
  96. package/agent/tasks/task-71-implement-delete-confirmation-flow.md +257 -0
  97. package/agent/tasks/task-72-add-deleted-filter-to-search-tools.md +18 -0
  98. package/agent/tasks/task-73-update-relationship-handling.md +18 -0
  99. package/agent/tasks/task-74-add-unit-tests-soft-delete.md +18 -0
  100. package/agent/tasks/task-75-update-documentation-changelog.md +26 -0
  101. package/agent/tasks/task-76-fix-indexnullstate-schema-bug.md +197 -0
  102. package/dist/collections/composite-ids.d.ts +106 -0
  103. package/dist/collections/core-infrastructure.spec.d.ts +11 -0
  104. package/dist/collections/dot-notation.d.ts +106 -0
  105. package/dist/collections/tracking-arrays.d.ts +176 -0
  106. package/dist/constants/content-types.d.ts +1 -0
  107. package/dist/schema/v2-collections-comments.spec.d.ts +8 -0
  108. package/dist/schema/v2-collections.d.ts +210 -0
  109. package/dist/server-factory.d.ts +15 -0
  110. package/dist/server-factory.js +3261 -1316
  111. package/dist/server.js +2926 -1236
  112. package/dist/services/access-control.d.ts +103 -0
  113. package/dist/services/access-control.spec.d.ts +2 -0
  114. package/dist/services/credentials-provider.d.ts +24 -0
  115. package/dist/services/credentials-provider.spec.d.ts +2 -0
  116. package/dist/services/escalation.service.d.ts +22 -0
  117. package/dist/services/escalation.service.spec.d.ts +2 -0
  118. package/dist/services/ghost-config.service.d.ts +55 -0
  119. package/dist/services/ghost-config.service.spec.d.ts +2 -0
  120. package/dist/services/space-config.service.d.ts +23 -0
  121. package/dist/services/space-config.service.spec.d.ts +2 -0
  122. package/dist/services/trust-enforcement.d.ts +83 -0
  123. package/dist/services/trust-enforcement.spec.d.ts +2 -0
  124. package/dist/services/trust-validator.d.ts +43 -0
  125. package/dist/services/trust-validator.spec.d.ts +2 -0
  126. package/dist/tools/confirm-publish-moderation.spec.d.ts +8 -0
  127. package/dist/tools/confirm.d.ts +8 -1
  128. package/dist/tools/create-memory.d.ts +2 -1
  129. package/dist/tools/create-memory.spec.d.ts +10 -0
  130. package/dist/tools/create-relationship.d.ts +2 -1
  131. package/dist/tools/delete-memory.d.ts +7 -31
  132. package/dist/tools/delete-relationship.d.ts +2 -1
  133. package/dist/tools/deny.d.ts +2 -1
  134. package/dist/tools/find-similar.d.ts +10 -2
  135. package/dist/tools/get-preferences.d.ts +2 -1
  136. package/dist/tools/ghost-config.d.ts +27 -0
  137. package/dist/tools/ghost-config.spec.d.ts +2 -0
  138. package/dist/tools/moderate.d.ts +20 -0
  139. package/dist/tools/moderate.spec.d.ts +5 -0
  140. package/dist/tools/publish.d.ts +11 -3
  141. package/dist/tools/query-memory.d.ts +11 -2
  142. package/dist/tools/query-space.d.ts +4 -1
  143. package/dist/tools/retract.d.ts +29 -0
  144. package/dist/tools/revise.d.ts +45 -0
  145. package/dist/tools/revise.spec.d.ts +8 -0
  146. package/dist/tools/search-memory.d.ts +8 -1
  147. package/dist/tools/search-relationship.d.ts +10 -2
  148. package/dist/tools/search-space.d.ts +25 -5
  149. package/dist/tools/search-space.spec.d.ts +9 -0
  150. package/dist/tools/set-preference.d.ts +2 -1
  151. package/dist/tools/update-memory.d.ts +2 -1
  152. package/dist/tools/update-relationship.d.ts +2 -1
  153. package/dist/types/access-result.d.ts +48 -0
  154. package/dist/types/access-result.spec.d.ts +2 -0
  155. package/dist/types/auth.d.ts +46 -0
  156. package/dist/types/ghost-config.d.ts +36 -0
  157. package/dist/types/memory.d.ts +11 -1
  158. package/dist/types/preferences.d.ts +1 -1
  159. package/dist/types/space-memory.d.ts +3 -0
  160. package/dist/utils/auth-helpers.d.ts +14 -0
  161. package/dist/utils/auth-helpers.spec.d.ts +2 -0
  162. package/dist/utils/test-data-generator.d.ts +124 -0
  163. package/dist/utils/test-data-generator.spec.d.ts +12 -0
  164. package/dist/utils/weaviate-filters.d.ts +19 -0
  165. package/dist/v2-performance.e2e.d.ts +17 -0
  166. package/dist/v2-smoke.e2e.d.ts +14 -0
  167. package/dist/weaviate/client.d.ts +5 -8
  168. package/dist/weaviate/space-schema.d.ts +2 -2
  169. package/docs/performance/v2-benchmarks.md +80 -0
  170. package/jest.e2e.config.js +14 -3
  171. package/package.json +1 -1
  172. package/scripts/.collection-recreation-state.yaml +16 -0
  173. package/scripts/.gitkeep +5 -0
  174. package/scripts/README-collection-recreation.md +224 -0
  175. package/scripts/README.md +51 -0
  176. package/scripts/backup-collections.ts +543 -0
  177. package/scripts/delete-collection.ts +137 -0
  178. package/scripts/migrate-recreate-collections.ts +578 -0
  179. package/scripts/migrate-v1-to-v2.ts +1094 -0
  180. package/scripts/package-lock.json +1113 -0
  181. package/scripts/package.json +27 -0
  182. package/src/collections/composite-ids.ts +193 -0
  183. package/src/collections/core-infrastructure.spec.ts +353 -0
  184. package/src/collections/dot-notation.ts +212 -0
  185. package/src/collections/tracking-arrays.ts +298 -0
  186. package/src/constants/content-types.ts +20 -0
  187. package/src/schema/v2-collections-comments.spec.ts +141 -0
  188. package/src/schema/v2-collections.ts +433 -0
  189. package/src/server-factory.ts +89 -20
  190. package/src/server.ts +45 -17
  191. package/src/services/access-control.spec.ts +383 -0
  192. package/src/services/access-control.ts +291 -0
  193. package/src/services/credentials-provider.spec.ts +22 -0
  194. package/src/services/credentials-provider.ts +34 -0
  195. package/src/services/escalation.service.spec.ts +183 -0
  196. package/src/services/escalation.service.ts +150 -0
  197. package/src/services/ghost-config.service.spec.ts +339 -0
  198. package/src/services/ghost-config.service.ts +219 -0
  199. package/src/services/space-config.service.spec.ts +102 -0
  200. package/src/services/space-config.service.ts +79 -0
  201. package/src/services/trust-enforcement.spec.ts +309 -0
  202. package/src/services/trust-enforcement.ts +197 -0
  203. package/src/services/trust-validator.spec.ts +108 -0
  204. package/src/services/trust-validator.ts +105 -0
  205. package/src/tools/confirm-publish-moderation.spec.ts +240 -0
  206. package/src/tools/confirm.ts +914 -116
  207. package/src/tools/create-memory.spec.ts +126 -0
  208. package/src/tools/create-memory.ts +20 -27
  209. package/src/tools/create-relationship.ts +30 -8
  210. package/src/tools/delete-memory.ts +99 -64
  211. package/src/tools/delete-relationship.ts +15 -6
  212. package/src/tools/deny.ts +8 -1
  213. package/src/tools/find-similar.ts +44 -6
  214. package/src/tools/get-preferences.ts +10 -1
  215. package/src/tools/ghost-config.spec.ts +180 -0
  216. package/src/tools/ghost-config.ts +230 -0
  217. package/src/tools/moderate.spec.ts +277 -0
  218. package/src/tools/moderate.ts +219 -0
  219. package/src/tools/publish.ts +99 -41
  220. package/src/tools/query-memory.ts +44 -9
  221. package/src/tools/query-space.ts +39 -4
  222. package/src/tools/retract.ts +292 -0
  223. package/src/tools/revise.spec.ts +146 -0
  224. package/src/tools/revise.ts +283 -0
  225. package/src/tools/search-memory.ts +46 -10
  226. package/src/tools/search-relationship.ts +30 -7
  227. package/src/tools/search-space.spec.ts +341 -0
  228. package/src/tools/search-space.ts +323 -99
  229. package/src/tools/set-preference.ts +10 -1
  230. package/src/tools/update-memory.ts +24 -5
  231. package/src/tools/update-relationship.ts +10 -1
  232. package/src/types/access-result.spec.ts +193 -0
  233. package/src/types/access-result.ts +62 -0
  234. package/src/types/auth.ts +52 -0
  235. package/src/types/ghost-config.ts +46 -0
  236. package/src/types/memory.ts +20 -1
  237. package/src/types/preferences.ts +2 -2
  238. package/src/types/space-memory.ts +5 -0
  239. package/src/utils/auth-helpers.spec.ts +75 -0
  240. package/src/utils/auth-helpers.ts +25 -0
  241. package/src/utils/test-data-generator.spec.ts +317 -0
  242. package/src/utils/test-data-generator.ts +292 -0
  243. package/src/utils/weaviate-filters.ts +32 -5
  244. package/src/v2-performance.e2e.ts +173 -0
  245. package/src/v2-smoke.e2e.ts +401 -0
  246. package/src/weaviate/client.spec.ts +5 -5
  247. package/src/weaviate/client.ts +55 -35
  248. package/src/weaviate/schema.ts +11 -239
  249. package/src/weaviate/space-schema.spec.ts +28 -25
  250. package/src/weaviate/space-schema.ts +35 -11
@@ -0,0 +1,578 @@
1
+ #!/usr/bin/env tsx
2
+ /**
3
+ * Recreate Collections Migration Script
4
+ *
5
+ * Recreates Weaviate collections with updated schema configuration (indexNullState: true).
6
+ * This is required after v3.0.1 to enable filtering on null values for the soft delete system.
7
+ *
8
+ * CRITICAL: This script will DELETE and RECREATE collections. All data will be preserved
9
+ * by exporting before deletion and re-importing after recreation.
10
+ *
11
+ * Usage:
12
+ * # Using environment variables
13
+ * npx tsx scripts/migrate-recreate-collections.ts
14
+ *
15
+ * # Dry run (test without making changes)
16
+ * npx tsx scripts/migrate-recreate-collections.ts --dry-run
17
+ *
18
+ * # Specific collections only
19
+ * npx tsx scripts/migrate-recreate-collections.ts --collections "Memory_user123,Memory_public"
20
+ */
21
+
22
+ import weaviate, { WeaviateClient } from 'weaviate-client';
23
+ import * as fs from 'fs';
24
+ import * as yaml from 'yaml';
25
+ import * as dotenv from 'dotenv';
26
+ import * as path from 'path';
27
+
28
+ // Load environment
29
+ dotenv.config();
30
+
31
+ // ============================================================================
32
+ // Types
33
+ // ============================================================================
34
+
35
+ interface MigrationConfig {
36
+ weaviate: {
37
+ url: string;
38
+ apiKey?: string;
39
+ openaiApiKey?: string;
40
+ };
41
+ options: {
42
+ batchSize: number;
43
+ dryRun: boolean;
44
+ collections?: string[];
45
+ stateFile: string;
46
+ };
47
+ }
48
+
49
+ interface CollectionBackup {
50
+ name: string;
51
+ schema: any;
52
+ documents: any[];
53
+ totalCount: number;
54
+ }
55
+
56
+ interface MigrationState {
57
+ migration: {
58
+ id: string;
59
+ started_at: string;
60
+ updated_at: string;
61
+ status: 'not_started' | 'in_progress' | 'completed' | 'failed';
62
+ };
63
+ collections: {
64
+ name: string;
65
+ status: 'not_started' | 'backed_up' | 'deleted' | 'recreated' | 'restored' | 'completed' | 'failed';
66
+ total_documents: number;
67
+ backed_up_documents: number;
68
+ restored_documents: number;
69
+ backup_file?: string;
70
+ }[];
71
+ progress: {
72
+ total_collections: number;
73
+ completed_collections: number;
74
+ percentage: number;
75
+ };
76
+ errors: Array<{
77
+ collection: string;
78
+ step: string;
79
+ error: string;
80
+ timestamp: string;
81
+ }>;
82
+ }
83
+
84
+ // ============================================================================
85
+ // State Manager
86
+ // ============================================================================
87
+
88
+ class MigrationStateManager {
89
+ private stateFile: string;
90
+ private state!: MigrationState;
91
+
92
+ constructor(stateFile: string) {
93
+ this.stateFile = stateFile;
94
+ }
95
+
96
+ async initialize(collections: string[]): Promise<void> {
97
+ if (fs.existsSync(this.stateFile)) {
98
+ await this.load();
99
+ console.log(`✓ Resuming migration from ${this.stateFile}\n`);
100
+ } else {
101
+ this.state = this.createInitialState(collections);
102
+ await this.save();
103
+ console.log(`✓ Created migration state file: ${this.stateFile}\n`);
104
+ }
105
+ }
106
+
107
+ private createInitialState(collections: string[]): MigrationState {
108
+ const now = new Date().toISOString();
109
+ return {
110
+ migration: {
111
+ id: `recreate-collections-${now.replace(/[:.]/g, '-').slice(0, 19)}`,
112
+ started_at: now,
113
+ updated_at: now,
114
+ status: 'not_started',
115
+ },
116
+ collections: collections.map(name => ({
117
+ name,
118
+ status: 'not_started',
119
+ total_documents: 0,
120
+ backed_up_documents: 0,
121
+ restored_documents: 0,
122
+ })),
123
+ progress: {
124
+ total_collections: collections.length,
125
+ completed_collections: 0,
126
+ percentage: 0,
127
+ },
128
+ errors: [],
129
+ };
130
+ }
131
+
132
+ async load(): Promise<void> {
133
+ const content = fs.readFileSync(this.stateFile, 'utf8');
134
+ this.state = yaml.parse(content);
135
+ }
136
+
137
+ async save(): Promise<void> {
138
+ this.state.migration.updated_at = new Date().toISOString();
139
+ const content = yaml.stringify(this.state);
140
+ fs.writeFileSync(this.stateFile, content, 'utf8');
141
+ }
142
+
143
+ updateCollectionStatus(
144
+ collectionName: string,
145
+ status: MigrationState['collections'][0]['status'],
146
+ updates?: Partial<MigrationState['collections'][0]>
147
+ ): void {
148
+ const collection = this.state.collections.find(c => c.name === collectionName);
149
+ if (collection) {
150
+ collection.status = status;
151
+ if (updates) {
152
+ Object.assign(collection, updates);
153
+ }
154
+ }
155
+ }
156
+
157
+ async completeCollection(collectionName: string): Promise<void> {
158
+ this.updateCollectionStatus(collectionName, 'completed');
159
+ this.state.progress.completed_collections++;
160
+ this.state.progress.percentage =
161
+ (this.state.progress.completed_collections / this.state.progress.total_collections) * 100;
162
+ await this.save();
163
+ }
164
+
165
+ async addError(collection: string, step: string, error: string): Promise<void> {
166
+ this.state.errors.push({
167
+ collection,
168
+ step,
169
+ error,
170
+ timestamp: new Date().toISOString(),
171
+ });
172
+ await this.save();
173
+ }
174
+
175
+ async complete(): Promise<void> {
176
+ this.state.migration.status = 'completed';
177
+ await this.save();
178
+ }
179
+
180
+ async fail(error: string): Promise<void> {
181
+ this.state.migration.status = 'failed';
182
+ await this.addError('migration', 'global', error);
183
+ }
184
+
185
+ getState(): MigrationState {
186
+ return this.state;
187
+ }
188
+
189
+ async cleanup(): Promise<void> {
190
+ if (fs.existsSync(this.stateFile)) {
191
+ fs.unlinkSync(this.stateFile);
192
+ console.log(`✓ Cleaned up state file: ${this.stateFile}`);
193
+ }
194
+ }
195
+ }
196
+
197
+ // ============================================================================
198
+ // Migration Class
199
+ // ============================================================================
200
+
201
+ class CollectionRecreationMigration {
202
+ private client!: WeaviateClient;
203
+ private config: MigrationConfig;
204
+ private stateManager: MigrationStateManager;
205
+ private backupDir: string = './migration-backups';
206
+
207
+ constructor(config: MigrationConfig) {
208
+ this.config = config;
209
+ this.stateManager = new MigrationStateManager(config.options.stateFile);
210
+ }
211
+
212
+ async connect(): Promise<void> {
213
+ console.log('🔌 Connecting to Weaviate...');
214
+
215
+ const clientConfig: any = {
216
+ authCredentials: this.config.weaviate.apiKey
217
+ ? new weaviate.ApiKey(this.config.weaviate.apiKey)
218
+ : undefined,
219
+ };
220
+
221
+ if (this.config.weaviate.openaiApiKey) {
222
+ clientConfig.headers = {
223
+ 'X-Openai-Api-Key': this.config.weaviate.openaiApiKey,
224
+ };
225
+ }
226
+
227
+ this.client = await weaviate.connectToWeaviateCloud(
228
+ this.config.weaviate.url,
229
+ clientConfig
230
+ );
231
+
232
+ console.log('✓ Connected\n');
233
+ }
234
+
235
+ async disconnect(): Promise<void> {
236
+ await this.client?.close();
237
+ }
238
+
239
+ async discoverCollections(): Promise<string[]> {
240
+ console.log('🔍 Discovering collections...');
241
+
242
+ const allCollections = await this.client.collections.listAll();
243
+ let collectionNames = allCollections
244
+ .map(c => c.name)
245
+ .filter(name => name.startsWith('Memory_'));
246
+
247
+ // Filter by specified collections if provided
248
+ if (this.config.options.collections && this.config.options.collections.length > 0) {
249
+ collectionNames = collectionNames.filter(name =>
250
+ this.config.options.collections!.includes(name)
251
+ );
252
+ }
253
+
254
+ console.log(` Found ${collectionNames.length} collections: ${collectionNames.join(', ')}\n`);
255
+ return collectionNames;
256
+ }
257
+
258
+ async backupCollection(collectionName: string): Promise<CollectionBackup> {
259
+ console.log(` 📥 Backing up ${collectionName}...`);
260
+
261
+ const collection = this.client.collections.get(collectionName);
262
+
263
+ // Get schema
264
+ const schema = await collection.config.get();
265
+
266
+ // Get all documents
267
+ const documents: any[] = [];
268
+ let offset = 0;
269
+ let hasMore = true;
270
+
271
+ const aggregate = await collection.aggregate.overAll();
272
+ const totalCount = aggregate.totalCount || 0;
273
+
274
+ console.log(` Total documents: ${totalCount}`);
275
+
276
+ while (hasMore) {
277
+ const result = await collection.query.fetchObjects({
278
+ limit: this.config.options.batchSize,
279
+ offset,
280
+ includeVector: true,
281
+ });
282
+
283
+ if (result.objects.length === 0) {
284
+ hasMore = false;
285
+ break;
286
+ }
287
+
288
+ documents.push(...result.objects);
289
+ offset += result.objects.length;
290
+
291
+ const percentage = (documents.length / totalCount) * 100;
292
+ process.stdout.write(`\r Progress: ${percentage.toFixed(1)}% (${documents.length}/${totalCount})`);
293
+ }
294
+
295
+ console.log('\n ✓ Backup complete');
296
+
297
+ return {
298
+ name: collectionName,
299
+ schema,
300
+ documents,
301
+ totalCount,
302
+ };
303
+ }
304
+
305
+ async saveBackup(backup: CollectionBackup): Promise<string> {
306
+ // Create backup directory if it doesn't exist
307
+ if (!fs.existsSync(this.backupDir)) {
308
+ fs.mkdirSync(this.backupDir, { recursive: true });
309
+ }
310
+
311
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);
312
+ const backupFile = path.join(this.backupDir, `${backup.name}-${timestamp}.json`);
313
+
314
+ fs.writeFileSync(backupFile, JSON.stringify(backup, null, 2), 'utf8');
315
+ console.log(` ✓ Saved backup: ${backupFile}`);
316
+
317
+ return backupFile;
318
+ }
319
+
320
+ async deleteCollection(collectionName: string): Promise<void> {
321
+ console.log(` 🗑️ Deleting ${collectionName}...`);
322
+
323
+ if (!this.config.options.dryRun) {
324
+ await this.client.collections.delete(collectionName);
325
+ console.log(` ✓ Deleted`);
326
+ } else {
327
+ console.log(` [DRY RUN] Would delete`);
328
+ }
329
+ }
330
+
331
+ async recreateCollection(collectionName: string): Promise<void> {
332
+ console.log(` 🔨 Recreating ${collectionName} with updated schema...`);
333
+
334
+ if (!this.config.options.dryRun) {
335
+ // Import schema creation functions
336
+ const { createMemoryCollection } = await import('../dist/weaviate/schema.js');
337
+ const { ensurePublicCollection } = await import('../dist/weaviate/space-schema.js');
338
+
339
+ if (collectionName === 'Memory_public') {
340
+ await ensurePublicCollection(this.client);
341
+ } else {
342
+ // Extract user ID from collection name (Memory_{user_id})
343
+ const userId = collectionName.replace('Memory_', '');
344
+ await createMemoryCollection(userId);
345
+ }
346
+
347
+ console.log(` ✓ Recreated with indexNullState: true`);
348
+ } else {
349
+ console.log(` [DRY RUN] Would recreate with indexNullState: true`);
350
+ }
351
+ }
352
+
353
+ async restoreDocuments(collectionName: string, documents: any[]): Promise<void> {
354
+ console.log(` 📤 Restoring ${documents.length} documents...`);
355
+
356
+ if (!this.config.options.dryRun) {
357
+ const collection = this.client.collections.get(collectionName);
358
+
359
+ let restored = 0;
360
+ for (let i = 0; i < documents.length; i += this.config.options.batchSize) {
361
+ const batch = documents.slice(i, i + this.config.options.batchSize);
362
+
363
+ const objects = batch.map(doc => ({
364
+ properties: doc.properties,
365
+ vector: doc.vector,
366
+ uuid: doc.uuid, // Preserve original IDs
367
+ }));
368
+
369
+ await collection.data.insertMany(objects);
370
+ restored += batch.length;
371
+
372
+ const percentage = (restored / documents.length) * 100;
373
+ process.stdout.write(`\r Progress: ${percentage.toFixed(1)}% (${restored}/${documents.length})`);
374
+ }
375
+
376
+ console.log('\n ✓ Restore complete');
377
+ } else {
378
+ console.log(` [DRY RUN] Would restore ${documents.length} documents`);
379
+ }
380
+ }
381
+
382
+ async migrateCollection(collectionName: string): Promise<boolean> {
383
+ console.log(`\n📦 Migrating: ${collectionName}`);
384
+ console.log('━'.repeat(60));
385
+
386
+ try {
387
+ // Step 1: Backup
388
+ this.stateManager.updateCollectionStatus(collectionName, 'not_started');
389
+ const backup = await this.backupCollection(collectionName);
390
+
391
+ if (!this.config.options.dryRun) {
392
+ const backupFile = await this.saveBackup(backup);
393
+ this.stateManager.updateCollectionStatus(collectionName, 'backed_up', {
394
+ total_documents: backup.totalCount,
395
+ backed_up_documents: backup.documents.length,
396
+ backup_file: backupFile,
397
+ });
398
+ await this.stateManager.save();
399
+ }
400
+
401
+ // Step 2: Delete
402
+ await this.deleteCollection(collectionName);
403
+ this.stateManager.updateCollectionStatus(collectionName, 'deleted');
404
+ await this.stateManager.save();
405
+
406
+ // Step 3: Recreate
407
+ await this.recreateCollection(collectionName);
408
+ this.stateManager.updateCollectionStatus(collectionName, 'recreated');
409
+ await this.stateManager.save();
410
+
411
+ // Step 4: Restore
412
+ await this.restoreDocuments(collectionName, backup.documents);
413
+ this.stateManager.updateCollectionStatus(collectionName, 'restored', {
414
+ restored_documents: backup.documents.length,
415
+ });
416
+ await this.stateManager.save();
417
+
418
+ // Step 5: Verify
419
+ if (!this.config.options.dryRun) {
420
+ const collection = this.client.collections.get(collectionName);
421
+ const aggregate = await collection.aggregate.overAll();
422
+ const restoredCount = aggregate.totalCount || 0;
423
+
424
+ if (restoredCount !== backup.totalCount) {
425
+ throw new Error(
426
+ `Document count mismatch: backed up ${backup.totalCount}, restored ${restoredCount}`
427
+ );
428
+ }
429
+
430
+ console.log(` ✓ Verified: ${restoredCount} documents restored`);
431
+ }
432
+
433
+ await this.stateManager.completeCollection(collectionName);
434
+ console.log(` ✅ Migration complete\n`);
435
+
436
+ return true;
437
+ } catch (error: any) {
438
+ console.error(` ❌ Migration failed: ${error.message}\n`);
439
+ await this.stateManager.addError(collectionName, 'migration', error.message);
440
+ this.stateManager.updateCollectionStatus(collectionName, 'failed');
441
+ await this.stateManager.save();
442
+ return false;
443
+ }
444
+ }
445
+
446
+ async migrateAll(): Promise<void> {
447
+ console.log('🚀 Collection Recreation Migration');
448
+ console.log('━'.repeat(60));
449
+ console.log('\n📊 Configuration:');
450
+ console.log(` Weaviate URL: ${this.config.weaviate.url}`);
451
+ console.log(` Batch Size: ${this.config.options.batchSize}`);
452
+ console.log(` Dry Run: ${this.config.options.dryRun}`);
453
+ console.log(` Backup Directory: ${this.backupDir}\n`);
454
+
455
+ if (this.config.options.dryRun) {
456
+ console.log('⚠️ DRY RUN MODE - No changes will be made\n');
457
+ }
458
+
459
+ try {
460
+ await this.connect();
461
+
462
+ const collections = await this.discoverCollections();
463
+ await this.stateManager.initialize(collections);
464
+
465
+ let successCount = 0;
466
+ let failCount = 0;
467
+
468
+ for (const collectionName of collections) {
469
+ const success = await this.migrateCollection(collectionName);
470
+ if (success) {
471
+ successCount++;
472
+ } else {
473
+ failCount++;
474
+ }
475
+ }
476
+
477
+ // Summary
478
+ console.log('━'.repeat(60));
479
+ console.log('✅ Migration Summary:');
480
+ console.log('━'.repeat(60));
481
+ console.log(` Total Collections: ${collections.length}`);
482
+ console.log(` Successful: ${successCount}`);
483
+ console.log(` Failed: ${failCount}`);
484
+ console.log(` Dry Run: ${this.config.options.dryRun}\n`);
485
+
486
+ if (failCount === 0) {
487
+ await this.stateManager.complete();
488
+
489
+ if (!this.config.options.dryRun) {
490
+ await this.stateManager.cleanup();
491
+ console.log('✨ Migration completed successfully!\n');
492
+ } else {
493
+ console.log('✨ Dry run completed successfully!\n');
494
+ }
495
+ } else {
496
+ console.log(`⚠️ Migration completed with ${failCount} failures`);
497
+ console.log(` Check ${this.config.options.stateFile} for details\n`);
498
+ }
499
+
500
+ } catch (error: any) {
501
+ console.error(`\n❌ Migration failed: ${error.message}`);
502
+ await this.stateManager.fail(error.message);
503
+ throw error;
504
+ } finally {
505
+ await this.disconnect();
506
+ }
507
+ }
508
+ }
509
+
510
+ // ============================================================================
511
+ // Configuration
512
+ // ============================================================================
513
+
514
+ function loadConfig(): MigrationConfig {
515
+ // Parse CLI arguments
516
+ const args = process.argv.slice(2);
517
+ const cliArgs: Record<string, string> = {};
518
+
519
+ for (let i = 0; i < args.length; i++) {
520
+ if (args[i].startsWith('--')) {
521
+ const key = args[i].slice(2);
522
+ const value = args[i + 1];
523
+ if (value && !value.startsWith('--')) {
524
+ cliArgs[key] = value;
525
+ i++;
526
+ } else {
527
+ cliArgs[key] = 'true';
528
+ }
529
+ }
530
+ }
531
+
532
+ const config: MigrationConfig = {
533
+ weaviate: {
534
+ url: cliArgs['weaviate-url'] || process.env.WEAVIATE_REST_URL || '',
535
+ apiKey: cliArgs['weaviate-key'] || process.env.WEAVIATE_API_KEY,
536
+ openaiApiKey: cliArgs['openai-key'] || process.env.OPENAI_EMBEDDINGS_API_KEY,
537
+ },
538
+ options: {
539
+ batchSize: parseInt(cliArgs['batch-size'] || process.env.BATCH_SIZE || '100'),
540
+ dryRun: cliArgs['dry-run'] === 'true',
541
+ collections: cliArgs['collections']?.split(',').map(c => c.trim()),
542
+ stateFile: cliArgs['state-file'] || '.collection-recreation-state.yaml',
543
+ },
544
+ };
545
+
546
+ // Validate
547
+ if (!config.weaviate.url) {
548
+ throw new Error('Weaviate URL is required (--weaviate-url or WEAVIATE_REST_URL)');
549
+ }
550
+
551
+ return config;
552
+ }
553
+
554
+ // ============================================================================
555
+ // Main
556
+ // ============================================================================
557
+
558
+ async function main() {
559
+ try {
560
+ const config = loadConfig();
561
+ const migration = new CollectionRecreationMigration(config);
562
+
563
+ await migration.migrateAll();
564
+
565
+ process.exit(0);
566
+ } catch (error: any) {
567
+ console.error(`\n❌ Fatal error: ${error.message}`);
568
+ console.error(error.stack);
569
+ process.exit(1);
570
+ }
571
+ }
572
+
573
+ // Run if executed directly
574
+ if (import.meta.url === `file://${process.argv[1]}`) {
575
+ main();
576
+ }
577
+
578
+ export { CollectionRecreationMigration, type MigrationConfig };