agentic-qe 2.8.0 → 2.8.1

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 (142) hide show
  1. package/CHANGELOG.md +105 -0
  2. package/README.md +1 -1
  3. package/dist/agents/BaseAgent.d.ts +128 -0
  4. package/dist/agents/BaseAgent.d.ts.map +1 -1
  5. package/dist/agents/BaseAgent.js +256 -0
  6. package/dist/agents/BaseAgent.js.map +1 -1
  7. package/dist/cli/commands/supabase/index.d.ts +20 -0
  8. package/dist/cli/commands/supabase/index.d.ts.map +1 -0
  9. package/dist/cli/commands/supabase/index.js +632 -0
  10. package/dist/cli/commands/supabase/index.js.map +1 -0
  11. package/dist/cli/index.js +3 -0
  12. package/dist/cli/index.js.map +1 -1
  13. package/dist/core/memory/HNSWVectorMemory.js +1 -1
  14. package/dist/mcp/handlers/NewDomainToolsHandler.d.ts +8 -8
  15. package/dist/mcp/handlers/NewDomainToolsHandler.d.ts.map +1 -1
  16. package/dist/mcp/handlers/NewDomainToolsHandler.js.map +1 -1
  17. package/dist/mcp/handlers/ruvector/RuVectorHandler.d.ts +54 -0
  18. package/dist/mcp/handlers/ruvector/RuVectorHandler.d.ts.map +1 -0
  19. package/dist/mcp/handlers/ruvector/RuVectorHandler.js +325 -0
  20. package/dist/mcp/handlers/ruvector/RuVectorHandler.js.map +1 -0
  21. package/dist/mcp/handlers/ruvector/index.d.ts +5 -0
  22. package/dist/mcp/handlers/ruvector/index.d.ts.map +1 -0
  23. package/dist/mcp/handlers/ruvector/index.js +9 -0
  24. package/dist/mcp/handlers/ruvector/index.js.map +1 -0
  25. package/dist/mcp/server-instructions.d.ts +1 -1
  26. package/dist/mcp/server-instructions.js +1 -1
  27. package/dist/mcp/server.d.ts.map +1 -1
  28. package/dist/mcp/server.js +100 -22
  29. package/dist/mcp/server.js.map +1 -1
  30. package/dist/nervous-system/adapters/BTSPAdapter.d.ts +342 -0
  31. package/dist/nervous-system/adapters/BTSPAdapter.d.ts.map +1 -0
  32. package/dist/nervous-system/adapters/BTSPAdapter.js +494 -0
  33. package/dist/nervous-system/adapters/BTSPAdapter.js.map +1 -0
  34. package/dist/nervous-system/adapters/CircadianController.d.ts +560 -0
  35. package/dist/nervous-system/adapters/CircadianController.d.ts.map +1 -0
  36. package/dist/nervous-system/adapters/CircadianController.js +882 -0
  37. package/dist/nervous-system/adapters/CircadianController.js.map +1 -0
  38. package/dist/nervous-system/adapters/GlobalWorkspaceAdapter.d.ts +337 -0
  39. package/dist/nervous-system/adapters/GlobalWorkspaceAdapter.d.ts.map +1 -0
  40. package/dist/nervous-system/adapters/GlobalWorkspaceAdapter.js +532 -0
  41. package/dist/nervous-system/adapters/GlobalWorkspaceAdapter.js.map +1 -0
  42. package/dist/nervous-system/adapters/HdcMemoryAdapter.d.ts +444 -0
  43. package/dist/nervous-system/adapters/HdcMemoryAdapter.d.ts.map +1 -0
  44. package/dist/nervous-system/adapters/HdcMemoryAdapter.js +715 -0
  45. package/dist/nervous-system/adapters/HdcMemoryAdapter.js.map +1 -0
  46. package/dist/nervous-system/adapters/ReflexLayer.d.ts +231 -0
  47. package/dist/nervous-system/adapters/ReflexLayer.d.ts.map +1 -0
  48. package/dist/nervous-system/adapters/ReflexLayer.js +309 -0
  49. package/dist/nervous-system/adapters/ReflexLayer.js.map +1 -0
  50. package/dist/nervous-system/index.d.ts +25 -0
  51. package/dist/nervous-system/index.d.ts.map +1 -0
  52. package/dist/nervous-system/index.js +80 -0
  53. package/dist/nervous-system/index.js.map +1 -0
  54. package/dist/nervous-system/integration/BTSPLearningEngine.d.ts +266 -0
  55. package/dist/nervous-system/integration/BTSPLearningEngine.d.ts.map +1 -0
  56. package/dist/nervous-system/integration/BTSPLearningEngine.js +587 -0
  57. package/dist/nervous-system/integration/BTSPLearningEngine.js.map +1 -0
  58. package/dist/nervous-system/integration/CircadianAgent.d.ts +389 -0
  59. package/dist/nervous-system/integration/CircadianAgent.d.ts.map +1 -0
  60. package/dist/nervous-system/integration/CircadianAgent.js +696 -0
  61. package/dist/nervous-system/integration/CircadianAgent.js.map +1 -0
  62. package/dist/nervous-system/integration/HybridPatternStore.d.ts +244 -0
  63. package/dist/nervous-system/integration/HybridPatternStore.d.ts.map +1 -0
  64. package/dist/nervous-system/integration/HybridPatternStore.js +622 -0
  65. package/dist/nervous-system/integration/HybridPatternStore.js.map +1 -0
  66. package/dist/nervous-system/integration/NervousSystemEnhancement.d.ts +459 -0
  67. package/dist/nervous-system/integration/NervousSystemEnhancement.d.ts.map +1 -0
  68. package/dist/nervous-system/integration/NervousSystemEnhancement.js +921 -0
  69. package/dist/nervous-system/integration/NervousSystemEnhancement.js.map +1 -0
  70. package/dist/nervous-system/integration/WorkspaceAgent.d.ts +398 -0
  71. package/dist/nervous-system/integration/WorkspaceAgent.d.ts.map +1 -0
  72. package/dist/nervous-system/integration/WorkspaceAgent.js +722 -0
  73. package/dist/nervous-system/integration/WorkspaceAgent.js.map +1 -0
  74. package/dist/nervous-system/integration/index.d.ts +22 -0
  75. package/dist/nervous-system/integration/index.d.ts.map +1 -0
  76. package/dist/nervous-system/integration/index.js +44 -0
  77. package/dist/nervous-system/integration/index.js.map +1 -0
  78. package/dist/nervous-system/persistence/BTSPSerializer.d.ts +96 -0
  79. package/dist/nervous-system/persistence/BTSPSerializer.d.ts.map +1 -0
  80. package/dist/nervous-system/persistence/BTSPSerializer.js +223 -0
  81. package/dist/nervous-system/persistence/BTSPSerializer.js.map +1 -0
  82. package/dist/nervous-system/persistence/CircadianSerializer.d.ts +90 -0
  83. package/dist/nervous-system/persistence/CircadianSerializer.d.ts.map +1 -0
  84. package/dist/nervous-system/persistence/CircadianSerializer.js +239 -0
  85. package/dist/nervous-system/persistence/CircadianSerializer.js.map +1 -0
  86. package/dist/nervous-system/persistence/HdcSerializer.d.ts +100 -0
  87. package/dist/nervous-system/persistence/HdcSerializer.d.ts.map +1 -0
  88. package/dist/nervous-system/persistence/HdcSerializer.js +259 -0
  89. package/dist/nervous-system/persistence/HdcSerializer.js.map +1 -0
  90. package/dist/nervous-system/persistence/INervousSystemStore.d.ts +208 -0
  91. package/dist/nervous-system/persistence/INervousSystemStore.d.ts.map +1 -0
  92. package/dist/nervous-system/persistence/INervousSystemStore.js +11 -0
  93. package/dist/nervous-system/persistence/INervousSystemStore.js.map +1 -0
  94. package/dist/nervous-system/persistence/NervousSystemPersistenceManager.d.ts +187 -0
  95. package/dist/nervous-system/persistence/NervousSystemPersistenceManager.d.ts.map +1 -0
  96. package/dist/nervous-system/persistence/NervousSystemPersistenceManager.js +411 -0
  97. package/dist/nervous-system/persistence/NervousSystemPersistenceManager.js.map +1 -0
  98. package/dist/nervous-system/persistence/SQLiteNervousSystemStore.d.ts +98 -0
  99. package/dist/nervous-system/persistence/SQLiteNervousSystemStore.d.ts.map +1 -0
  100. package/dist/nervous-system/persistence/SQLiteNervousSystemStore.js +510 -0
  101. package/dist/nervous-system/persistence/SQLiteNervousSystemStore.js.map +1 -0
  102. package/dist/nervous-system/persistence/index.d.ts +22 -0
  103. package/dist/nervous-system/persistence/index.d.ts.map +1 -0
  104. package/dist/nervous-system/persistence/index.js +45 -0
  105. package/dist/nervous-system/persistence/index.js.map +1 -0
  106. package/dist/nervous-system/wasm-loader.d.ts +52 -0
  107. package/dist/nervous-system/wasm-loader.d.ts.map +1 -0
  108. package/dist/nervous-system/wasm-loader.js +188 -0
  109. package/dist/nervous-system/wasm-loader.js.map +1 -0
  110. package/dist/persistence/HybridPersistenceProvider.d.ts +184 -0
  111. package/dist/persistence/HybridPersistenceProvider.d.ts.map +1 -0
  112. package/dist/persistence/HybridPersistenceProvider.js +1086 -0
  113. package/dist/persistence/HybridPersistenceProvider.js.map +1 -0
  114. package/dist/persistence/IPersistenceProvider.d.ts +657 -0
  115. package/dist/persistence/IPersistenceProvider.d.ts.map +1 -0
  116. package/dist/persistence/IPersistenceProvider.js +11 -0
  117. package/dist/persistence/IPersistenceProvider.js.map +1 -0
  118. package/dist/persistence/SupabaseConfig.d.ts +176 -0
  119. package/dist/persistence/SupabaseConfig.d.ts.map +1 -0
  120. package/dist/persistence/SupabaseConfig.js +277 -0
  121. package/dist/persistence/SupabaseConfig.js.map +1 -0
  122. package/dist/persistence/SupabasePersistenceProvider.d.ts +143 -0
  123. package/dist/persistence/SupabasePersistenceProvider.d.ts.map +1 -0
  124. package/dist/persistence/SupabasePersistenceProvider.js +955 -0
  125. package/dist/persistence/SupabasePersistenceProvider.js.map +1 -0
  126. package/dist/persistence/adapters/CodeIntelligenceSyncAdapter.d.ts +213 -0
  127. package/dist/persistence/adapters/CodeIntelligenceSyncAdapter.d.ts.map +1 -0
  128. package/dist/persistence/adapters/CodeIntelligenceSyncAdapter.js +468 -0
  129. package/dist/persistence/adapters/CodeIntelligenceSyncAdapter.js.map +1 -0
  130. package/dist/persistence/adapters/MemorySyncAdapter.d.ts +115 -0
  131. package/dist/persistence/adapters/MemorySyncAdapter.d.ts.map +1 -0
  132. package/dist/persistence/adapters/MemorySyncAdapter.js +291 -0
  133. package/dist/persistence/adapters/MemorySyncAdapter.js.map +1 -0
  134. package/dist/persistence/adapters/index.d.ts +11 -0
  135. package/dist/persistence/adapters/index.d.ts.map +1 -0
  136. package/dist/persistence/adapters/index.js +20 -0
  137. package/dist/persistence/adapters/index.js.map +1 -0
  138. package/dist/persistence/index.d.ts +14 -0
  139. package/dist/persistence/index.d.ts.map +1 -1
  140. package/dist/persistence/index.js +36 -1
  141. package/dist/persistence/index.js.map +1 -1
  142. package/package.json +3 -1
