@savestate/cli 0.4.2 → 0.6.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 (40) hide show
  1. package/README.md +34 -6
  2. package/dist/adapters/clawdbot.d.ts +69 -58
  3. package/dist/adapters/clawdbot.d.ts.map +1 -1
  4. package/dist/adapters/clawdbot.js +375 -101
  5. package/dist/adapters/clawdbot.js.map +1 -1
  6. package/dist/cli.js +8 -0
  7. package/dist/cli.js.map +1 -1
  8. package/dist/mcp/server.d.ts +26 -0
  9. package/dist/mcp/server.d.ts.map +1 -0
  10. package/dist/mcp/server.js +371 -0
  11. package/dist/mcp/server.js.map +1 -0
  12. package/dist/migrate/capabilities.d.ts +23 -0
  13. package/dist/migrate/capabilities.d.ts.map +1 -0
  14. package/dist/migrate/capabilities.js +80 -0
  15. package/dist/migrate/capabilities.js.map +1 -0
  16. package/dist/migrate/extractors/registry.d.ts +24 -0
  17. package/dist/migrate/extractors/registry.d.ts.map +1 -0
  18. package/dist/migrate/extractors/registry.js +38 -0
  19. package/dist/migrate/extractors/registry.js.map +1 -0
  20. package/dist/migrate/index.d.ts +13 -0
  21. package/dist/migrate/index.d.ts.map +1 -0
  22. package/dist/migrate/index.js +15 -0
  23. package/dist/migrate/index.js.map +1 -0
  24. package/dist/migrate/loaders/registry.d.ts +24 -0
  25. package/dist/migrate/loaders/registry.d.ts.map +1 -0
  26. package/dist/migrate/loaders/registry.js +38 -0
  27. package/dist/migrate/loaders/registry.js.map +1 -0
  28. package/dist/migrate/orchestrator.d.ts +77 -0
  29. package/dist/migrate/orchestrator.d.ts.map +1 -0
  30. package/dist/migrate/orchestrator.js +322 -0
  31. package/dist/migrate/orchestrator.js.map +1 -0
  32. package/dist/migrate/transformers/registry.d.ts +27 -0
  33. package/dist/migrate/transformers/registry.d.ts.map +1 -0
  34. package/dist/migrate/transformers/registry.js +47 -0
  35. package/dist/migrate/transformers/registry.js.map +1 -0
  36. package/dist/migrate/types.d.ts +350 -0
  37. package/dist/migrate/types.d.ts.map +1 -0
  38. package/dist/migrate/types.js +8 -0
  39. package/dist/migrate/types.js.map +1 -0
  40. package/package.json +4 -2
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Platform Capabilities
3
+ *
4
+ * Defines what each platform supports for compatibility checking.
5
+ */
6
+ export const PLATFORM_CAPABILITIES = {
7
+ chatgpt: {
8
+ id: 'chatgpt',
9
+ name: 'ChatGPT',
10
+ instructionLimit: 1500,
11
+ hasMemory: true,
12
+ memoryLimit: 100,
13
+ hasFiles: true,
14
+ fileSizeLimit: 512 * 1024 * 1024, // 512MB
15
+ hasProjects: false,
16
+ hasConversations: true,
17
+ hasCustomBots: true,
18
+ },
19
+ claude: {
20
+ id: 'claude',
21
+ name: 'Claude',
22
+ instructionLimit: 8000, // System prompt can be much longer
23
+ hasMemory: false, // Claude uses project knowledge instead
24
+ hasFiles: true,
25
+ fileSizeLimit: 32 * 1024 * 1024, // 32MB per file
26
+ hasProjects: true,
27
+ hasConversations: true,
28
+ hasCustomBots: false, // Projects serve this role
29
+ },
30
+ gemini: {
31
+ id: 'gemini',
32
+ name: 'Gemini',
33
+ instructionLimit: 4000,
34
+ hasMemory: true,
35
+ memoryLimit: 50,
36
+ hasFiles: true,
37
+ fileSizeLimit: 20 * 1024 * 1024, // 20MB
38
+ hasProjects: false,
39
+ hasConversations: true,
40
+ hasCustomBots: false,
41
+ },
42
+ copilot: {
43
+ id: 'copilot',
44
+ name: 'Microsoft Copilot',
45
+ instructionLimit: 2000,
46
+ hasMemory: true,
47
+ hasFiles: true,
48
+ fileSizeLimit: 10 * 1024 * 1024, // 10MB
49
+ hasProjects: false,
50
+ hasConversations: true,
51
+ hasCustomBots: false,
52
+ },
53
+ };
54
+ /**
55
+ * Get capabilities for a platform.
56
+ */
57
+ export function getPlatformCapabilities(platform) {
58
+ return PLATFORM_CAPABILITIES[platform];
59
+ }
60
+ /**
61
+ * Check if a migration path is supported.
62
+ */
63
+ export function isMigrationSupported(source, target) {
64
+ // Currently supported paths
65
+ const supported = [
66
+ ['chatgpt', 'claude'],
67
+ ['claude', 'chatgpt'],
68
+ ];
69
+ return supported.some(([s, t]) => s === source && t === target);
70
+ }
71
+ /**
72
+ * Get all supported migration paths.
73
+ */
74
+ export function getSupportedMigrations() {
75
+ return [
76
+ { source: 'chatgpt', target: 'claude' },
77
+ { source: 'claude', target: 'chatgpt' },
78
+ ];
79
+ }
80
+ //# sourceMappingURL=capabilities.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capabilities.js","sourceRoot":"","sources":["../../src/migrate/capabilities.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,MAAM,CAAC,MAAM,qBAAqB,GAA2C;IAC3E,OAAO,EAAE;QACP,EAAE,EAAE,SAAS;QACb,IAAI,EAAE,SAAS;QACf,gBAAgB,EAAE,IAAI;QACtB,SAAS,EAAE,IAAI;QACf,WAAW,EAAE,GAAG;QAChB,QAAQ,EAAE,IAAI;QACd,aAAa,EAAE,GAAG,GAAG,IAAI,GAAG,IAAI,EAAE,QAAQ;QAC1C,WAAW,EAAE,KAAK;QAClB,gBAAgB,EAAE,IAAI;QACtB,aAAa,EAAE,IAAI;KACpB;IACD,MAAM,EAAE;QACN,EAAE,EAAE,QAAQ;QACZ,IAAI,EAAE,QAAQ;QACd,gBAAgB,EAAE,IAAI,EAAE,mCAAmC;QAC3D,SAAS,EAAE,KAAK,EAAE,wCAAwC;QAC1D,QAAQ,EAAE,IAAI;QACd,aAAa,EAAE,EAAE,GAAG,IAAI,GAAG,IAAI,EAAE,gBAAgB;QACjD,WAAW,EAAE,IAAI;QACjB,gBAAgB,EAAE,IAAI;QACtB,aAAa,EAAE,KAAK,EAAE,2BAA2B;KAClD;IACD,MAAM,EAAE;QACN,EAAE,EAAE,QAAQ;QACZ,IAAI,EAAE,QAAQ;QACd,gBAAgB,EAAE,IAAI;QACtB,SAAS,EAAE,IAAI;QACf,WAAW,EAAE,EAAE;QACf,QAAQ,EAAE,IAAI;QACd,aAAa,EAAE,EAAE,GAAG,IAAI,GAAG,IAAI,EAAE,OAAO;QACxC,WAAW,EAAE,KAAK;QAClB,gBAAgB,EAAE,IAAI;QACtB,aAAa,EAAE,KAAK;KACrB;IACD,OAAO,EAAE;QACP,EAAE,EAAE,SAAS;QACb,IAAI,EAAE,mBAAmB;QACzB,gBAAgB,EAAE,IAAI;QACtB,SAAS,EAAE,IAAI;QACf,QAAQ,EAAE,IAAI;QACd,aAAa,EAAE,EAAE,GAAG,IAAI,GAAG,IAAI,EAAE,OAAO;QACxC,WAAW,EAAE,KAAK;QAClB,gBAAgB,EAAE,IAAI;QACtB,aAAa,EAAE,KAAK;KACrB;CACF,CAAC;AAEF;;GAEG;AACH,MAAM,UAAU,uBAAuB,CAAC,QAAkB;IACxD,OAAO,qBAAqB,CAAC,QAAQ,CAAC,CAAC;AACzC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,oBAAoB,CAAC,MAAgB,EAAE,MAAgB;IACrE,4BAA4B;IAC5B,MAAM,SAAS,GAAG;QAChB,CAAC,SAAS,EAAE,QAAQ,CAAC;QACrB,CAAC,QAAQ,EAAE,SAAS,CAAC;KACtB,CAAC;IAEF,OAAO,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,MAAM,IAAI,CAAC,KAAK,MAAM,CAAC,CAAC;AAClE,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,sBAAsB;IACpC,OAAO;QACL,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE;QACvC,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE;KACxC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Extractor Registry
3
+ *
4
+ * Manages available extractors for different platforms.
5
+ * New extractors are registered here.
6
+ */
7
+ import type { Platform, Extractor } from '../types.js';
8
+ /**
9
+ * Register an extractor for a platform.
10
+ */
11
+ export declare function registerExtractor(platform: Platform, factory: () => Extractor): void;
12
+ /**
13
+ * Get an extractor for a platform.
14
+ */
15
+ export declare function getExtractor(platform: Platform): Extractor | null;
16
+ /**
17
+ * List all registered extractors.
18
+ */
19
+ export declare function listExtractors(): Platform[];
20
+ /**
21
+ * Check if an extractor exists for a platform.
22
+ */
23
+ export declare function hasExtractor(platform: Platform): boolean;
24
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../../src/migrate/extractors/registry.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAIvD;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,SAAS,GAAG,IAAI,CAEpF;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,QAAQ,GAAG,SAAS,GAAG,IAAI,CAGjE;AAED;;GAEG;AACH,wBAAgB,cAAc,IAAI,QAAQ,EAAE,CAE3C;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAExD"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Extractor Registry
3
+ *
4
+ * Manages available extractors for different platforms.
5
+ * New extractors are registered here.
6
+ */
7
+ const extractors = new Map();
8
+ /**
9
+ * Register an extractor for a platform.
10
+ */
11
+ export function registerExtractor(platform, factory) {
12
+ extractors.set(platform, factory);
13
+ }
14
+ /**
15
+ * Get an extractor for a platform.
16
+ */
17
+ export function getExtractor(platform) {
18
+ const factory = extractors.get(platform);
19
+ return factory ? factory() : null;
20
+ }
21
+ /**
22
+ * List all registered extractors.
23
+ */
24
+ export function listExtractors() {
25
+ return [...extractors.keys()];
26
+ }
27
+ /**
28
+ * Check if an extractor exists for a platform.
29
+ */
30
+ export function hasExtractor(platform) {
31
+ return extractors.has(platform);
32
+ }
33
+ // ─── Register Built-in Extractors ────────────────────────────
34
+ // ChatGPT extractor will be registered in #24
35
+ // registerExtractor('chatgpt', () => new ChatGPTExtractor());
36
+ // Claude extractor will be registered in #29
37
+ // registerExtractor('claude', () => new ClaudeExtractor());
38
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../../src/migrate/extractors/registry.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,MAAM,UAAU,GAAG,IAAI,GAAG,EAA6B,CAAC;AAExD;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAAC,QAAkB,EAAE,OAAwB;IAC5E,UAAU,CAAC,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;AACpC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,YAAY,CAAC,QAAkB;IAC7C,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACzC,OAAO,OAAO,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AACpC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,cAAc;IAC5B,OAAO,CAAC,GAAG,UAAU,CAAC,IAAI,EAAE,CAAC,CAAC;AAChC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,YAAY,CAAC,QAAkB;IAC7C,OAAO,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AAClC,CAAC;AAED,gEAAgE;AAEhE,8CAA8C;AAC9C,8DAA8D;AAE9D,6CAA6C;AAC7C,4DAA4D"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Migration Wizard
3
+ *
4
+ * Platform-to-platform AI identity migration.
5
+ * Extract → Transform → Load
6
+ */
7
+ export type { Platform, PlatformCapabilities, MigrationBundle, MigrationContents, MigrationState, MigrationPhase, MigrationOptions, MigrationCheckpoint, CompatibilityReport, CompatibilityItem, CompatibilityStatus, Extractor, ExtractOptions, Transformer, TransformOptions, Loader, LoadOptions, LoadResult, } from './types.js';
8
+ export { MigrationOrchestrator, type MigrationEvent, type MigrationEventHandler } from './orchestrator.js';
9
+ export { getExtractor, registerExtractor, listExtractors, hasExtractor } from './extractors/registry.js';
10
+ export { getTransformer, registerTransformer, listTransformers, hasTransformer } from './transformers/registry.js';
11
+ export { getLoader, registerLoader, listLoaders, hasLoader } from './loaders/registry.js';
12
+ export { getPlatformCapabilities, PLATFORM_CAPABILITIES } from './capabilities.js';
13
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/migrate/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,YAAY,EACV,QAAQ,EACR,oBAAoB,EACpB,eAAe,EACf,iBAAiB,EACjB,cAAc,EACd,cAAc,EACd,gBAAgB,EAChB,mBAAmB,EACnB,mBAAmB,EACnB,iBAAiB,EACjB,mBAAmB,EACnB,SAAS,EACT,cAAc,EACd,WAAW,EACX,gBAAgB,EAChB,MAAM,EACN,WAAW,EACX,UAAU,GACX,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,qBAAqB,EAAE,KAAK,cAAc,EAAE,KAAK,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAG3G,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACzG,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AACnH,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAG1F,OAAO,EAAE,uBAAuB,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Migration Wizard
3
+ *
4
+ * Platform-to-platform AI identity migration.
5
+ * Extract → Transform → Load
6
+ */
7
+ // Orchestrator
8
+ export { MigrationOrchestrator } from './orchestrator.js';
9
+ // Registries
10
+ export { getExtractor, registerExtractor, listExtractors, hasExtractor } from './extractors/registry.js';
11
+ export { getTransformer, registerTransformer, listTransformers, hasTransformer } from './transformers/registry.js';
12
+ export { getLoader, registerLoader, listLoaders, hasLoader } from './loaders/registry.js';
13
+ // Platform capabilities (for compatibility checking)
14
+ export { getPlatformCapabilities, PLATFORM_CAPABILITIES } from './capabilities.js';
15
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/migrate/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAwBH,eAAe;AACf,OAAO,EAAE,qBAAqB,EAAmD,MAAM,mBAAmB,CAAC;AAE3G,aAAa;AACb,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACzG,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AACnH,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAE1F,qDAAqD;AACrD,OAAO,EAAE,uBAAuB,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Loader Registry
3
+ *
4
+ * Manages available loaders for different platforms.
5
+ * New loaders are registered here.
6
+ */
7
+ import type { Platform, Loader } from '../types.js';
8
+ /**
9
+ * Register a loader for a platform.
10
+ */
11
+ export declare function registerLoader(platform: Platform, factory: () => Loader): void;
12
+ /**
13
+ * Get a loader for a platform.
14
+ */
15
+ export declare function getLoader(platform: Platform): Loader | null;
16
+ /**
17
+ * List all registered loaders.
18
+ */
19
+ export declare function listLoaders(): Platform[];
20
+ /**
21
+ * Check if a loader exists for a platform.
22
+ */
23
+ export declare function hasLoader(platform: Platform): boolean;
24
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../../src/migrate/loaders/registry.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAIpD;;GAEG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,MAAM,GAAG,IAAI,CAE9E;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,GAAG,IAAI,CAG3D;AAED;;GAEG;AACH,wBAAgB,WAAW,IAAI,QAAQ,EAAE,CAExC;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAErD"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Loader Registry
3
+ *
4
+ * Manages available loaders for different platforms.
5
+ * New loaders are registered here.
6
+ */
7
+ const loaders = new Map();
8
+ /**
9
+ * Register a loader for a platform.
10
+ */
11
+ export function registerLoader(platform, factory) {
12
+ loaders.set(platform, factory);
13
+ }
14
+ /**
15
+ * Get a loader for a platform.
16
+ */
17
+ export function getLoader(platform) {
18
+ const factory = loaders.get(platform);
19
+ return factory ? factory() : null;
20
+ }
21
+ /**
22
+ * List all registered loaders.
23
+ */
24
+ export function listLoaders() {
25
+ return [...loaders.keys()];
26
+ }
27
+ /**
28
+ * Check if a loader exists for a platform.
29
+ */
30
+ export function hasLoader(platform) {
31
+ return loaders.has(platform);
32
+ }
33
+ // ─── Register Built-in Loaders ───────────────────────────────
34
+ // Claude loader will be registered in #25
35
+ // registerLoader('claude', () => new ClaudeLoader());
36
+ // ChatGPT loader will be registered in #30
37
+ // registerLoader('chatgpt', () => new ChatGPTLoader());
38
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../../src/migrate/loaders/registry.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,MAAM,OAAO,GAAG,IAAI,GAAG,EAA0B,CAAC;AAElD;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,QAAkB,EAAE,OAAqB;IACtE,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;AACjC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,SAAS,CAAC,QAAkB;IAC1C,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACtC,OAAO,OAAO,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AACpC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,WAAW;IACzB,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;AAC7B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,SAAS,CAAC,QAAkB;IAC1C,OAAO,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AAC/B,CAAC;AAED,gEAAgE;AAEhE,0CAA0C;AAC1C,sDAAsD;AAEtD,2CAA2C;AAC3C,wDAAwD"}
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Migration Orchestrator
3
+ *
4
+ * Coordinates the three-phase migration process:
5
+ * Extract → Transform → Load
6
+ *
7
+ * Features:
8
+ * - Phase checkpoint/resume capability
9
+ * - Progress tracking
10
+ * - Error recovery
11
+ * - Rollback support
12
+ */
13
+ import type { Platform, MigrationBundle, MigrationState, MigrationPhase, MigrationOptions, CompatibilityReport, LoadResult } from './types.js';
14
+ export type MigrationEventType = 'phase:start' | 'phase:complete' | 'phase:error' | 'progress' | 'checkpoint' | 'complete' | 'error';
15
+ export interface MigrationEvent {
16
+ type: MigrationEventType;
17
+ phase?: MigrationPhase;
18
+ progress?: number;
19
+ message?: string;
20
+ error?: Error;
21
+ data?: unknown;
22
+ }
23
+ export type MigrationEventHandler = (event: MigrationEvent) => void;
24
+ export declare class MigrationOrchestrator {
25
+ private state;
26
+ private bundle;
27
+ private eventHandlers;
28
+ private workDir;
29
+ constructor(source: Platform, target: Platform, options?: MigrationOptions);
30
+ /**
31
+ * Run the full migration pipeline.
32
+ */
33
+ run(): Promise<LoadResult>;
34
+ /**
35
+ * Run only the extract phase (useful for debugging/inspection).
36
+ */
37
+ extract(): Promise<MigrationBundle>;
38
+ /**
39
+ * Generate compatibility report without running full migration.
40
+ */
41
+ analyze(): Promise<CompatibilityReport>;
42
+ /**
43
+ * Resume a failed or interrupted migration.
44
+ */
45
+ static resume(migrationId: string, workDir?: string): Promise<MigrationOrchestrator>;
46
+ /**
47
+ * Resume and continue the migration from where it left off.
48
+ */
49
+ continue(): Promise<LoadResult>;
50
+ /**
51
+ * Clean up migration artifacts.
52
+ */
53
+ cleanup(): Promise<void>;
54
+ /**
55
+ * Subscribe to migration events.
56
+ */
57
+ on(handler: MigrationEventHandler): () => void;
58
+ /**
59
+ * Get current migration state.
60
+ */
61
+ getState(): MigrationState;
62
+ /**
63
+ * Get the migration bundle (if extracted).
64
+ */
65
+ getBundle(): MigrationBundle | null;
66
+ private runExtractPhase;
67
+ private runTransformPhase;
68
+ private runLoadPhase;
69
+ private generateId;
70
+ private ensureWorkDir;
71
+ private setPhase;
72
+ private saveState;
73
+ private saveCheckpoint;
74
+ private loadCheckpoint;
75
+ private emit;
76
+ }
77
+ //# sourceMappingURL=orchestrator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orchestrator.d.ts","sourceRoot":"","sources":["../../src/migrate/orchestrator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAQH,OAAO,KAAK,EACV,QAAQ,EACR,eAAe,EACf,cAAc,EACd,cAAc,EAEd,gBAAgB,EAChB,mBAAmB,EAInB,UAAU,EACX,MAAM,YAAY,CAAC;AAQpB,MAAM,MAAM,kBAAkB,GAC1B,aAAa,GACb,gBAAgB,GAChB,aAAa,GACb,UAAU,GACV,YAAY,GACZ,UAAU,GACV,OAAO,CAAC;AAEZ,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,kBAAkB,CAAC;IACzB,KAAK,CAAC,EAAE,cAAc,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,MAAM,qBAAqB,GAAG,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;AAIpE,qBAAa,qBAAqB;IAChC,OAAO,CAAC,KAAK,CAAiB;IAC9B,OAAO,CAAC,MAAM,CAAgC;IAC9C,OAAO,CAAC,aAAa,CAA+B;IACpD,OAAO,CAAC,OAAO,CAAS;gBAGtB,MAAM,EAAE,QAAQ,EAChB,MAAM,EAAE,QAAQ,EAChB,OAAO,GAAE,gBAAqB;IAoBhC;;OAEG;IACG,GAAG,IAAI,OAAO,CAAC,UAAU,CAAC;IA+BhC;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,eAAe,CAAC;IAMzC;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,mBAAmB,CAAC;IAkB7C;;OAEG;WACU,MAAM,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,CAAC;IAwB1F;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC,UAAU,CAAC;IA+BrC;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAM9B;;OAEG;IACH,EAAE,CAAC,OAAO,EAAE,qBAAqB,GAAG,MAAM,IAAI;IAQ9C;;OAEG;IACH,QAAQ,IAAI,cAAc;IAI1B;;OAEG;IACH,SAAS,IAAI,eAAe,GAAG,IAAI;YAMrB,eAAe;YAgCf,iBAAiB;YA+BjB,YAAY;IAqD1B,OAAO,CAAC,UAAU;YAIJ,aAAa;IAI3B,OAAO,CAAC,QAAQ;YAKF,SAAS;YAKT,cAAc;YA4Bd,cAAc;IAc5B,OAAO,CAAC,IAAI;CASb"}
@@ -0,0 +1,322 @@
1
+ /**
2
+ * Migration Orchestrator
3
+ *
4
+ * Coordinates the three-phase migration process:
5
+ * Extract → Transform → Load
6
+ *
7
+ * Features:
8
+ * - Phase checkpoint/resume capability
9
+ * - Progress tracking
10
+ * - Error recovery
11
+ * - Rollback support
12
+ */
13
+ import { randomBytes } from 'node:crypto';
14
+ import { mkdir, writeFile, readFile, rm } from 'node:fs/promises';
15
+ import { existsSync } from 'node:fs';
16
+ import { join } from 'node:path';
17
+ import { createHash } from 'node:crypto';
18
+ import { getExtractor } from './extractors/registry.js';
19
+ import { getTransformer } from './transformers/registry.js';
20
+ import { getLoader } from './loaders/registry.js';
21
+ // ─── Orchestrator ────────────────────────────────────────────
22
+ export class MigrationOrchestrator {
23
+ state;
24
+ bundle = null;
25
+ eventHandlers = [];
26
+ workDir;
27
+ constructor(source, target, options = {}) {
28
+ const id = this.generateId();
29
+ this.workDir = options.workDir ?? join(process.cwd(), '.savestate', 'migrations', id);
30
+ this.state = {
31
+ id,
32
+ phase: 'pending',
33
+ source,
34
+ target,
35
+ startedAt: new Date().toISOString(),
36
+ phaseStartedAt: new Date().toISOString(),
37
+ checkpoints: [],
38
+ progress: 0,
39
+ options,
40
+ };
41
+ }
42
+ // ─── Public API ────────────────────────────────────────────
43
+ /**
44
+ * Run the full migration pipeline.
45
+ */
46
+ async run() {
47
+ await this.ensureWorkDir();
48
+ try {
49
+ // Phase 1: Extract
50
+ await this.runExtractPhase();
51
+ // Phase 2: Transform
52
+ await this.runTransformPhase();
53
+ // Phase 3: Load
54
+ const result = await this.runLoadPhase();
55
+ this.state.phase = 'complete';
56
+ this.state.completedAt = new Date().toISOString();
57
+ await this.saveState();
58
+ this.emit({ type: 'complete', data: result });
59
+ return result;
60
+ }
61
+ catch (error) {
62
+ this.state.phase = 'failed';
63
+ this.state.error = error instanceof Error ? error.message : String(error);
64
+ await this.saveState();
65
+ this.emit({ type: 'error', error: error instanceof Error ? error : new Error(String(error)) });
66
+ throw error;
67
+ }
68
+ }
69
+ /**
70
+ * Run only the extract phase (useful for debugging/inspection).
71
+ */
72
+ async extract() {
73
+ await this.ensureWorkDir();
74
+ await this.runExtractPhase();
75
+ return this.bundle;
76
+ }
77
+ /**
78
+ * Generate compatibility report without running full migration.
79
+ */
80
+ async analyze() {
81
+ await this.ensureWorkDir();
82
+ // Extract first if we don't have a bundle
83
+ if (!this.bundle) {
84
+ await this.runExtractPhase();
85
+ }
86
+ const transformer = getTransformer(this.state.source, this.state.target);
87
+ if (!transformer) {
88
+ throw new Error(`No transformer available for ${this.state.source} → ${this.state.target}`);
89
+ }
90
+ return transformer.analyze(this.bundle);
91
+ }
92
+ /**
93
+ * Resume a failed or interrupted migration.
94
+ */
95
+ static async resume(migrationId, workDir) {
96
+ const baseDir = workDir ?? join(process.cwd(), '.savestate', 'migrations', migrationId);
97
+ const statePath = join(baseDir, 'state.json');
98
+ if (!existsSync(statePath)) {
99
+ throw new Error(`Migration ${migrationId} not found at ${baseDir}`);
100
+ }
101
+ const stateJson = await readFile(statePath, 'utf-8');
102
+ const state = JSON.parse(stateJson);
103
+ const orchestrator = new MigrationOrchestrator(state.source, state.target, state.options);
104
+ orchestrator.state = state;
105
+ orchestrator.workDir = baseDir;
106
+ // Load bundle if we have one
107
+ if (state.bundlePath && existsSync(state.bundlePath)) {
108
+ const bundleJson = await readFile(state.bundlePath, 'utf-8');
109
+ orchestrator.bundle = JSON.parse(bundleJson);
110
+ }
111
+ return orchestrator;
112
+ }
113
+ /**
114
+ * Resume and continue the migration from where it left off.
115
+ */
116
+ async continue() {
117
+ const lastCheckpoint = this.state.checkpoints[this.state.checkpoints.length - 1];
118
+ if (!lastCheckpoint) {
119
+ // No checkpoint, start from beginning
120
+ return this.run();
121
+ }
122
+ // Resume from the phase after the last checkpoint
123
+ switch (lastCheckpoint.phase) {
124
+ case 'extracting':
125
+ // Extract completed, continue with transform
126
+ await this.loadCheckpoint(lastCheckpoint);
127
+ await this.runTransformPhase();
128
+ return this.runLoadPhase();
129
+ case 'transforming':
130
+ // Transform completed, continue with load
131
+ await this.loadCheckpoint(lastCheckpoint);
132
+ return this.runLoadPhase();
133
+ case 'loading':
134
+ // Load was in progress, need to restart it
135
+ await this.loadCheckpoint(lastCheckpoint);
136
+ return this.runLoadPhase();
137
+ default:
138
+ return this.run();
139
+ }
140
+ }
141
+ /**
142
+ * Clean up migration artifacts.
143
+ */
144
+ async cleanup() {
145
+ if (existsSync(this.workDir)) {
146
+ await rm(this.workDir, { recursive: true, force: true });
147
+ }
148
+ }
149
+ /**
150
+ * Subscribe to migration events.
151
+ */
152
+ on(handler) {
153
+ this.eventHandlers.push(handler);
154
+ return () => {
155
+ const index = this.eventHandlers.indexOf(handler);
156
+ if (index >= 0)
157
+ this.eventHandlers.splice(index, 1);
158
+ };
159
+ }
160
+ /**
161
+ * Get current migration state.
162
+ */
163
+ getState() {
164
+ return { ...this.state };
165
+ }
166
+ /**
167
+ * Get the migration bundle (if extracted).
168
+ */
169
+ getBundle() {
170
+ return this.bundle;
171
+ }
172
+ // ─── Phase Runners ─────────────────────────────────────────
173
+ async runExtractPhase() {
174
+ this.setPhase('extracting');
175
+ this.emit({ type: 'phase:start', phase: 'extracting', message: 'Starting extraction...' });
176
+ const extractor = getExtractor(this.state.source);
177
+ if (!extractor) {
178
+ throw new Error(`No extractor available for ${this.state.source}`);
179
+ }
180
+ const canExtract = await extractor.canExtract();
181
+ if (!canExtract) {
182
+ throw new Error(`Cannot extract from ${this.state.source} - check authentication`);
183
+ }
184
+ this.bundle = await extractor.extract({
185
+ include: this.state.options.include,
186
+ workDir: this.workDir,
187
+ onProgress: (progress, message) => {
188
+ this.state.progress = progress * 0.33; // Extract is 0-33%
189
+ this.emit({ type: 'progress', progress: this.state.progress, message });
190
+ },
191
+ });
192
+ // Save bundle to disk
193
+ const bundlePath = join(this.workDir, 'bundle.json');
194
+ await writeFile(bundlePath, JSON.stringify(this.bundle, null, 2));
195
+ this.state.bundlePath = bundlePath;
196
+ await this.saveCheckpoint('extracting');
197
+ this.emit({ type: 'phase:complete', phase: 'extracting', message: 'Extraction complete' });
198
+ }
199
+ async runTransformPhase() {
200
+ if (!this.bundle) {
201
+ throw new Error('No bundle to transform - run extract phase first');
202
+ }
203
+ this.setPhase('transforming');
204
+ this.emit({ type: 'phase:start', phase: 'transforming', message: 'Starting transformation...' });
205
+ const transformer = getTransformer(this.state.source, this.state.target);
206
+ if (!transformer) {
207
+ throw new Error(`No transformer available for ${this.state.source} → ${this.state.target}`);
208
+ }
209
+ this.bundle = await transformer.transform(this.bundle, {
210
+ overflowStrategy: 'summarize',
211
+ onProgress: (progress, message) => {
212
+ this.state.progress = 33 + progress * 0.34; // Transform is 33-67%
213
+ this.emit({ type: 'progress', progress: this.state.progress, message });
214
+ },
215
+ });
216
+ // Update bundle on disk
217
+ const bundlePath = join(this.workDir, 'bundle.json');
218
+ await writeFile(bundlePath, JSON.stringify(this.bundle, null, 2));
219
+ await this.saveCheckpoint('transforming');
220
+ this.emit({ type: 'phase:complete', phase: 'transforming', message: 'Transformation complete' });
221
+ }
222
+ async runLoadPhase() {
223
+ if (!this.bundle) {
224
+ throw new Error('No bundle to load - run extract and transform phases first');
225
+ }
226
+ this.setPhase('loading');
227
+ this.emit({ type: 'phase:start', phase: 'loading', message: 'Starting load...' });
228
+ // Handle dry run
229
+ if (this.state.options.dryRun) {
230
+ const dryRunResult = {
231
+ success: true,
232
+ loaded: {
233
+ instructions: !!this.bundle.contents.instructions,
234
+ memories: this.bundle.contents.memories?.count ?? 0,
235
+ files: this.bundle.contents.files?.count ?? 0,
236
+ customBots: this.bundle.contents.customBots?.count ?? 0,
237
+ },
238
+ warnings: ['Dry run - no changes made'],
239
+ errors: [],
240
+ };
241
+ this.emit({ type: 'phase:complete', phase: 'loading', message: 'Dry run complete' });
242
+ return dryRunResult;
243
+ }
244
+ const loader = getLoader(this.state.target);
245
+ if (!loader) {
246
+ throw new Error(`No loader available for ${this.state.target}`);
247
+ }
248
+ const canLoad = await loader.canLoad();
249
+ if (!canLoad) {
250
+ throw new Error(`Cannot load to ${this.state.target} - check authentication`);
251
+ }
252
+ const result = await loader.load(this.bundle, {
253
+ dryRun: false,
254
+ projectName: `Migrated from ${this.state.source} (${new Date().toISOString().split('T')[0]})`,
255
+ onProgress: (progress, message) => {
256
+ this.state.progress = 67 + progress * 0.33; // Load is 67-100%
257
+ this.emit({ type: 'progress', progress: this.state.progress, message });
258
+ },
259
+ });
260
+ await this.saveCheckpoint('loading');
261
+ this.emit({ type: 'phase:complete', phase: 'loading', message: 'Load complete', data: result });
262
+ return result;
263
+ }
264
+ // ─── Helpers ───────────────────────────────────────────────
265
+ generateId() {
266
+ return `mig_${randomBytes(8).toString('hex')}`;
267
+ }
268
+ async ensureWorkDir() {
269
+ await mkdir(this.workDir, { recursive: true });
270
+ }
271
+ setPhase(phase) {
272
+ this.state.phase = phase;
273
+ this.state.phaseStartedAt = new Date().toISOString();
274
+ }
275
+ async saveState() {
276
+ const statePath = join(this.workDir, 'state.json');
277
+ await writeFile(statePath, JSON.stringify(this.state, null, 2));
278
+ }
279
+ async saveCheckpoint(phase) {
280
+ const checkpointId = `checkpoint_${phase}_${Date.now()}`;
281
+ const checkpointPath = join(this.workDir, `${checkpointId}.json`);
282
+ const checkpointData = {
283
+ phase,
284
+ bundle: this.bundle,
285
+ state: this.state,
286
+ };
287
+ const dataStr = JSON.stringify(checkpointData);
288
+ await writeFile(checkpointPath, dataStr);
289
+ const checksum = createHash('sha256').update(dataStr).digest('hex');
290
+ const checkpoint = {
291
+ phase,
292
+ timestamp: new Date().toISOString(),
293
+ dataPath: checkpointPath,
294
+ checksum,
295
+ };
296
+ this.state.checkpoints.push(checkpoint);
297
+ await this.saveState();
298
+ this.emit({ type: 'checkpoint', phase, message: `Checkpoint saved: ${checkpointId}` });
299
+ }
300
+ async loadCheckpoint(checkpoint) {
301
+ const dataStr = await readFile(checkpoint.dataPath, 'utf-8');
302
+ // Verify checksum
303
+ const actualChecksum = createHash('sha256').update(dataStr).digest('hex');
304
+ if (actualChecksum !== checkpoint.checksum) {
305
+ throw new Error(`Checkpoint corrupted: ${checkpoint.dataPath}`);
306
+ }
307
+ const data = JSON.parse(dataStr);
308
+ this.bundle = data.bundle;
309
+ // Don't overwrite current state - we want to keep progress info
310
+ }
311
+ emit(event) {
312
+ for (const handler of this.eventHandlers) {
313
+ try {
314
+ handler(event);
315
+ }
316
+ catch {
317
+ // Don't let handler errors break the migration
318
+ }
319
+ }
320
+ }
321
+ }
322
+ //# sourceMappingURL=orchestrator.js.map