agentic-qe 2.8.0 → 2.8.2
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/CHANGELOG.md +148 -0
- package/README.md +1 -1
- package/dist/agents/BaseAgent.d.ts +329 -0
- package/dist/agents/BaseAgent.d.ts.map +1 -1
- package/dist/agents/BaseAgent.js +657 -0
- package/dist/agents/BaseAgent.js.map +1 -1
- package/dist/cli/commands/supabase/index.d.ts +20 -0
- package/dist/cli/commands/supabase/index.d.ts.map +1 -0
- package/dist/cli/commands/supabase/index.js +632 -0
- package/dist/cli/commands/supabase/index.js.map +1 -0
- package/dist/cli/index.js +3 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/code-intelligence/embeddings/EmbeddingCacheFactory.d.ts +135 -0
- package/dist/code-intelligence/embeddings/EmbeddingCacheFactory.d.ts.map +1 -0
- package/dist/code-intelligence/embeddings/EmbeddingCacheFactory.js +301 -0
- package/dist/code-intelligence/embeddings/EmbeddingCacheFactory.js.map +1 -0
- package/dist/code-intelligence/embeddings/NomicEmbedder.d.ts +78 -6
- package/dist/code-intelligence/embeddings/NomicEmbedder.d.ts.map +1 -1
- package/dist/code-intelligence/embeddings/NomicEmbedder.js +162 -21
- package/dist/code-intelligence/embeddings/NomicEmbedder.js.map +1 -1
- package/dist/code-intelligence/embeddings/backends/MemoryBackend.d.ts +59 -0
- package/dist/code-intelligence/embeddings/backends/MemoryBackend.d.ts.map +1 -0
- package/dist/code-intelligence/embeddings/backends/MemoryBackend.js +173 -0
- package/dist/code-intelligence/embeddings/backends/MemoryBackend.js.map +1 -0
- package/dist/code-intelligence/embeddings/backends/RedisBackend.d.ts +50 -0
- package/dist/code-intelligence/embeddings/backends/RedisBackend.d.ts.map +1 -0
- package/dist/code-intelligence/embeddings/backends/RedisBackend.js +279 -0
- package/dist/code-intelligence/embeddings/backends/RedisBackend.js.map +1 -0
- package/dist/code-intelligence/embeddings/backends/SQLiteBackend.d.ts +64 -0
- package/dist/code-intelligence/embeddings/backends/SQLiteBackend.d.ts.map +1 -0
- package/dist/code-intelligence/embeddings/backends/SQLiteBackend.js +314 -0
- package/dist/code-intelligence/embeddings/backends/SQLiteBackend.js.map +1 -0
- package/dist/code-intelligence/embeddings/backends/index.d.ts +16 -0
- package/dist/code-intelligence/embeddings/backends/index.d.ts.map +1 -0
- package/dist/code-intelligence/embeddings/backends/index.js +28 -0
- package/dist/code-intelligence/embeddings/backends/index.js.map +1 -0
- package/dist/code-intelligence/embeddings/backends/types.d.ts +177 -0
- package/dist/code-intelligence/embeddings/backends/types.d.ts.map +1 -0
- package/dist/code-intelligence/embeddings/backends/types.js +30 -0
- package/dist/code-intelligence/embeddings/backends/types.js.map +1 -0
- package/dist/code-intelligence/embeddings/index.d.ts +7 -0
- package/dist/code-intelligence/embeddings/index.d.ts.map +1 -1
- package/dist/code-intelligence/embeddings/index.js +16 -1
- package/dist/code-intelligence/embeddings/index.js.map +1 -1
- package/dist/core/memory/HNSWVectorMemory.js +1 -1
- package/dist/infrastructure/index.d.ts +15 -0
- package/dist/infrastructure/index.d.ts.map +1 -0
- package/dist/infrastructure/index.js +44 -0
- package/dist/infrastructure/index.js.map +1 -0
- package/dist/infrastructure/network/AgentRateLimiter.d.ts +59 -0
- package/dist/infrastructure/network/AgentRateLimiter.d.ts.map +1 -0
- package/dist/infrastructure/network/AgentRateLimiter.js +186 -0
- package/dist/infrastructure/network/AgentRateLimiter.js.map +1 -0
- package/dist/infrastructure/network/AuditLogger.d.ts +102 -0
- package/dist/infrastructure/network/AuditLogger.d.ts.map +1 -0
- package/dist/infrastructure/network/AuditLogger.js +284 -0
- package/dist/infrastructure/network/AuditLogger.js.map +1 -0
- package/dist/infrastructure/network/DomainWhitelist.d.ts +111 -0
- package/dist/infrastructure/network/DomainWhitelist.d.ts.map +1 -0
- package/dist/infrastructure/network/DomainWhitelist.js +216 -0
- package/dist/infrastructure/network/DomainWhitelist.js.map +1 -0
- package/dist/infrastructure/network/NetworkPolicyManager.d.ts +97 -0
- package/dist/infrastructure/network/NetworkPolicyManager.d.ts.map +1 -0
- package/dist/infrastructure/network/NetworkPolicyManager.js +309 -0
- package/dist/infrastructure/network/NetworkPolicyManager.js.map +1 -0
- package/dist/infrastructure/network/index.d.ts +19 -0
- package/dist/infrastructure/network/index.d.ts.map +1 -0
- package/dist/infrastructure/network/index.js +46 -0
- package/dist/infrastructure/network/index.js.map +1 -0
- package/dist/infrastructure/network/policies/default-policies.d.ts +78 -0
- package/dist/infrastructure/network/policies/default-policies.d.ts.map +1 -0
- package/dist/infrastructure/network/policies/default-policies.js +312 -0
- package/dist/infrastructure/network/policies/default-policies.js.map +1 -0
- package/dist/infrastructure/network/types.d.ts +214 -0
- package/dist/infrastructure/network/types.d.ts.map +1 -0
- package/dist/infrastructure/network/types.js +25 -0
- package/dist/infrastructure/network/types.js.map +1 -0
- package/dist/infrastructure/sandbox/ResourceMonitor.d.ts +124 -0
- package/dist/infrastructure/sandbox/ResourceMonitor.d.ts.map +1 -0
- package/dist/infrastructure/sandbox/ResourceMonitor.js +305 -0
- package/dist/infrastructure/sandbox/ResourceMonitor.js.map +1 -0
- package/dist/infrastructure/sandbox/SandboxManager.d.ts +122 -0
- package/dist/infrastructure/sandbox/SandboxManager.d.ts.map +1 -0
- package/dist/infrastructure/sandbox/SandboxManager.js +527 -0
- package/dist/infrastructure/sandbox/SandboxManager.js.map +1 -0
- package/dist/infrastructure/sandbox/index.d.ts +18 -0
- package/dist/infrastructure/sandbox/index.d.ts.map +1 -0
- package/dist/infrastructure/sandbox/index.js +38 -0
- package/dist/infrastructure/sandbox/index.js.map +1 -0
- package/dist/infrastructure/sandbox/profiles/agent-profiles.d.ts +53 -0
- package/dist/infrastructure/sandbox/profiles/agent-profiles.d.ts.map +1 -0
- package/dist/infrastructure/sandbox/profiles/agent-profiles.js +433 -0
- package/dist/infrastructure/sandbox/profiles/agent-profiles.js.map +1 -0
- package/dist/infrastructure/sandbox/types.d.ts +227 -0
- package/dist/infrastructure/sandbox/types.d.ts.map +1 -0
- package/dist/infrastructure/sandbox/types.js +63 -0
- package/dist/infrastructure/sandbox/types.js.map +1 -0
- package/dist/mcp/handlers/NewDomainToolsHandler.d.ts +8 -8
- package/dist/mcp/handlers/NewDomainToolsHandler.d.ts.map +1 -1
- package/dist/mcp/handlers/NewDomainToolsHandler.js.map +1 -1
- package/dist/mcp/handlers/ruvector/RuVectorHandler.d.ts +54 -0
- package/dist/mcp/handlers/ruvector/RuVectorHandler.d.ts.map +1 -0
- package/dist/mcp/handlers/ruvector/RuVectorHandler.js +325 -0
- package/dist/mcp/handlers/ruvector/RuVectorHandler.js.map +1 -0
- package/dist/mcp/handlers/ruvector/index.d.ts +5 -0
- package/dist/mcp/handlers/ruvector/index.d.ts.map +1 -0
- package/dist/mcp/handlers/ruvector/index.js +9 -0
- package/dist/mcp/handlers/ruvector/index.js.map +1 -0
- package/dist/mcp/server-instructions.d.ts +1 -1
- package/dist/mcp/server-instructions.js +1 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +100 -22
- package/dist/mcp/server.js.map +1 -1
- package/dist/nervous-system/adapters/BTSPAdapter.d.ts +342 -0
- package/dist/nervous-system/adapters/BTSPAdapter.d.ts.map +1 -0
- package/dist/nervous-system/adapters/BTSPAdapter.js +494 -0
- package/dist/nervous-system/adapters/BTSPAdapter.js.map +1 -0
- package/dist/nervous-system/adapters/CircadianController.d.ts +560 -0
- package/dist/nervous-system/adapters/CircadianController.d.ts.map +1 -0
- package/dist/nervous-system/adapters/CircadianController.js +882 -0
- package/dist/nervous-system/adapters/CircadianController.js.map +1 -0
- package/dist/nervous-system/adapters/GlobalWorkspaceAdapter.d.ts +337 -0
- package/dist/nervous-system/adapters/GlobalWorkspaceAdapter.d.ts.map +1 -0
- package/dist/nervous-system/adapters/GlobalWorkspaceAdapter.js +532 -0
- package/dist/nervous-system/adapters/GlobalWorkspaceAdapter.js.map +1 -0
- package/dist/nervous-system/adapters/HdcMemoryAdapter.d.ts +444 -0
- package/dist/nervous-system/adapters/HdcMemoryAdapter.d.ts.map +1 -0
- package/dist/nervous-system/adapters/HdcMemoryAdapter.js +715 -0
- package/dist/nervous-system/adapters/HdcMemoryAdapter.js.map +1 -0
- package/dist/nervous-system/adapters/ReflexLayer.d.ts +231 -0
- package/dist/nervous-system/adapters/ReflexLayer.d.ts.map +1 -0
- package/dist/nervous-system/adapters/ReflexLayer.js +309 -0
- package/dist/nervous-system/adapters/ReflexLayer.js.map +1 -0
- package/dist/nervous-system/index.d.ts +25 -0
- package/dist/nervous-system/index.d.ts.map +1 -0
- package/dist/nervous-system/index.js +80 -0
- package/dist/nervous-system/index.js.map +1 -0
- package/dist/nervous-system/integration/BTSPLearningEngine.d.ts +266 -0
- package/dist/nervous-system/integration/BTSPLearningEngine.d.ts.map +1 -0
- package/dist/nervous-system/integration/BTSPLearningEngine.js +587 -0
- package/dist/nervous-system/integration/BTSPLearningEngine.js.map +1 -0
- package/dist/nervous-system/integration/CircadianAgent.d.ts +389 -0
- package/dist/nervous-system/integration/CircadianAgent.d.ts.map +1 -0
- package/dist/nervous-system/integration/CircadianAgent.js +696 -0
- package/dist/nervous-system/integration/CircadianAgent.js.map +1 -0
- package/dist/nervous-system/integration/HybridPatternStore.d.ts +244 -0
- package/dist/nervous-system/integration/HybridPatternStore.d.ts.map +1 -0
- package/dist/nervous-system/integration/HybridPatternStore.js +622 -0
- package/dist/nervous-system/integration/HybridPatternStore.js.map +1 -0
- package/dist/nervous-system/integration/NervousSystemEnhancement.d.ts +459 -0
- package/dist/nervous-system/integration/NervousSystemEnhancement.d.ts.map +1 -0
- package/dist/nervous-system/integration/NervousSystemEnhancement.js +921 -0
- package/dist/nervous-system/integration/NervousSystemEnhancement.js.map +1 -0
- package/dist/nervous-system/integration/WorkspaceAgent.d.ts +398 -0
- package/dist/nervous-system/integration/WorkspaceAgent.d.ts.map +1 -0
- package/dist/nervous-system/integration/WorkspaceAgent.js +722 -0
- package/dist/nervous-system/integration/WorkspaceAgent.js.map +1 -0
- package/dist/nervous-system/integration/index.d.ts +22 -0
- package/dist/nervous-system/integration/index.d.ts.map +1 -0
- package/dist/nervous-system/integration/index.js +44 -0
- package/dist/nervous-system/integration/index.js.map +1 -0
- package/dist/nervous-system/persistence/BTSPSerializer.d.ts +96 -0
- package/dist/nervous-system/persistence/BTSPSerializer.d.ts.map +1 -0
- package/dist/nervous-system/persistence/BTSPSerializer.js +223 -0
- package/dist/nervous-system/persistence/BTSPSerializer.js.map +1 -0
- package/dist/nervous-system/persistence/CircadianSerializer.d.ts +90 -0
- package/dist/nervous-system/persistence/CircadianSerializer.d.ts.map +1 -0
- package/dist/nervous-system/persistence/CircadianSerializer.js +239 -0
- package/dist/nervous-system/persistence/CircadianSerializer.js.map +1 -0
- package/dist/nervous-system/persistence/HdcSerializer.d.ts +100 -0
- package/dist/nervous-system/persistence/HdcSerializer.d.ts.map +1 -0
- package/dist/nervous-system/persistence/HdcSerializer.js +259 -0
- package/dist/nervous-system/persistence/HdcSerializer.js.map +1 -0
- package/dist/nervous-system/persistence/INervousSystemStore.d.ts +208 -0
- package/dist/nervous-system/persistence/INervousSystemStore.d.ts.map +1 -0
- package/dist/nervous-system/persistence/INervousSystemStore.js +11 -0
- package/dist/nervous-system/persistence/INervousSystemStore.js.map +1 -0
- package/dist/nervous-system/persistence/NervousSystemPersistenceManager.d.ts +187 -0
- package/dist/nervous-system/persistence/NervousSystemPersistenceManager.d.ts.map +1 -0
- package/dist/nervous-system/persistence/NervousSystemPersistenceManager.js +411 -0
- package/dist/nervous-system/persistence/NervousSystemPersistenceManager.js.map +1 -0
- package/dist/nervous-system/persistence/SQLiteNervousSystemStore.d.ts +98 -0
- package/dist/nervous-system/persistence/SQLiteNervousSystemStore.d.ts.map +1 -0
- package/dist/nervous-system/persistence/SQLiteNervousSystemStore.js +510 -0
- package/dist/nervous-system/persistence/SQLiteNervousSystemStore.js.map +1 -0
- package/dist/nervous-system/persistence/index.d.ts +22 -0
- package/dist/nervous-system/persistence/index.d.ts.map +1 -0
- package/dist/nervous-system/persistence/index.js +45 -0
- package/dist/nervous-system/persistence/index.js.map +1 -0
- package/dist/nervous-system/wasm-loader.d.ts +52 -0
- package/dist/nervous-system/wasm-loader.d.ts.map +1 -0
- package/dist/nervous-system/wasm-loader.js +188 -0
- package/dist/nervous-system/wasm-loader.js.map +1 -0
- package/dist/persistence/HybridPersistenceProvider.d.ts +184 -0
- package/dist/persistence/HybridPersistenceProvider.d.ts.map +1 -0
- package/dist/persistence/HybridPersistenceProvider.js +1086 -0
- package/dist/persistence/HybridPersistenceProvider.js.map +1 -0
- package/dist/persistence/IPersistenceProvider.d.ts +657 -0
- package/dist/persistence/IPersistenceProvider.d.ts.map +1 -0
- package/dist/persistence/IPersistenceProvider.js +11 -0
- package/dist/persistence/IPersistenceProvider.js.map +1 -0
- package/dist/persistence/SupabaseConfig.d.ts +176 -0
- package/dist/persistence/SupabaseConfig.d.ts.map +1 -0
- package/dist/persistence/SupabaseConfig.js +277 -0
- package/dist/persistence/SupabaseConfig.js.map +1 -0
- package/dist/persistence/SupabasePersistenceProvider.d.ts +143 -0
- package/dist/persistence/SupabasePersistenceProvider.d.ts.map +1 -0
- package/dist/persistence/SupabasePersistenceProvider.js +959 -0
- package/dist/persistence/SupabasePersistenceProvider.js.map +1 -0
- package/dist/persistence/adapters/CodeIntelligenceSyncAdapter.d.ts +213 -0
- package/dist/persistence/adapters/CodeIntelligenceSyncAdapter.d.ts.map +1 -0
- package/dist/persistence/adapters/CodeIntelligenceSyncAdapter.js +468 -0
- package/dist/persistence/adapters/CodeIntelligenceSyncAdapter.js.map +1 -0
- package/dist/persistence/adapters/MemorySyncAdapter.d.ts +115 -0
- package/dist/persistence/adapters/MemorySyncAdapter.d.ts.map +1 -0
- package/dist/persistence/adapters/MemorySyncAdapter.js +291 -0
- package/dist/persistence/adapters/MemorySyncAdapter.js.map +1 -0
- package/dist/persistence/adapters/index.d.ts +11 -0
- package/dist/persistence/adapters/index.d.ts.map +1 -0
- package/dist/persistence/adapters/index.js +20 -0
- package/dist/persistence/adapters/index.js.map +1 -0
- package/dist/persistence/index.d.ts +14 -0
- package/dist/persistence/index.d.ts.map +1 -1
- package/dist/persistence/index.js +36 -1
- package/dist/persistence/index.js.map +1 -1
- package/package.json +7 -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
|