@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.
- package/AGENT.md +296 -250
- package/CHANGELOG.md +468 -0
- package/README.md +163 -46
- package/agent/commands/acp.clarification-create.md +382 -0
- package/agent/commands/acp.command-create.md +0 -1
- package/agent/commands/acp.design-create.md +0 -1
- package/agent/commands/acp.init.md +0 -1
- package/agent/commands/acp.package-create.md +0 -1
- package/agent/commands/acp.package-info.md +0 -1
- package/agent/commands/acp.package-install.md +0 -1
- package/agent/commands/acp.package-list.md +0 -1
- package/agent/commands/acp.package-publish.md +0 -1
- package/agent/commands/acp.package-remove.md +0 -1
- package/agent/commands/acp.package-search.md +0 -1
- package/agent/commands/acp.package-update.md +0 -1
- package/agent/commands/acp.package-validate.md +0 -1
- package/agent/commands/acp.pattern-create.md +0 -1
- package/agent/commands/acp.plan.md +0 -1
- package/agent/commands/acp.proceed.md +0 -1
- package/agent/commands/acp.project-create.md +0 -1
- package/agent/commands/acp.project-info.md +309 -0
- package/agent/commands/acp.project-list.md +0 -1
- package/agent/commands/acp.project-remove.md +379 -0
- package/agent/commands/acp.project-set.md +0 -1
- package/agent/commands/acp.project-update.md +296 -0
- package/agent/commands/acp.report.md +0 -1
- package/agent/commands/acp.resume.md +0 -1
- package/agent/commands/acp.status.md +0 -1
- package/agent/commands/acp.sync.md +0 -1
- package/agent/commands/acp.task-create.md +17 -10
- package/agent/commands/acp.update.md +0 -1
- package/agent/commands/acp.validate.md +0 -1
- package/agent/commands/acp.version-check-for-updates.md +0 -1
- package/agent/commands/acp.version-check.md +0 -1
- package/agent/commands/acp.version-update.md +0 -1
- package/agent/commands/command.template.md +0 -5
- package/agent/commands/git.commit.md +13 -2
- package/agent/commands/git.init.md +0 -1
- package/agent/design/comment-memory-type.md +2 -2
- package/agent/design/local.collaborative-memory-sync.md +265 -0
- package/agent/design/local.content-flags.md +210 -0
- package/agent/design/local.ghost-persona-system.md +273 -0
- package/agent/design/local.group-acl-integration.md +338 -0
- package/agent/design/local.memory-acl-schema.md +352 -0
- package/agent/design/local.memory-collection-pattern-v2.md +348 -0
- package/agent/design/local.moderation-and-space-config.md +257 -0
- package/agent/design/local.v2-api-reference.md +621 -0
- package/agent/design/local.v2-migration-guide.md +191 -0
- package/agent/design/local.v2-usage-examples.md +265 -0
- package/agent/design/permissions-storage-architecture.md +11 -3
- package/agent/design/soft-delete-system.md +291 -0
- package/agent/design/trust-escalation-prevention.md +9 -2
- package/agent/design/trust-system-implementation.md +12 -3
- package/agent/milestones/milestone-13-soft-delete-system.md +306 -0
- package/agent/milestones/milestone-14-memory-collection-v2.md +182 -0
- package/agent/milestones/milestone-15-moderation-space-config.md +126 -0
- package/agent/package.template.yaml +0 -17
- package/agent/progress.yaml +762 -49
- package/agent/scripts/acp.common.sh +2 -0
- package/agent/scripts/acp.install.sh +15 -85
- package/agent/scripts/acp.package-install-optimized.sh +454 -0
- package/agent/scripts/acp.package-install.sh +248 -380
- package/agent/scripts/acp.package-validate.sh +0 -99
- package/agent/scripts/acp.project-info.sh +218 -0
- package/agent/scripts/acp.project-remove.sh +302 -0
- package/agent/scripts/acp.project-update.sh +296 -0
- package/agent/scripts/acp.yaml-parser.sh +128 -10
- package/agent/tasks/milestone-14-memory-collection-v2/task-165-core-infrastructure-setup.md +171 -0
- package/agent/tasks/milestone-14-memory-collection-v2/task-166-update-remember-publish.md +191 -0
- package/agent/tasks/milestone-14-memory-collection-v2/task-167-update-remember-retract.md +186 -0
- package/agent/tasks/milestone-14-memory-collection-v2/task-168-implement-remember-revise.md +184 -0
- package/agent/tasks/milestone-14-memory-collection-v2/task-169-update-remember-search-space.md +179 -0
- package/agent/tasks/milestone-14-memory-collection-v2/task-170-update-remember-create-update.md +139 -0
- package/agent/tasks/milestone-14-memory-collection-v2/task-172-performance-testing-optimization.md +161 -0
- package/agent/tasks/milestone-14-memory-collection-v2/task-173-documentation-examples.md +258 -0
- package/agent/tasks/milestone-15-moderation-space-config/task-174-add-moderation-schema-fields.md +57 -0
- package/agent/tasks/milestone-15-moderation-space-config/task-175-create-space-config-service.md +64 -0
- package/agent/tasks/milestone-15-moderation-space-config/task-176-wire-moderation-publish-flow.md +45 -0
- package/agent/tasks/milestone-15-moderation-space-config/task-177-add-moderation-search-filters.md +70 -0
- package/agent/tasks/milestone-15-moderation-space-config/task-178-create-remember-moderate-tool.md +69 -0
- package/agent/tasks/milestone-15-moderation-space-config/task-179-documentation-integration-tests.md +58 -0
- package/agent/tasks/milestone-16-ghost-system/task-187-ghost-config-firestore.md +41 -0
- package/agent/tasks/milestone-16-ghost-system/task-188-trust-filter-integration.md +44 -0
- package/agent/tasks/milestone-16-ghost-system/task-189-ghost-memory-filtering.md +43 -0
- package/agent/tasks/milestone-16-ghost-system/task-190-ghost-config-tools.md +45 -0
- package/agent/tasks/milestone-16-ghost-system/task-191-escalation-firestore.md +38 -0
- package/agent/tasks/milestone-16-ghost-system/task-192-documentation-verification.md +39 -0
- package/agent/tasks/milestone-7-trust-permissions/task-180-access-result-permission-types.md +69 -0
- package/agent/tasks/milestone-7-trust-permissions/task-181-firestore-permissions-access-logs.md +56 -0
- package/agent/tasks/milestone-7-trust-permissions/task-182-trust-enforcement-service.md +68 -0
- package/agent/tasks/milestone-7-trust-permissions/task-183-access-control-service.md +70 -0
- package/agent/tasks/milestone-7-trust-permissions/task-184-permission-tools.md +79 -0
- package/agent/tasks/milestone-7-trust-permissions/task-185-wire-trust-into-search-query.md +55 -0
- package/agent/tasks/milestone-7-trust-permissions/task-186-documentation-verification.md +56 -0
- package/agent/tasks/task-70-add-soft-delete-schema-fields.md +165 -0
- package/agent/tasks/task-71-implement-delete-confirmation-flow.md +257 -0
- package/agent/tasks/task-72-add-deleted-filter-to-search-tools.md +18 -0
- package/agent/tasks/task-73-update-relationship-handling.md +18 -0
- package/agent/tasks/task-74-add-unit-tests-soft-delete.md +18 -0
- package/agent/tasks/task-75-update-documentation-changelog.md +26 -0
- package/agent/tasks/task-76-fix-indexnullstate-schema-bug.md +197 -0
- package/dist/collections/composite-ids.d.ts +106 -0
- package/dist/collections/core-infrastructure.spec.d.ts +11 -0
- package/dist/collections/dot-notation.d.ts +106 -0
- package/dist/collections/tracking-arrays.d.ts +176 -0
- package/dist/constants/content-types.d.ts +1 -0
- package/dist/schema/v2-collections-comments.spec.d.ts +8 -0
- package/dist/schema/v2-collections.d.ts +210 -0
- package/dist/server-factory.d.ts +15 -0
- package/dist/server-factory.js +3261 -1316
- package/dist/server.js +2926 -1236
- package/dist/services/access-control.d.ts +103 -0
- package/dist/services/access-control.spec.d.ts +2 -0
- package/dist/services/credentials-provider.d.ts +24 -0
- package/dist/services/credentials-provider.spec.d.ts +2 -0
- package/dist/services/escalation.service.d.ts +22 -0
- package/dist/services/escalation.service.spec.d.ts +2 -0
- package/dist/services/ghost-config.service.d.ts +55 -0
- package/dist/services/ghost-config.service.spec.d.ts +2 -0
- package/dist/services/space-config.service.d.ts +23 -0
- package/dist/services/space-config.service.spec.d.ts +2 -0
- package/dist/services/trust-enforcement.d.ts +83 -0
- package/dist/services/trust-enforcement.spec.d.ts +2 -0
- package/dist/services/trust-validator.d.ts +43 -0
- package/dist/services/trust-validator.spec.d.ts +2 -0
- package/dist/tools/confirm-publish-moderation.spec.d.ts +8 -0
- package/dist/tools/confirm.d.ts +8 -1
- package/dist/tools/create-memory.d.ts +2 -1
- package/dist/tools/create-memory.spec.d.ts +10 -0
- package/dist/tools/create-relationship.d.ts +2 -1
- package/dist/tools/delete-memory.d.ts +7 -31
- package/dist/tools/delete-relationship.d.ts +2 -1
- package/dist/tools/deny.d.ts +2 -1
- package/dist/tools/find-similar.d.ts +10 -2
- package/dist/tools/get-preferences.d.ts +2 -1
- package/dist/tools/ghost-config.d.ts +27 -0
- package/dist/tools/ghost-config.spec.d.ts +2 -0
- package/dist/tools/moderate.d.ts +20 -0
- package/dist/tools/moderate.spec.d.ts +5 -0
- package/dist/tools/publish.d.ts +11 -3
- package/dist/tools/query-memory.d.ts +11 -2
- package/dist/tools/query-space.d.ts +4 -1
- package/dist/tools/retract.d.ts +29 -0
- package/dist/tools/revise.d.ts +45 -0
- package/dist/tools/revise.spec.d.ts +8 -0
- package/dist/tools/search-memory.d.ts +8 -1
- package/dist/tools/search-relationship.d.ts +10 -2
- package/dist/tools/search-space.d.ts +25 -5
- package/dist/tools/search-space.spec.d.ts +9 -0
- package/dist/tools/set-preference.d.ts +2 -1
- package/dist/tools/update-memory.d.ts +2 -1
- package/dist/tools/update-relationship.d.ts +2 -1
- package/dist/types/access-result.d.ts +48 -0
- package/dist/types/access-result.spec.d.ts +2 -0
- package/dist/types/auth.d.ts +46 -0
- package/dist/types/ghost-config.d.ts +36 -0
- package/dist/types/memory.d.ts +11 -1
- package/dist/types/preferences.d.ts +1 -1
- package/dist/types/space-memory.d.ts +3 -0
- package/dist/utils/auth-helpers.d.ts +14 -0
- package/dist/utils/auth-helpers.spec.d.ts +2 -0
- package/dist/utils/test-data-generator.d.ts +124 -0
- package/dist/utils/test-data-generator.spec.d.ts +12 -0
- package/dist/utils/weaviate-filters.d.ts +19 -0
- package/dist/v2-performance.e2e.d.ts +17 -0
- package/dist/v2-smoke.e2e.d.ts +14 -0
- package/dist/weaviate/client.d.ts +5 -8
- package/dist/weaviate/space-schema.d.ts +2 -2
- package/docs/performance/v2-benchmarks.md +80 -0
- package/jest.e2e.config.js +14 -3
- package/package.json +1 -1
- package/scripts/.collection-recreation-state.yaml +16 -0
- package/scripts/.gitkeep +5 -0
- package/scripts/README-collection-recreation.md +224 -0
- package/scripts/README.md +51 -0
- package/scripts/backup-collections.ts +543 -0
- package/scripts/delete-collection.ts +137 -0
- package/scripts/migrate-recreate-collections.ts +578 -0
- package/scripts/migrate-v1-to-v2.ts +1094 -0
- package/scripts/package-lock.json +1113 -0
- package/scripts/package.json +27 -0
- package/src/collections/composite-ids.ts +193 -0
- package/src/collections/core-infrastructure.spec.ts +353 -0
- package/src/collections/dot-notation.ts +212 -0
- package/src/collections/tracking-arrays.ts +298 -0
- package/src/constants/content-types.ts +20 -0
- package/src/schema/v2-collections-comments.spec.ts +141 -0
- package/src/schema/v2-collections.ts +433 -0
- package/src/server-factory.ts +89 -20
- package/src/server.ts +45 -17
- package/src/services/access-control.spec.ts +383 -0
- package/src/services/access-control.ts +291 -0
- package/src/services/credentials-provider.spec.ts +22 -0
- package/src/services/credentials-provider.ts +34 -0
- package/src/services/escalation.service.spec.ts +183 -0
- package/src/services/escalation.service.ts +150 -0
- package/src/services/ghost-config.service.spec.ts +339 -0
- package/src/services/ghost-config.service.ts +219 -0
- package/src/services/space-config.service.spec.ts +102 -0
- package/src/services/space-config.service.ts +79 -0
- package/src/services/trust-enforcement.spec.ts +309 -0
- package/src/services/trust-enforcement.ts +197 -0
- package/src/services/trust-validator.spec.ts +108 -0
- package/src/services/trust-validator.ts +105 -0
- package/src/tools/confirm-publish-moderation.spec.ts +240 -0
- package/src/tools/confirm.ts +914 -116
- package/src/tools/create-memory.spec.ts +126 -0
- package/src/tools/create-memory.ts +20 -27
- package/src/tools/create-relationship.ts +30 -8
- package/src/tools/delete-memory.ts +99 -64
- package/src/tools/delete-relationship.ts +15 -6
- package/src/tools/deny.ts +8 -1
- package/src/tools/find-similar.ts +44 -6
- package/src/tools/get-preferences.ts +10 -1
- package/src/tools/ghost-config.spec.ts +180 -0
- package/src/tools/ghost-config.ts +230 -0
- package/src/tools/moderate.spec.ts +277 -0
- package/src/tools/moderate.ts +219 -0
- package/src/tools/publish.ts +99 -41
- package/src/tools/query-memory.ts +44 -9
- package/src/tools/query-space.ts +39 -4
- package/src/tools/retract.ts +292 -0
- package/src/tools/revise.spec.ts +146 -0
- package/src/tools/revise.ts +283 -0
- package/src/tools/search-memory.ts +46 -10
- package/src/tools/search-relationship.ts +30 -7
- package/src/tools/search-space.spec.ts +341 -0
- package/src/tools/search-space.ts +323 -99
- package/src/tools/set-preference.ts +10 -1
- package/src/tools/update-memory.ts +24 -5
- package/src/tools/update-relationship.ts +10 -1
- package/src/types/access-result.spec.ts +193 -0
- package/src/types/access-result.ts +62 -0
- package/src/types/auth.ts +52 -0
- package/src/types/ghost-config.ts +46 -0
- package/src/types/memory.ts +20 -1
- package/src/types/preferences.ts +2 -2
- package/src/types/space-memory.ts +5 -0
- package/src/utils/auth-helpers.spec.ts +75 -0
- package/src/utils/auth-helpers.ts +25 -0
- package/src/utils/test-data-generator.spec.ts +317 -0
- package/src/utils/test-data-generator.ts +292 -0
- package/src/utils/weaviate-filters.ts +32 -5
- package/src/v2-performance.e2e.ts +173 -0
- package/src/v2-smoke.e2e.ts +401 -0
- package/src/weaviate/client.spec.ts +5 -5
- package/src/weaviate/client.ts +55 -35
- package/src/weaviate/schema.ts +11 -239
- package/src/weaviate/space-schema.spec.ts +28 -25
- 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 };
|