@@ -0,0 +1,1086 @@
1
+ "use strict";
2
+ /**
3
+ * Hybrid Persistence Provider
4
+ *
5
+ * Local-first persistence with cloud sync capabilities.
6
+ * Uses SQLite for immediate local storage and syncs to Supabase in the background.
7
+ *
8
+ * Features:
9
+ * - Immediate local writes (low latency)
10
+ * - Background sync to cloud
11
+ * - Conflict resolution strategies
12
+ * - Offline support with sync on reconnect
13
+ * - Queue-based sync for reliability
14
+ *
15
+ * @module persistence/HybridPersistenceProvider
16
+ */
17
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
18
+ if (k2 === undefined) k2 = k;
19
+ var desc = Object.getOwnPropertyDescriptor(m, k);
20
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
21
+ desc = { enumerable: true, get: function() { return m[k]; } };
22
+ }
23
+ Object.defineProperty(o, k2, desc);
24
+ }) : (function(o, m, k, k2) {
25
+ if (k2 === undefined) k2 = k;
26
+ o[k2] = m[k];
27
+ }));
28
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
29
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
30
+ }) : function(o, v) {
31
+ o["default"] = v;
32
+ });
33
+ var __importStar = (this && this.__importStar) || (function () {
34
+ var ownKeys = function(o) {
35
+ ownKeys = Object.getOwnPropertyNames || function (o) {
36
+ var ar = [];
37
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
38
+ return ar;
39
+ };
40
+ return ownKeys(o);
41
+ };
42
+ return function (mod) {
43
+ if (mod && mod.__esModule) return mod;
44
+ var result = {};
45
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
46
+ __setModuleDefault(result, mod);
47
+ return result;
48
+ };
49
+ })();
50
+ Object.defineProperty(exports, "__esModule", { value: true });
51
+ exports.HybridPersistenceProvider = void 0;
52
+ exports.createHybridPersistenceProvider = createHybridPersistenceProvider;
53
+ const events_1 = require("events");
54
+ const SupabaseConfig_js_1 = require("./SupabaseConfig.js");
55
+ const SupabasePersistenceProvider_js_1 = require("./SupabasePersistenceProvider.js");
56
+ const SQLiteNervousSystemStore_js_1 = require("../nervous-system/persistence/SQLiteNervousSystemStore.js");
57
+ // ============================================
58
+ // Provider Implementation
59
+ // ============================================
60
+ /**
61
+ * Hybrid persistence provider with local-first approach
62
+ *
63
+ * @example
64
+ * ```typescript
65
+ * const provider = new HybridPersistenceProvider({
66
+ * localDbPath: './data/aqe.db',
67
+ * supabaseConfig: {
68
+ * connection: {
69
+ * url: 'https://xxx.supabase.co',
70
+ * anonKey: 'xxx',
71
+ * },
72
+ * },
73
+ * });
74
+ *
75
+ * await provider.initialize();
76
+ *
77
+ * // Writes go to local first, then sync to cloud
78
+ * await provider.storeExperience(experience);
79
+ *
80
+ * // Force sync
81
+ * const result = await provider.syncToCloud();
82
+ * console.log(`Synced ${result.uploaded} items`);
83
+ * ```
84
+ */
85
+ class HybridPersistenceProvider extends events_1.EventEmitter {
86
+ constructor(config) {
87
+ super();
88
+ // Local store
89
+ this.localStore = null;
90
+ // Cloud provider (optional)
91
+ this.cloudProvider = null;
92
+ // Sync queue
93
+ this.syncQueue = [];
94
+ this.syncTimer = null;
95
+ // State
96
+ this.initialized = false;
97
+ this.syncStatus = {
98
+ lastSyncTime: null,
99
+ pendingUploads: 0,
100
+ pendingDownloads: 0,
101
+ conflicts: 0,
102
+ isOnline: false,
103
+ isSyncing: false,
104
+ };
105
+ this.config = {
106
+ localDbPath: config.localDbPath,
107
+ supabaseConfig: config.supabaseConfig ?? {},
108
+ syncConfig: config.syncConfig ?? {},
109
+ autoSync: config.autoSync ?? true,
110
+ maxQueueSize: config.maxQueueSize ?? 100,
111
+ };
112
+ this.syncConfig = {
113
+ ...SupabaseConfig_js_1.DEFAULT_SYNC_CONFIG,
114
+ ...config.syncConfig,
115
+ };
116
+ }
117
+ // ============================================
118
+ // Lifecycle
119
+ // ============================================
120
+ async initialize() {
121
+ if (this.initialized) {
122
+ return;
123
+ }
124
+ // Initialize local store
125
+ this.localStore = (0, SQLiteNervousSystemStore_js_1.createSQLiteNervousSystemStore)({
126
+ dbPath: this.config.localDbPath,
127
+ });
128
+ await this.localStore.initialize();
129
+ // Initialize cloud provider if configured
130
+ if ((0, SupabaseConfig_js_1.isSupabaseConfigured)() || this.config.supabaseConfig?.connection) {
131
+ try {
132
+ this.cloudProvider = new SupabasePersistenceProvider_js_1.SupabasePersistenceProvider(this.config.supabaseConfig);
133
+ await this.cloudProvider.initialize();
134
+ this.syncStatus.isOnline = true;
135
+ this.emit('online');
136
+ }
137
+ catch (error) {
138
+ console.warn('[HybridProvider] Cloud provider failed to initialize:', error);
139
+ this.syncStatus.isOnline = false;
140
+ }
141
+ }
142
+ // Start background sync if enabled
143
+ if (this.config.autoSync && this.syncConfig.backgroundSync) {
144
+ this.startBackgroundSync();
145
+ }
146
+ this.initialized = true;
147
+ this.emit('initialized');
148
+ }
149
+ async shutdown() {
150
+ // Stop background sync
151
+ this.stopBackgroundSync();
152
+ // Flush pending sync queue
153
+ if (this.syncQueue.length > 0 && this.syncStatus.isOnline) {
154
+ try {
155
+ await this.syncToCloud();
156
+ }
157
+ catch (error) {
158
+ console.warn('[HybridProvider] Failed to sync before shutdown:', error);
159
+ }
160
+ }
161
+ // Shutdown providers
162
+ if (this.cloudProvider) {
163
+ await this.cloudProvider.shutdown();
164
+ this.cloudProvider = null;
165
+ }
166
+ if (this.localStore) {
167
+ await this.localStore.shutdown();
168
+ this.localStore = null;
169
+ }
170
+ this.initialized = false;
171
+ this.emit('shutdown');
172
+ }
173
+ // ============================================
174
+ // Learning Experiences (Local-first)
175
+ // ============================================
176
+ async storeExperience(experience) {
177
+ this.ensureInitialized();
178
+ // Store locally first (immediate)
179
+ // For now, we store in local SQLite using a simple JSON approach
180
+ // In a full implementation, we'd have a proper experiences table
181
+ const key = `experience:${experience.id}`;
182
+ const data = JSON.stringify(experience);
183
+ // Use the nervous system state storage as a generic key-value store
184
+ await this.localStore.saveCircadianState(key, {
185
+ version: 1,
186
+ state: { data },
187
+ metrics: {},
188
+ lastPhaseChange: 0,
189
+ serializedAt: Date.now(),
190
+ });
191
+ // Queue for cloud sync
192
+ this.queueSync('insert', 'experiences', experience.id, experience);
193
+ this.emit('experience:stored', experience.id);
194
+ }
195
+ async queryExperiences(query) {
196
+ this.ensureInitialized();
197
+ // Try cloud first if online for most up-to-date data
198
+ if (this.syncStatus.isOnline && this.cloudProvider) {
199
+ try {
200
+ return await this.cloudProvider.queryExperiences(query);
201
+ }
202
+ catch (error) {
203
+ console.warn('[HybridProvider] Cloud query failed, falling back to local:', error);
204
+ }
205
+ }
206
+ // Fall back to local (simplified - would need proper local query implementation)
207
+ // For a full implementation, we'd query the local SQLite database
208
+ return [];
209
+ }
210
+ async searchSimilarExperiences(embedding, limit) {
211
+ this.ensureInitialized();
212
+ // Vector search only available in cloud
213
+ if (this.syncStatus.isOnline && this.cloudProvider) {
214
+ return this.cloudProvider.searchSimilarExperiences(embedding, limit);
215
+ }
216
+ // Local fallback - would need local vector search implementation
217
+ return [];
218
+ }
219
+ // ============================================
220
+ // Patterns (Local-first)
221
+ // ============================================
222
+ async storePattern(pattern) {
223
+ this.ensureInitialized();
224
+ // Store locally
225
+ const key = `pattern:${pattern.id}`;
226
+ const data = JSON.stringify(pattern);
227
+ await this.localStore.saveCircadianState(key, {
228
+ version: 1,
229
+ state: { data },
230
+ metrics: {},
231
+ lastPhaseChange: 0,
232
+ serializedAt: Date.now(),
233
+ });
234
+ // Queue for cloud sync
235
+ this.queueSync('insert', 'patterns', pattern.id, pattern);
236
+ this.emit('pattern:stored', pattern.id);
237
+ }
238
+ async queryPatterns(query) {
239
+ this.ensureInitialized();
240
+ if (this.syncStatus.isOnline && this.cloudProvider) {
241
+ try {
242
+ return await this.cloudProvider.queryPatterns(query);
243
+ }
244
+ catch (error) {
245
+ console.warn('[HybridProvider] Cloud query failed, falling back to local:', error);
246
+ }
247
+ }
248
+ return [];
249
+ }
250
+ async searchSimilarPatterns(embedding, limit) {
251
+ this.ensureInitialized();
252
+ if (this.syncStatus.isOnline && this.cloudProvider) {
253
+ return this.cloudProvider.searchSimilarPatterns(embedding, limit);
254
+ }
255
+ return [];
256
+ }
257
+ // ============================================
258
+ // Nervous System State (Local-first)
259
+ // ============================================
260
+ async saveNervousSystemState(agentId, component, state) {
261
+ this.ensureInitialized();
262
+ // For hybrid provider, delegate to cloud if available for full state handling
263
+ // Local store handles the underlying SQLite persistence
264
+ if (this.syncStatus.isOnline && this.cloudProvider) {
265
+ await this.cloudProvider.saveNervousSystemState(agentId, component, state);
266
+ }
267
+ // Also store locally using a simplified approach
268
+ // We use the circadian state table as a generic JSON store for local cache
269
+ const cacheKey = `ns:${agentId}:${component}`;
270
+ await this.localStore.saveCircadianState(cacheKey, {
271
+ version: 1,
272
+ state: {
273
+ phase: 'Active',
274
+ cycleTime: 0,
275
+ phaseTime: 0,
276
+ energyRemaining: 0,
277
+ cyclesCompleted: 0,
278
+ activeModulation: null,
279
+ timeToNextPhase: 0,
280
+ wasmEnabled: false,
281
+ // Store actual data as JSON in a custom field
282
+ _rawData: state instanceof Uint8Array ? Array.from(state) : state,
283
+ _isBinary: state instanceof Uint8Array,
284
+ },
285
+ metrics: {
286
+ phaseTime: { Active: 0, Dawn: 0, Dusk: 0, Rest: 0 },
287
+ reactionsPerPhase: { Active: 0, Dawn: 0, Dusk: 0, Rest: 0 },
288
+ rejectionsPerPhase: { Active: 0, Dawn: 0, Dusk: 0, Rest: 0 },
289
+ averageDutyFactor: 0,
290
+ totalEnergyConsumed: 0,
291
+ phaseTransitions: 0,
292
+ hysteresisActivations: 0,
293
+ wtaCompetitions: 0,
294
+ },
295
+ lastPhaseChange: Date.now(),
296
+ serializedAt: Date.now(),
297
+ });
298
+ // Queue for cloud sync if not already synced
299
+ if (!this.syncStatus.isOnline) {
300
+ this.queueSync('update', 'nervous_system', `${agentId}:${component}`, {
301
+ agentId,
302
+ component,
303
+ state: state instanceof Uint8Array ? Array.from(state) : state,
304
+ });
305
+ }
306
+ this.emit('nervousSystem:saved', { agentId, component });
307
+ }
308
+ async loadNervousSystemState(agentId, component) {
309
+ this.ensureInitialized();
310
+ // Try cloud first if available
311
+ if (this.syncStatus.isOnline && this.cloudProvider) {
312
+ try {
313
+ const cloudState = await this.cloudProvider.loadNervousSystemState(agentId, component);
314
+ if (cloudState) {
315
+ return cloudState;
316
+ }
317
+ }
318
+ catch (error) {
319
+ console.warn('[HybridProvider] Cloud load failed, trying local:', error);
320
+ }
321
+ }
322
+ // Fall back to local cache
323
+ const cacheKey = `ns:${agentId}:${component}`;
324
+ const cached = await this.localStore.loadCircadianState(cacheKey);
325
+ if (cached && cached.state) {
326
+ const stateData = cached.state;
327
+ const rawData = stateData._rawData;
328
+ const isBinary = stateData._isBinary;
329
+ if (rawData) {
330
+ if (isBinary && Array.isArray(rawData)) {
331
+ return new Uint8Array(rawData);
332
+ }
333
+ return rawData;
334
+ }
335
+ }
336
+ return null;
337
+ }
338
+ async deleteNervousSystemState(agentId) {
339
+ this.ensureInitialized();
340
+ await this.localStore.deleteAllState(agentId);
341
+ // Queue for cloud sync
342
+ this.queueSync('delete', 'nervous_system', agentId);
343
+ this.emit('nervousSystem:deleted', agentId);
344
+ }
345
+ async listAgentsWithState() {
346
+ this.ensureInitialized();
347
+ return this.localStore.listAgents();
348
+ }
349
+ // ============================================
350
+ // Sharing (Delegated to cloud)
351
+ // ============================================
352
+ async shareExperience(experienceId, privacyLevel) {
353
+ this.ensureCloudAvailable();
354
+ await this.cloudProvider.shareExperience(experienceId, privacyLevel);
355
+ }
356
+ async importSharedExperiences(query) {
357
+ this.ensureCloudAvailable();
358
+ return this.cloudProvider.importSharedExperiences(query);
359
+ }
360
+ async sharePattern(patternId, privacyLevel) {
361
+ this.ensureCloudAvailable();
362
+ await this.cloudProvider.sharePattern(patternId, privacyLevel);
363
+ }
364
+ async importSharedPatterns(query) {
365
+ this.ensureCloudAvailable();
366
+ return this.cloudProvider.importSharedPatterns(query);
367
+ }
368
+ // ============================================
369
+ // Memory Entries (Local-first)
370
+ // ============================================
371
+ async storeMemoryEntry(entry) {
372
+ this.ensureInitialized();
373
+ // Store locally first
374
+ const key = `memory:${entry.partition}:${entry.key}`;
375
+ await this.localStore.saveCircadianState(key, {
376
+ version: 1,
377
+ state: { data: JSON.stringify(entry) },
378
+ metrics: {},
379
+ lastPhaseChange: 0,
380
+ serializedAt: Date.now(),
381
+ });
382
+ // Queue for cloud sync
383
+ this.queueSync('insert', 'memory_entries', `${entry.partition}:${entry.key}`, entry);
384
+ this.emit('memory:stored', entry.key);
385
+ }
386
+ async storeMemoryEntries(entries) {
387
+ for (const entry of entries) {
388
+ await this.storeMemoryEntry(entry);
389
+ }
390
+ }
391
+ async getMemoryEntry(key, partition = 'default') {
392
+ this.ensureInitialized();
393
+ // Try cloud first if available
394
+ if (this.syncStatus.isOnline && this.cloudProvider?.getMemoryEntry) {
395
+ try {
396
+ const cloudEntry = await this.cloudProvider.getMemoryEntry(key, partition);
397
+ if (cloudEntry)
398
+ return cloudEntry;
399
+ }
400
+ catch (error) {
401
+ console.warn('[HybridProvider] Cloud getMemoryEntry failed:', error);
402
+ }
403
+ }
404
+ // Fall back to local
405
+ const localKey = `memory:${partition}:${key}`;
406
+ const cached = await this.localStore.loadCircadianState(localKey);
407
+ if (cached?.state) {
408
+ const stateData = cached.state;
409
+ if (stateData.data) {
410
+ return JSON.parse(stateData.data);
411
+ }
412
+ }
413
+ return null;
414
+ }
415
+ async queryMemoryEntries(query) {
416
+ this.ensureInitialized();
417
+ // Query cloud if available (more complete data)
418
+ if (this.syncStatus.isOnline && this.cloudProvider?.queryMemoryEntries) {
419
+ try {
420
+ return await this.cloudProvider.queryMemoryEntries(query);
421
+ }
422
+ catch (error) {
423
+ console.warn('[HybridProvider] Cloud queryMemoryEntries failed:', error);
424
+ }
425
+ }
426
+ // Local fallback - simplified, would need proper implementation
427
+ return [];
428
+ }
429
+ async deleteMemoryEntries(keyPattern, partition) {
430
+ this.ensureInitialized();
431
+ // Queue for cloud sync
432
+ this.queueSync('delete', 'memory_entries', `${partition ?? 'default'}:${keyPattern}`);
433
+ // Also delete locally if cloud succeeds
434
+ if (this.syncStatus.isOnline && this.cloudProvider?.deleteMemoryEntries) {
435
+ try {
436
+ return await this.cloudProvider.deleteMemoryEntries(keyPattern, partition);
437
+ }
438
+ catch (error) {
439
+ console.warn('[HybridProvider] Cloud deleteMemoryEntries failed:', error);
440
+ }
441
+ }
442
+ return 0;
443
+ }
444
+ // ============================================
445
+ // Events (Local-first with buffering)
446
+ // ============================================
447
+ async storeEvent(event) {
448
+ this.ensureInitialized();
449
+ // Store locally
450
+ const key = `event:${event.id}`;
451
+ await this.localStore.saveCircadianState(key, {
452
+ version: 1,
453
+ state: { data: JSON.stringify(event) },
454
+ metrics: {},
455
+ lastPhaseChange: 0,
456
+ serializedAt: Date.now(),
457
+ });
458
+ // Queue for cloud sync
459
+ this.queueSync('insert', 'events', event.id, event);
460
+ this.emit('event:stored', event.id);
461
+ }
462
+ async storeEvents(events) {
463
+ // Batch store for efficiency
464
+ for (const event of events) {
465
+ await this.storeEvent(event);
466
+ }
467
+ }
468
+ async queryEvents(query) {
469
+ this.ensureInitialized();
470
+ // Query cloud if available
471
+ if (this.syncStatus.isOnline && this.cloudProvider?.queryEvents) {
472
+ try {
473
+ return await this.cloudProvider.queryEvents(query);
474
+ }
475
+ catch (error) {
476
+ console.warn('[HybridProvider] Cloud queryEvents failed:', error);
477
+ }
478
+ }
479
+ // Local fallback
480
+ return [];
481
+ }
482
+ async deleteOldEvents(olderThan) {
483
+ this.ensureInitialized();
484
+ // Queue for cloud sync
485
+ this.queueSync('delete', 'events', `older-than:${olderThan.toISOString()}`);
486
+ if (this.syncStatus.isOnline && this.cloudProvider?.deleteOldEvents) {
487
+ try {
488
+ return await this.cloudProvider.deleteOldEvents(olderThan);
489
+ }
490
+ catch (error) {
491
+ console.warn('[HybridProvider] Cloud deleteOldEvents failed:', error);
492
+ }
493
+ }
494
+ return 0;
495
+ }
496
+ // ============================================
497
+ // Code Chunks (Local-first)
498
+ // ============================================
499
+ async storeCodeChunk(chunk) {
500
+ this.ensureInitialized();
501
+ // Store locally
502
+ const key = `code:${chunk.projectId}:${chunk.filePath}:${chunk.startLine}`;
503
+ await this.localStore.saveCircadianState(key, {
504
+ version: 1,
505
+ state: { data: JSON.stringify(chunk) },
506
+ metrics: {},
507
+ lastPhaseChange: 0,
508
+ serializedAt: Date.now(),
509
+ });
510
+ // Queue for cloud sync
511
+ this.queueSync('insert', 'code_chunks', chunk.id, chunk);
512
+ this.emit('code:stored', chunk.id);
513
+ }
514
+ async storeCodeChunks(chunks) {
515
+ for (const chunk of chunks) {
516
+ await this.storeCodeChunk(chunk);
517
+ }
518
+ }
519
+ async queryCodeChunks(query) {
520
+ this.ensureInitialized();
521
+ // Query cloud if available
522
+ if (this.syncStatus.isOnline && this.cloudProvider?.queryCodeChunks) {
523
+ try {
524
+ return await this.cloudProvider.queryCodeChunks(query);
525
+ }
526
+ catch (error) {
527
+ console.warn('[HybridProvider] Cloud queryCodeChunks failed:', error);
528
+ }
529
+ }
530
+ // Local fallback
531
+ return [];
532
+ }
533
+ async searchSimilarCode(embedding, options) {
534
+ this.ensureInitialized();
535
+ // Vector search only available in cloud
536
+ if (this.syncStatus.isOnline && this.cloudProvider?.searchSimilarCode) {
537
+ return this.cloudProvider.searchSimilarCode(embedding, options);
538
+ }
539
+ // No local vector search - would require local embedding index
540
+ return [];
541
+ }
542
+ async deleteCodeChunksForFile(projectId, filePath) {
543
+ this.ensureInitialized();
544
+ // Queue for cloud sync
545
+ this.queueSync('delete', 'code_chunks', `file:${projectId}:${filePath}`);
546
+ if (this.syncStatus.isOnline && this.cloudProvider?.deleteCodeChunksForFile) {
547
+ try {
548
+ return await this.cloudProvider.deleteCodeChunksForFile(projectId, filePath);
549
+ }
550
+ catch (error) {
551
+ console.warn('[HybridProvider] Cloud deleteCodeChunksForFile failed:', error);
552
+ }
553
+ }
554
+ return 0;
555
+ }
556
+ async deleteCodeChunksForProject(projectId) {
557
+ this.ensureInitialized();
558
+ // Queue for cloud sync
559
+ this.queueSync('delete', 'code_chunks', `project:${projectId}`);
560
+ if (this.syncStatus.isOnline && this.cloudProvider?.deleteCodeChunksForProject) {
561
+ try {
562
+ return await this.cloudProvider.deleteCodeChunksForProject(projectId);
563
+ }
564
+ catch (error) {
565
+ console.warn('[HybridProvider] Cloud deleteCodeChunksForProject failed:', error);
566
+ }
567
+ }
568
+ return 0;
569
+ }
570
+ // ============================================
571
+ // Sync Operations
572
+ // ============================================
573
+ async syncToCloud() {
574
+ if (!this.syncStatus.isOnline || !this.cloudProvider) {
575
+ throw new Error('Cloud provider not available');
576
+ }
577
+ if (this.syncStatus.isSyncing) {
578
+ return { uploaded: 0, conflicts: 0 };
579
+ }
580
+ this.syncStatus.isSyncing = true;
581
+ this.emit('sync:started');
582
+ let uploaded = 0;
583
+ let conflicts = 0;
584
+ try {
585
+ // Process sync queue
586
+ const queue = [...this.syncQueue];
587
+ this.syncQueue = [];
588
+ for (const entry of queue) {
589
+ try {
590
+ await this.processSyncEntry(entry);
591
+ uploaded++;
592
+ }
593
+ catch (error) {
594
+ // Check if it's a conflict
595
+ if (this.isConflictError(error)) {
596
+ conflicts++;
597
+ await this.resolveConflict(entry);
598
+ }
599
+ else {
600
+ // Re-queue for retry
601
+ entry.retryCount++;
602
+ if (entry.retryCount < this.syncConfig.retryAttempts) {
603
+ this.syncQueue.push(entry);
604
+ }
605
+ else {
606
+ console.error(`[HybridProvider] Sync failed for ${entry.tableName}:${entry.recordId}`, error);
607
+ }
608
+ }
609
+ }
610
+ }
611
+ this.syncStatus.lastSyncTime = new Date();
612
+ this.syncStatus.pendingUploads = this.syncQueue.length;
613
+ this.syncStatus.conflicts = conflicts;
614
+ this.emit('sync:completed', { uploaded, conflicts });
615
+ }
616
+ finally {
617
+ this.syncStatus.isSyncing = false;
618
+ }
619
+ return { uploaded, conflicts };
620
+ }
621
+ async syncFromCloud() {
622
+ if (!this.syncStatus.isOnline || !this.cloudProvider) {
623
+ throw new Error('Cloud provider not available');
624
+ }
625
+ // For a full implementation, this would:
626
+ // 1. Query cloud for records newer than last sync
627
+ // 2. Download and merge with local data
628
+ // 3. Handle conflicts based on resolution strategy
629
+ this.emit('sync:fromCloud');
630
+ return { downloaded: 0, conflicts: 0 };
631
+ }
632
+ async getSyncStatus() {
633
+ return {
634
+ ...this.syncStatus,
635
+ pendingUploads: this.syncQueue.length,
636
+ };
637
+ }
638
+ // ============================================
639
+ // Info
640
+ // ============================================
641
+ getProviderInfo() {
642
+ return {
643
+ type: 'hybrid',
644
+ features: [
645
+ 'local-first',
646
+ 'offline-support',
647
+ 'background-sync',
648
+ 'conflict-resolution',
649
+ 'cloud-backup',
650
+ 'memory-sync',
651
+ 'event-sync',
652
+ 'code-intelligence-sync',
653
+ ...(this.cloudProvider ? ['cloud-available', 'vector-search', 'sharing'] : []),
654
+ ],
655
+ initialized: this.initialized,
656
+ location: this.config.localDbPath,
657
+ stats: {
658
+ agentCount: 0, // Would need to query
659
+ lastSyncTime: this.syncStatus.lastSyncTime ?? undefined,
660
+ },
661
+ };
662
+ }
663
+ // ============================================
664
+ // Private Methods
665
+ // ============================================
666
+ ensureInitialized() {
667
+ if (!this.initialized || !this.localStore) {
668
+ throw new Error('HybridPersistenceProvider not initialized');
669
+ }
670
+ }
671
+ ensureCloudAvailable() {
672
+ this.ensureInitialized();
673
+ if (!this.cloudProvider) {
674
+ throw new Error('Cloud provider not available');
675
+ }
676
+ }
677
+ queueSync(operation, tableName, recordId, data) {
678
+ const entry = {
679
+ id: `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
680
+ operation,
681
+ tableName,
682
+ recordId,
683
+ data,
684
+ retryCount: 0,
685
+ createdAt: Date.now(),
686
+ };
687
+ this.syncQueue.push(entry);
688
+ this.syncStatus.pendingUploads = this.syncQueue.length;
689
+ // Force sync if queue is too large
690
+ if (this.syncQueue.length >= this.config.maxQueueSize) {
691
+ this.syncToCloud().catch((err) => console.warn('[HybridProvider] Force sync failed:', err));
692
+ }
693
+ }
694
+ async processSyncEntry(entry) {
695
+ if (!this.cloudProvider)
696
+ return;
697
+ // Process based on table and operation
698
+ switch (entry.tableName) {
699
+ case 'experiences':
700
+ if (entry.operation === 'insert' || entry.operation === 'update') {
701
+ await this.cloudProvider.storeExperience(entry.data);
702
+ }
703
+ break;
704
+ case 'patterns':
705
+ if (entry.operation === 'insert' || entry.operation === 'update') {
706
+ await this.cloudProvider.storePattern(entry.data);
707
+ }
708
+ break;
709
+ case 'nervous_system':
710
+ if (entry.operation === 'update' && entry.data) {
711
+ const { agentId, component, state } = entry.data;
712
+ const stateValue = Array.isArray(state) ? new Uint8Array(state) : state;
713
+ await this.cloudProvider.saveNervousSystemState(agentId, component, stateValue);
714
+ }
715
+ else if (entry.operation === 'delete') {
716
+ await this.cloudProvider.deleteNervousSystemState(entry.recordId);
717
+ }
718
+ break;
719
+ case 'memory_entries':
720
+ if ((entry.operation === 'insert' || entry.operation === 'update') && entry.data) {
721
+ if (this.cloudProvider.storeMemoryEntry) {
722
+ await this.cloudProvider.storeMemoryEntry(entry.data);
723
+ }
724
+ }
725
+ else if (entry.operation === 'delete') {
726
+ if (this.cloudProvider.deleteMemoryEntries) {
727
+ const [partition, keyPattern] = entry.recordId.split(':');
728
+ await this.cloudProvider.deleteMemoryEntries(keyPattern, partition);
729
+ }
730
+ }
731
+ break;
732
+ case 'events':
733
+ if ((entry.operation === 'insert' || entry.operation === 'update') && entry.data) {
734
+ if (this.cloudProvider.storeEvent) {
735
+ await this.cloudProvider.storeEvent(entry.data);
736
+ }
737
+ }
738
+ else if (entry.operation === 'delete') {
739
+ if (entry.recordId.startsWith('older-than:') && this.cloudProvider.deleteOldEvents) {
740
+ const dateStr = entry.recordId.replace('older-than:', '');
741
+ await this.cloudProvider.deleteOldEvents(new Date(dateStr));
742
+ }
743
+ }
744
+ break;
745
+ case 'code_chunks':
746
+ if ((entry.operation === 'insert' || entry.operation === 'update') && entry.data) {
747
+ if (this.cloudProvider.storeCodeChunk) {
748
+ await this.cloudProvider.storeCodeChunk(entry.data);
749
+ }
750
+ }
751
+ else if (entry.operation === 'delete') {
752
+ if (entry.recordId.startsWith('file:') && this.cloudProvider.deleteCodeChunksForFile) {
753
+ const [, projectId, ...filePathParts] = entry.recordId.split(':');
754
+ await this.cloudProvider.deleteCodeChunksForFile(projectId, filePathParts.join(':'));
755
+ }
756
+ else if (entry.recordId.startsWith('project:') && this.cloudProvider.deleteCodeChunksForProject) {
757
+ const projectId = entry.recordId.replace('project:', '');
758
+ await this.cloudProvider.deleteCodeChunksForProject(projectId);
759
+ }
760
+ }
761
+ break;
762
+ }
763
+ }
764
+ isConflictError(error) {
765
+ if (error instanceof Error) {
766
+ return error.message.includes('conflict') || error.message.includes('duplicate');
767
+ }
768
+ return false;
769
+ }
770
+ async resolveConflict(entry) {
771
+ // Apply conflict resolution strategy
772
+ switch (this.syncConfig.conflictResolution) {
773
+ case 'local':
774
+ // Keep local version - force update to cloud
775
+ entry.retryCount = 0;
776
+ this.syncQueue.push(entry);
777
+ break;
778
+ case 'remote':
779
+ // Keep remote version - discard local change
780
+ // Would need to fetch and apply remote version
781
+ break;
782
+ case 'newest':
783
+ // Compare timestamps and keep newest
784
+ // Would need to fetch remote timestamp
785
+ break;
786
+ }
787
+ this.emit('sync:conflict', entry);
788
+ }
789
+ startBackgroundSync() {
790
+ if (this.syncTimer)
791
+ return;
792
+ this.syncTimer = setInterval(() => {
793
+ if (this.syncQueue.length > 0 && this.syncStatus.isOnline) {
794
+ this.syncToCloud().catch((err) => console.warn('[HybridProvider] Background sync failed:', err));
795
+ }
796
+ }, this.syncConfig.syncInterval);
797
+ }
798
+ stopBackgroundSync() {
799
+ if (this.syncTimer) {
800
+ clearInterval(this.syncTimer);
801
+ this.syncTimer = null;
802
+ }
803
+ }
804
+ // ============================================
805
+ // Sync Management Methods
806
+ // ============================================
807
+ /**
808
+ * Get current sync statistics
809
+ */
810
+ getSyncStats() {
811
+ return {
812
+ pendingOperations: this.syncQueue.length,
813
+ lastSyncTime: this.syncStatus.lastSyncTime,
814
+ isOnline: this.syncStatus.isOnline,
815
+ isSyncing: this.syncStatus.isSyncing,
816
+ conflicts: this.syncStatus.conflicts,
817
+ };
818
+ }
819
+ /**
820
+ * Force immediate sync of all pending operations
821
+ */
822
+ async forceSyncNow() {
823
+ if (!this.cloudProvider) {
824
+ return { synced: 0, failed: 0 };
825
+ }
826
+ const queueSnapshot = [...this.syncQueue];
827
+ let synced = 0;
828
+ let failed = 0;
829
+ for (const entry of queueSnapshot) {
830
+ try {
831
+ await this.processSyncEntry(entry);
832
+ // Remove from queue
833
+ this.syncQueue = this.syncQueue.filter((e) => e.id !== entry.id);
834
+ synced++;
835
+ }
836
+ catch (error) {
837
+ console.warn(`[HybridProvider] Sync failed for ${entry.tableName}:${entry.recordId}:`, error);
838
+ failed++;
839
+ // Increment retry count
840
+ const queueEntry = this.syncQueue.find((e) => e.id === entry.id);
841
+ if (queueEntry) {
842
+ queueEntry.retryCount++;
843
+ }
844
+ }
845
+ }
846
+ this.syncStatus.lastSyncTime = new Date();
847
+ this.emit('sync:completed', { synced, failed });
848
+ return { synced, failed };
849
+ }
850
+ /**
851
+ * Clear all pending sync operations
852
+ */
853
+ clearSyncQueue() {
854
+ const count = this.syncQueue.length;
855
+ this.syncQueue = [];
856
+ this.emit('sync:queue-cleared', { count });
857
+ }
858
+ /**
859
+ * Set online status (for offline/online detection)
860
+ */
861
+ setOnlineStatus(isOnline) {
862
+ const wasOnline = this.syncStatus.isOnline;
863
+ this.syncStatus.isOnline = isOnline;
864
+ if (!wasOnline && isOnline && this.syncQueue.length > 0) {
865
+ // Came back online with pending operations, trigger sync
866
+ this.forceSyncNow().catch((err) => console.warn('[HybridProvider] Sync on reconnect failed:', err));
867
+ }
868
+ this.emit('sync:online-status', { isOnline });
869
+ }
870
+ /**
871
+ * Migrate all local data from memory.db to Supabase cloud
872
+ * This is a one-time migration for existing local data
873
+ */
874
+ async migrateLocalToCloud(memoryDbPath, options = {}) {
875
+ if (!this.cloudProvider) {
876
+ throw new Error('Cloud provider not available');
877
+ }
878
+ const { batchSize = 100, onProgress = console.log } = options;
879
+ const results = { experiences: 0, memories: 0, patterns: 0, events: 0, failed: 0 };
880
+ // Dynamic import to avoid bundling issues
881
+ const Database = (await Promise.resolve().then(() => __importStar(require('better-sqlite3')))).default;
882
+ const db = new Database(memoryDbPath, { readonly: true });
883
+ try {
884
+ // Project should already be ensured during initialize()
885
+ // The cloud provider handles projectId internally
886
+ // Migrate learning_experiences
887
+ onProgress('Migrating learning experiences...');
888
+ const experiences = db.prepare(`
889
+ SELECT agent_id, task_type, state, action, reward, next_state, metadata, created_at
890
+ FROM learning_experiences
891
+ `).all();
892
+ for (let i = 0; i < experiences.length; i += batchSize) {
893
+ const batch = experiences.slice(i, i + batchSize);
894
+ for (const exp of batch) {
895
+ try {
896
+ await this.cloudProvider.storeExperience({
897
+ id: crypto.randomUUID(),
898
+ agentId: exp.agent_id || 'unknown',
899
+ agentType: exp.task_type?.split('-')[0] || 'general',
900
+ taskType: exp.task_type || 'unknown',
901
+ context: this.safeJsonParse(exp.state, {}),
902
+ outcome: {
903
+ result: 'success',
904
+ confidence: exp.reward || 0.5,
905
+ ...this.safeJsonParse(exp.action, {}),
906
+ },
907
+ privacyLevel: 'private',
908
+ isAnonymized: false,
909
+ shareCount: 0,
910
+ createdAt: this.safeParseDate(exp.created_at),
911
+ });
912
+ results.experiences++;
913
+ }
914
+ catch (err) {
915
+ results.failed++;
916
+ if (results.failed <= 3) {
917
+ console.error(` Experience error: ${err instanceof Error ? err.message : err}`);
918
+ }
919
+ }
920
+ }
921
+ onProgress(` Experiences: ${Math.min(i + batchSize, experiences.length)}/${experiences.length}`);
922
+ }
923
+ // Migrate memory_entries
924
+ onProgress('Migrating memory entries...');
925
+ const memories = db.prepare(`
926
+ SELECT key, partition, value, owner, metadata, created_at, expires_at
927
+ FROM memory_entries
928
+ LIMIT 2000
929
+ `).all();
930
+ for (let i = 0; i < memories.length; i += batchSize) {
931
+ const batch = memories.slice(i, i + batchSize);
932
+ for (const mem of batch) {
933
+ try {
934
+ await this.cloudProvider.storeMemoryEntry({
935
+ key: mem.key,
936
+ partition: mem.partition || 'default',
937
+ value: String(mem.value),
938
+ owner: mem.owner || 'system',
939
+ accessLevel: 'owner',
940
+ metadata: this.safeJsonParse(mem.metadata, {}),
941
+ createdAt: this.safeParseDate(mem.created_at),
942
+ expiresAt: mem.expires_at ? this.safeParseDate(mem.expires_at) : undefined,
943
+ });
944
+ results.memories++;
945
+ }
946
+ catch (err) {
947
+ results.failed++;
948
+ if (results.failed <= 5) {
949
+ console.error(` Memory error: ${err instanceof Error ? err.message : err}`);
950
+ }
951
+ }
952
+ }
953
+ onProgress(` Memories: ${Math.min(i + batchSize, memories.length)}/${memories.length}`);
954
+ }
955
+ // Migrate patterns
956
+ onProgress('Migrating patterns...');
957
+ const patterns = db.prepare(`
958
+ SELECT id, pattern, confidence, usage_count, metadata, domain, created_at
959
+ FROM patterns
960
+ LIMIT 500
961
+ `).all();
962
+ for (let i = 0; i < patterns.length; i += batchSize) {
963
+ const batch = patterns.slice(i, i + batchSize);
964
+ for (const pat of batch) {
965
+ try {
966
+ // Preserve original_id in metadata if not a valid UUID
967
+ const metadata = this.safeJsonParse(pat.metadata, {});
968
+ if (pat.id && !this.isValidUUID(pat.id)) {
969
+ metadata.original_id = pat.id;
970
+ }
971
+ await this.cloudProvider.storePattern({
972
+ id: this.isValidUUID(pat.id) ? pat.id : crypto.randomUUID(),
973
+ type: 'learned',
974
+ domain: pat.domain || 'general',
975
+ content: pat.pattern || '',
976
+ confidence: pat.confidence || 0.5,
977
+ usageCount: pat.usage_count || 0,
978
+ privacyLevel: 'private',
979
+ isAnonymized: false,
980
+ metadata,
981
+ createdAt: this.safeParseDate(pat.created_at),
982
+ });
983
+ results.patterns++;
984
+ }
985
+ catch (err) {
986
+ results.failed++;
987
+ if (results.failed <= 8) {
988
+ console.error(` Pattern error: ${err instanceof Error ? err.message : err}`);
989
+ }
990
+ }
991
+ }
992
+ onProgress(` Patterns: ${Math.min(i + batchSize, patterns.length)}/${patterns.length}`);
993
+ }
994
+ // Migrate events
995
+ onProgress('Migrating events...');
996
+ const events = db.prepare(`
997
+ SELECT id, type, payload, timestamp, source, ttl
998
+ FROM events
999
+ LIMIT 2000
1000
+ `).all();
1001
+ for (let i = 0; i < events.length; i += batchSize) {
1002
+ const batch = events.slice(i, i + batchSize);
1003
+ for (const evt of batch) {
1004
+ try {
1005
+ // Parse payload and add original_id to preserve reference
1006
+ const payload = this.safeJsonParse(evt.payload, {});
1007
+ if (evt.id && !this.isValidUUID(evt.id)) {
1008
+ payload.original_id = evt.id;
1009
+ }
1010
+ await this.cloudProvider.storeEvent({
1011
+ id: this.isValidUUID(evt.id) ? evt.id : crypto.randomUUID(),
1012
+ type: evt.type || 'unknown',
1013
+ payload,
1014
+ source: evt.source || 'migration',
1015
+ timestamp: this.safeParseDate(evt.timestamp),
1016
+ ttl: evt.ttl || 0,
1017
+ });
1018
+ results.events++;
1019
+ }
1020
+ catch (err) {
1021
+ results.failed++;
1022
+ if (results.failed <= 10) {
1023
+ console.error(` Event error: ${err instanceof Error ? err.message : err}`);
1024
+ }
1025
+ }
1026
+ }
1027
+ onProgress(` Events: ${Math.min(i + batchSize, events.length)}/${events.length}`);
1028
+ }
1029
+ }
1030
+ finally {
1031
+ db.close();
1032
+ }
1033
+ return results;
1034
+ }
1035
+ safeJsonParse(value, fallback) {
1036
+ if (typeof value === 'string') {
1037
+ try {
1038
+ return JSON.parse(value);
1039
+ }
1040
+ catch {
1041
+ return fallback;
1042
+ }
1043
+ }
1044
+ return value ?? fallback;
1045
+ }
1046
+ isValidUUID(value) {
1047
+ if (typeof value !== 'string')
1048
+ return false;
1049
+ const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
1050
+ return uuidRegex.test(value);
1051
+ }
1052
+ safeParseDate(value) {
1053
+ if (!value)
1054
+ return new Date();
1055
+ // Try as number (timestamp)
1056
+ const num = Number(value);
1057
+ if (!isNaN(num) && num > 0) {
1058
+ // Check if it's a reasonable timestamp (after year 2000, before year 2100)
1059
+ const minTs = new Date('2000-01-01').getTime();
1060
+ const maxTs = new Date('2100-01-01').getTime();
1061
+ if (num >= minTs && num <= maxTs) {
1062
+ return new Date(num);
1063
+ }
1064
+ // Might be seconds instead of milliseconds
1065
+ if (num * 1000 >= minTs && num * 1000 <= maxTs) {
1066
+ return new Date(num * 1000);
1067
+ }
1068
+ }
1069
+ // Try as string
1070
+ if (typeof value === 'string') {
1071
+ const date = new Date(value);
1072
+ if (!isNaN(date.getTime())) {
1073
+ return date;
1074
+ }
1075
+ }
1076
+ return new Date();
1077
+ }
1078
+ }
1079
+ exports.HybridPersistenceProvider = HybridPersistenceProvider;
1080
+ /**
1081
+ * Factory function to create a hybrid persistence provider
1082
+ */
1083
+ function createHybridPersistenceProvider(config) {
1084
+ return new HybridPersistenceProvider(config);
1085
+ }
1086
+ //# sourceMappingURL=HybridPersistenceProvider.js.map