agentic-qe 2.8.1 → 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 +43 -0
- package/README.md +1 -1
- package/dist/agents/BaseAgent.d.ts +201 -0
- package/dist/agents/BaseAgent.d.ts.map +1 -1
- package/dist/agents/BaseAgent.js +401 -0
- package/dist/agents/BaseAgent.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/server-instructions.d.ts +1 -1
- package/dist/mcp/server-instructions.js +1 -1
- package/dist/persistence/SupabasePersistenceProvider.d.ts.map +1 -1
- package/dist/persistence/SupabasePersistenceProvider.js +8 -4
- package/dist/persistence/SupabasePersistenceProvider.js.map +1 -1
- package/package.json +5 -1
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Redis Storage Backend for Embedding Cache
|
|
4
|
+
*
|
|
5
|
+
* Distributed caching with automatic TTL expiration.
|
|
6
|
+
* Best for multi-process/multi-server deployments.
|
|
7
|
+
*
|
|
8
|
+
* @module code-intelligence/embeddings/backends/RedisBackend
|
|
9
|
+
* @see Issue #146 - Security Hardening: SP-2 Dedicated Embedding Cache
|
|
10
|
+
*/
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.RedisStorageBackend = void 0;
|
|
13
|
+
const ioredis_1 = require("ioredis");
|
|
14
|
+
const types_js_1 = require("./types.js");
|
|
15
|
+
/**
|
|
16
|
+
* Default Redis configuration
|
|
17
|
+
*/
|
|
18
|
+
const DEFAULT_REDIS_CONFIG = {
|
|
19
|
+
host: 'localhost',
|
|
20
|
+
port: 6379,
|
|
21
|
+
db: 0,
|
|
22
|
+
keyPrefix: 'emb:',
|
|
23
|
+
ttlSeconds: 86400, // 24 hours
|
|
24
|
+
connectTimeoutMs: 5000,
|
|
25
|
+
tls: false,
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Redis-based embedding storage backend
|
|
29
|
+
*
|
|
30
|
+
* Features:
|
|
31
|
+
* - Distributed caching across processes
|
|
32
|
+
* - Automatic TTL expiration via Redis SETEX
|
|
33
|
+
* - Connection pooling via ioredis
|
|
34
|
+
* - Graceful degradation on connection failure
|
|
35
|
+
*/
|
|
36
|
+
class RedisStorageBackend {
|
|
37
|
+
constructor(config) {
|
|
38
|
+
this.name = 'redis';
|
|
39
|
+
this.type = 'redis';
|
|
40
|
+
this.client = null;
|
|
41
|
+
this.initialized = false;
|
|
42
|
+
this.healthy = false;
|
|
43
|
+
this.config = {
|
|
44
|
+
host: config.host,
|
|
45
|
+
port: config.port,
|
|
46
|
+
password: config.password ?? '',
|
|
47
|
+
db: config.db ?? DEFAULT_REDIS_CONFIG.db,
|
|
48
|
+
keyPrefix: config.keyPrefix ?? DEFAULT_REDIS_CONFIG.keyPrefix,
|
|
49
|
+
ttlSeconds: config.ttlSeconds ?? DEFAULT_REDIS_CONFIG.ttlSeconds,
|
|
50
|
+
connectTimeoutMs: config.connectTimeoutMs ?? DEFAULT_REDIS_CONFIG.connectTimeoutMs,
|
|
51
|
+
tls: config.tls ?? DEFAULT_REDIS_CONFIG.tls,
|
|
52
|
+
maxSize: config.maxSize ?? 0,
|
|
53
|
+
defaultTtlMs: config.defaultTtlMs ?? types_js_1.DEFAULT_TTL_MS,
|
|
54
|
+
debug: config.debug ?? false,
|
|
55
|
+
retryStrategy: config.retryStrategy ?? ((times) => Math.min(times * 100, 3000)),
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
async initialize() {
|
|
59
|
+
if (this.initialized)
|
|
60
|
+
return;
|
|
61
|
+
try {
|
|
62
|
+
this.client = new ioredis_1.Redis({
|
|
63
|
+
host: this.config.host,
|
|
64
|
+
port: this.config.port,
|
|
65
|
+
password: this.config.password || undefined,
|
|
66
|
+
db: this.config.db,
|
|
67
|
+
connectTimeout: this.config.connectTimeoutMs,
|
|
68
|
+
tls: this.config.tls ? {} : undefined,
|
|
69
|
+
retryStrategy: this.config.retryStrategy,
|
|
70
|
+
lazyConnect: true,
|
|
71
|
+
});
|
|
72
|
+
// Set up event handlers
|
|
73
|
+
this.client.on('connect', () => {
|
|
74
|
+
this.healthy = true;
|
|
75
|
+
this.log('Connected to Redis');
|
|
76
|
+
});
|
|
77
|
+
this.client.on('error', (error) => {
|
|
78
|
+
this.healthy = false;
|
|
79
|
+
this.log(`Redis error: ${error.message}`);
|
|
80
|
+
});
|
|
81
|
+
this.client.on('close', () => {
|
|
82
|
+
this.healthy = false;
|
|
83
|
+
this.log('Redis connection closed');
|
|
84
|
+
});
|
|
85
|
+
// Connect
|
|
86
|
+
await this.client.connect();
|
|
87
|
+
await this.client.ping();
|
|
88
|
+
this.initialized = true;
|
|
89
|
+
this.healthy = true;
|
|
90
|
+
this.log('Redis backend initialized');
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
this.healthy = false;
|
|
94
|
+
throw new Error(`Failed to initialize Redis backend: ${error.message}`);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
async close() {
|
|
98
|
+
if (this.client) {
|
|
99
|
+
await this.client.quit();
|
|
100
|
+
this.client = null;
|
|
101
|
+
}
|
|
102
|
+
this.initialized = false;
|
|
103
|
+
this.healthy = false;
|
|
104
|
+
this.log('Redis backend closed');
|
|
105
|
+
}
|
|
106
|
+
async isHealthy() {
|
|
107
|
+
if (!this.client || !this.initialized)
|
|
108
|
+
return false;
|
|
109
|
+
try {
|
|
110
|
+
await this.client.ping();
|
|
111
|
+
this.healthy = true;
|
|
112
|
+
return true;
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
this.healthy = false;
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
async get(key) {
|
|
120
|
+
this.ensureClient();
|
|
121
|
+
try {
|
|
122
|
+
const data = await this.client.get(this.prefixKey(key));
|
|
123
|
+
if (!data)
|
|
124
|
+
return null;
|
|
125
|
+
return this.deserialize(data);
|
|
126
|
+
}
|
|
127
|
+
catch (error) {
|
|
128
|
+
this.log(`Get error: ${error.message}`);
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
async set(key, entry) {
|
|
133
|
+
this.ensureClient();
|
|
134
|
+
try {
|
|
135
|
+
const serialized = this.serialize(entry);
|
|
136
|
+
await this.client.setex(this.prefixKey(key), this.config.ttlSeconds, serialized);
|
|
137
|
+
}
|
|
138
|
+
catch (error) {
|
|
139
|
+
this.log(`Set error: ${error.message}`);
|
|
140
|
+
throw error;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
async has(key) {
|
|
144
|
+
this.ensureClient();
|
|
145
|
+
try {
|
|
146
|
+
const exists = await this.client.exists(this.prefixKey(key));
|
|
147
|
+
return exists === 1;
|
|
148
|
+
}
|
|
149
|
+
catch {
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
async delete(key) {
|
|
154
|
+
this.ensureClient();
|
|
155
|
+
try {
|
|
156
|
+
const result = await this.client.del(this.prefixKey(key));
|
|
157
|
+
return result === 1;
|
|
158
|
+
}
|
|
159
|
+
catch {
|
|
160
|
+
return false;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
async clear() {
|
|
164
|
+
this.ensureClient();
|
|
165
|
+
try {
|
|
166
|
+
// Use SCAN to find all keys with our prefix
|
|
167
|
+
const pattern = `${this.config.keyPrefix}*`;
|
|
168
|
+
let cursor = '0';
|
|
169
|
+
const keysToDelete = [];
|
|
170
|
+
do {
|
|
171
|
+
const [nextCursor, keys] = await this.client.scan(cursor, 'MATCH', pattern, 'COUNT', 1000);
|
|
172
|
+
cursor = nextCursor;
|
|
173
|
+
keysToDelete.push(...keys);
|
|
174
|
+
} while (cursor !== '0');
|
|
175
|
+
// Delete in batches
|
|
176
|
+
if (keysToDelete.length > 0) {
|
|
177
|
+
const pipeline = this.client.pipeline();
|
|
178
|
+
for (const key of keysToDelete) {
|
|
179
|
+
pipeline.del(key);
|
|
180
|
+
}
|
|
181
|
+
await pipeline.exec();
|
|
182
|
+
}
|
|
183
|
+
this.log(`Cleared ${keysToDelete.length} keys`);
|
|
184
|
+
}
|
|
185
|
+
catch (error) {
|
|
186
|
+
this.log(`Clear error: ${error.message}`);
|
|
187
|
+
throw error;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
async size() {
|
|
191
|
+
this.ensureClient();
|
|
192
|
+
try {
|
|
193
|
+
const pattern = `${this.config.keyPrefix}*`;
|
|
194
|
+
let cursor = '0';
|
|
195
|
+
let count = 0;
|
|
196
|
+
do {
|
|
197
|
+
const [nextCursor, keys] = await this.client.scan(cursor, 'MATCH', pattern, 'COUNT', 1000);
|
|
198
|
+
cursor = nextCursor;
|
|
199
|
+
count += keys.length;
|
|
200
|
+
} while (cursor !== '0');
|
|
201
|
+
return count;
|
|
202
|
+
}
|
|
203
|
+
catch {
|
|
204
|
+
return 0;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
async *keys() {
|
|
208
|
+
this.ensureClient();
|
|
209
|
+
const pattern = `${this.config.keyPrefix}*`;
|
|
210
|
+
let cursor = '0';
|
|
211
|
+
do {
|
|
212
|
+
const [nextCursor, keys] = await this.client.scan(cursor, 'MATCH', pattern, 'COUNT', 100);
|
|
213
|
+
cursor = nextCursor;
|
|
214
|
+
for (const key of keys) {
|
|
215
|
+
// Remove prefix before yielding
|
|
216
|
+
yield key.substring(this.config.keyPrefix.length);
|
|
217
|
+
}
|
|
218
|
+
} while (cursor !== '0');
|
|
219
|
+
}
|
|
220
|
+
async pruneExpired(_maxAgeMs) {
|
|
221
|
+
// Redis handles TTL expiration automatically
|
|
222
|
+
// This method is a no-op for Redis
|
|
223
|
+
this.log('Redis handles TTL expiration automatically');
|
|
224
|
+
return 0;
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Get backend statistics
|
|
228
|
+
*/
|
|
229
|
+
async getStats() {
|
|
230
|
+
const size = await this.size();
|
|
231
|
+
return {
|
|
232
|
+
name: this.name,
|
|
233
|
+
type: this.type,
|
|
234
|
+
size,
|
|
235
|
+
memoryUsageBytes: size * types_js_1.BYTES_PER_ENTRY,
|
|
236
|
+
healthy: this.healthy,
|
|
237
|
+
lastHealthCheck: new Date(),
|
|
238
|
+
metrics: {
|
|
239
|
+
ttlSeconds: this.config.ttlSeconds,
|
|
240
|
+
db: this.config.db,
|
|
241
|
+
},
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
// ============================================
|
|
245
|
+
// Private Methods
|
|
246
|
+
// ============================================
|
|
247
|
+
prefixKey(key) {
|
|
248
|
+
return `${this.config.keyPrefix}${key}`;
|
|
249
|
+
}
|
|
250
|
+
serialize(entry) {
|
|
251
|
+
// Use MessagePack-style binary encoding for efficiency
|
|
252
|
+
// For now, use JSON (can optimize later)
|
|
253
|
+
return JSON.stringify({
|
|
254
|
+
e: entry.embedding,
|
|
255
|
+
t: entry.timestamp,
|
|
256
|
+
m: entry.model,
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
deserialize(data) {
|
|
260
|
+
const parsed = JSON.parse(data);
|
|
261
|
+
return {
|
|
262
|
+
embedding: parsed.e,
|
|
263
|
+
timestamp: parsed.t,
|
|
264
|
+
model: parsed.m,
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
ensureClient() {
|
|
268
|
+
if (!this.client || !this.initialized) {
|
|
269
|
+
throw new Error('Redis client not initialized. Call initialize() first.');
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
log(message) {
|
|
273
|
+
if (this.config.debug) {
|
|
274
|
+
console.log(`[RedisBackend] ${message}`);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
exports.RedisStorageBackend = RedisStorageBackend;
|
|
279
|
+
//# sourceMappingURL=RedisBackend.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RedisBackend.js","sourceRoot":"","sources":["../../../../src/code-intelligence/embeddings/backends/RedisBackend.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SQLite Storage Backend for Embedding Cache
|
|
3
|
+
*
|
|
4
|
+
* Persistent local storage with efficient binary embedding storage.
|
|
5
|
+
* Best for single-server deployments requiring persistence.
|
|
6
|
+
*
|
|
7
|
+
* @module code-intelligence/embeddings/backends/SQLiteBackend
|
|
8
|
+
* @see Issue #146 - Security Hardening: SP-2 Dedicated Embedding Cache
|
|
9
|
+
*/
|
|
10
|
+
import type { EmbeddingCacheEntry } from '../types.js';
|
|
11
|
+
import type { EmbeddingStorageBackend, SQLiteBackendConfig, BackendStats } from './types.js';
|
|
12
|
+
/**
|
|
13
|
+
* SQLite-based embedding storage backend
|
|
14
|
+
*
|
|
15
|
+
* Features:
|
|
16
|
+
* - Persistent storage across restarts
|
|
17
|
+
* - Efficient binary BLOB storage for embeddings
|
|
18
|
+
* - WAL mode for concurrent access
|
|
19
|
+
* - Indexed timestamp for fast TTL queries
|
|
20
|
+
*/
|
|
21
|
+
export declare class SQLiteStorageBackend implements EmbeddingStorageBackend {
|
|
22
|
+
readonly name = "sqlite";
|
|
23
|
+
readonly type: "sqlite";
|
|
24
|
+
private db;
|
|
25
|
+
private config;
|
|
26
|
+
private initialized;
|
|
27
|
+
private stmtGet;
|
|
28
|
+
private stmtSet;
|
|
29
|
+
private stmtHas;
|
|
30
|
+
private stmtDelete;
|
|
31
|
+
private stmtSize;
|
|
32
|
+
private stmtPrune;
|
|
33
|
+
constructor(config: SQLiteBackendConfig);
|
|
34
|
+
initialize(): Promise<void>;
|
|
35
|
+
close(): Promise<void>;
|
|
36
|
+
isHealthy(): Promise<boolean>;
|
|
37
|
+
get(key: string): Promise<EmbeddingCacheEntry | null>;
|
|
38
|
+
set(key: string, entry: EmbeddingCacheEntry): Promise<void>;
|
|
39
|
+
has(key: string): Promise<boolean>;
|
|
40
|
+
delete(key: string): Promise<boolean>;
|
|
41
|
+
clear(): Promise<void>;
|
|
42
|
+
size(): Promise<number>;
|
|
43
|
+
keys(): AsyncIterable<string>;
|
|
44
|
+
pruneExpired(maxAgeMs: number): Promise<number>;
|
|
45
|
+
/**
|
|
46
|
+
* Get backend statistics
|
|
47
|
+
*/
|
|
48
|
+
getStats(): Promise<BackendStats>;
|
|
49
|
+
/**
|
|
50
|
+
* Run VACUUM to reclaim space
|
|
51
|
+
*/
|
|
52
|
+
vacuum(): Promise<void>;
|
|
53
|
+
/**
|
|
54
|
+
* Get database file size in bytes
|
|
55
|
+
*/
|
|
56
|
+
getDatabaseSize(): Promise<number>;
|
|
57
|
+
private prepareStatements;
|
|
58
|
+
private serializeEmbedding;
|
|
59
|
+
private deserializeEmbedding;
|
|
60
|
+
private isExpired;
|
|
61
|
+
private ensureDb;
|
|
62
|
+
private log;
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=SQLiteBackend.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SQLiteBackend.d.ts","sourceRoot":"","sources":["../../../../src/code-intelligence/embeddings/backends/SQLiteBackend.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,KAAK,EACV,uBAAuB,EACvB,mBAAmB,EACnB,YAAY,EACb,MAAM,YAAY,CAAC;AAapB;;;;;;;;GAQG;AACH,qBAAa,oBAAqB,YAAW,uBAAuB;IAClE,QAAQ,CAAC,IAAI,YAAY;IACzB,QAAQ,CAAC,IAAI,EAAG,QAAQ,CAAU;IAElC,OAAO,CAAC,EAAE,CAAkC;IAC5C,OAAO,CAAC,MAAM,CAAgC;IAC9C,OAAO,CAAC,WAAW,CAAkB;IAGrC,OAAO,CAAC,OAAO,CAAmC;IAClD,OAAO,CAAC,OAAO,CAAmC;IAClD,OAAO,CAAC,OAAO,CAAmC;IAClD,OAAO,CAAC,UAAU,CAAmC;IACrD,OAAO,CAAC,QAAQ,CAAmC;IACnD,OAAO,CAAC,SAAS,CAAmC;gBAExC,MAAM,EAAE,mBAAmB;IAajC,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAqC3B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAqBtB,SAAS,IAAI,OAAO,CAAC,OAAO,CAAC;IAW7B,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC;IA6BrD,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IAY3D,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAelC,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAWrC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAYtB,IAAI,IAAI,OAAO,CAAC,MAAM,CAAC;IAWtB,IAAI,IAAI,aAAa,CAAC,MAAM,CAAC;IAU9B,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAkBrD;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC,YAAY,CAAC;IA2BvC;;OAEG;IACG,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAM7B;;OAEG;IACG,eAAe,IAAI,OAAO,CAAC,MAAM,CAAC;IAiBxC,OAAO,CAAC,iBAAiB;IA4BzB,OAAO,CAAC,kBAAkB;IAS1B,OAAO,CAAC,oBAAoB;IAQ5B,OAAO,CAAC,SAAS;IAKjB,OAAO,CAAC,QAAQ;IAMhB,OAAO,CAAC,GAAG;CAKZ"}
|
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* SQLite Storage Backend for Embedding Cache
|
|
4
|
+
*
|
|
5
|
+
* Persistent local storage with efficient binary embedding storage.
|
|
6
|
+
* Best for single-server deployments requiring persistence.
|
|
7
|
+
*
|
|
8
|
+
* @module code-intelligence/embeddings/backends/SQLiteBackend
|
|
9
|
+
* @see Issue #146 - Security Hardening: SP-2 Dedicated Embedding Cache
|
|
10
|
+
*/
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.SQLiteStorageBackend = void 0;
|
|
16
|
+
const better_sqlite3_1 = __importDefault(require("better-sqlite3"));
|
|
17
|
+
const types_js_1 = require("./types.js");
|
|
18
|
+
/**
|
|
19
|
+
* Default SQLite configuration
|
|
20
|
+
*/
|
|
21
|
+
const DEFAULT_SQLITE_CONFIG = {
|
|
22
|
+
tableName: 'embedding_cache',
|
|
23
|
+
walMode: true,
|
|
24
|
+
busyTimeoutMs: 5000,
|
|
25
|
+
vacuumOnClose: false,
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* SQLite-based embedding storage backend
|
|
29
|
+
*
|
|
30
|
+
* Features:
|
|
31
|
+
* - Persistent storage across restarts
|
|
32
|
+
* - Efficient binary BLOB storage for embeddings
|
|
33
|
+
* - WAL mode for concurrent access
|
|
34
|
+
* - Indexed timestamp for fast TTL queries
|
|
35
|
+
*/
|
|
36
|
+
class SQLiteStorageBackend {
|
|
37
|
+
constructor(config) {
|
|
38
|
+
this.name = 'sqlite';
|
|
39
|
+
this.type = 'sqlite';
|
|
40
|
+
this.db = null;
|
|
41
|
+
this.initialized = false;
|
|
42
|
+
// Prepared statements for performance
|
|
43
|
+
this.stmtGet = null;
|
|
44
|
+
this.stmtSet = null;
|
|
45
|
+
this.stmtHas = null;
|
|
46
|
+
this.stmtDelete = null;
|
|
47
|
+
this.stmtSize = null;
|
|
48
|
+
this.stmtPrune = null;
|
|
49
|
+
this.config = {
|
|
50
|
+
dbPath: config.dbPath,
|
|
51
|
+
tableName: config.tableName ?? DEFAULT_SQLITE_CONFIG.tableName,
|
|
52
|
+
walMode: config.walMode ?? DEFAULT_SQLITE_CONFIG.walMode,
|
|
53
|
+
busyTimeoutMs: config.busyTimeoutMs ?? DEFAULT_SQLITE_CONFIG.busyTimeoutMs,
|
|
54
|
+
vacuumOnClose: config.vacuumOnClose ?? DEFAULT_SQLITE_CONFIG.vacuumOnClose,
|
|
55
|
+
maxSize: config.maxSize ?? 0,
|
|
56
|
+
defaultTtlMs: config.defaultTtlMs ?? types_js_1.DEFAULT_TTL_MS,
|
|
57
|
+
debug: config.debug ?? false,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
async initialize() {
|
|
61
|
+
if (this.initialized)
|
|
62
|
+
return;
|
|
63
|
+
try {
|
|
64
|
+
this.db = new better_sqlite3_1.default(this.config.dbPath);
|
|
65
|
+
// Configure database
|
|
66
|
+
this.db.pragma(`busy_timeout = ${this.config.busyTimeoutMs}`);
|
|
67
|
+
if (this.config.walMode) {
|
|
68
|
+
this.db.pragma('journal_mode = WAL');
|
|
69
|
+
}
|
|
70
|
+
// Create table
|
|
71
|
+
this.db.exec(`
|
|
72
|
+
CREATE TABLE IF NOT EXISTS ${this.config.tableName} (
|
|
73
|
+
key TEXT PRIMARY KEY,
|
|
74
|
+
embedding BLOB NOT NULL,
|
|
75
|
+
model TEXT NOT NULL,
|
|
76
|
+
timestamp INTEGER NOT NULL,
|
|
77
|
+
created_at INTEGER DEFAULT (strftime('%s', 'now'))
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
CREATE INDEX IF NOT EXISTS idx_${this.config.tableName}_timestamp
|
|
81
|
+
ON ${this.config.tableName}(timestamp);
|
|
82
|
+
`);
|
|
83
|
+
// Prepare statements
|
|
84
|
+
this.prepareStatements();
|
|
85
|
+
this.initialized = true;
|
|
86
|
+
this.log('SQLite backend initialized');
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
throw new Error(`Failed to initialize SQLite backend: ${error.message}`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
async close() {
|
|
93
|
+
if (this.db) {
|
|
94
|
+
if (this.config.vacuumOnClose) {
|
|
95
|
+
this.db.exec('VACUUM');
|
|
96
|
+
}
|
|
97
|
+
this.db.close();
|
|
98
|
+
this.db = null;
|
|
99
|
+
}
|
|
100
|
+
// Clear prepared statements
|
|
101
|
+
this.stmtGet = null;
|
|
102
|
+
this.stmtSet = null;
|
|
103
|
+
this.stmtHas = null;
|
|
104
|
+
this.stmtDelete = null;
|
|
105
|
+
this.stmtSize = null;
|
|
106
|
+
this.stmtPrune = null;
|
|
107
|
+
this.initialized = false;
|
|
108
|
+
this.log('SQLite backend closed');
|
|
109
|
+
}
|
|
110
|
+
async isHealthy() {
|
|
111
|
+
if (!this.db || !this.initialized)
|
|
112
|
+
return false;
|
|
113
|
+
try {
|
|
114
|
+
this.db.exec('SELECT 1');
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
async get(key) {
|
|
122
|
+
this.ensureDb();
|
|
123
|
+
try {
|
|
124
|
+
const row = this.stmtGet.get(key);
|
|
125
|
+
if (!row)
|
|
126
|
+
return null;
|
|
127
|
+
// Check if expired
|
|
128
|
+
if (this.isExpired(row.timestamp)) {
|
|
129
|
+
await this.delete(key);
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
return {
|
|
133
|
+
embedding: this.deserializeEmbedding(row.embedding),
|
|
134
|
+
model: row.model,
|
|
135
|
+
timestamp: row.timestamp,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
catch (error) {
|
|
139
|
+
this.log(`Get error: ${error.message}`);
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
async set(key, entry) {
|
|
144
|
+
this.ensureDb();
|
|
145
|
+
try {
|
|
146
|
+
const embeddingBlob = this.serializeEmbedding(entry.embedding);
|
|
147
|
+
this.stmtSet.run(key, embeddingBlob, entry.model, entry.timestamp);
|
|
148
|
+
}
|
|
149
|
+
catch (error) {
|
|
150
|
+
this.log(`Set error: ${error.message}`);
|
|
151
|
+
throw error;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
async has(key) {
|
|
155
|
+
this.ensureDb();
|
|
156
|
+
try {
|
|
157
|
+
const row = this.stmtHas.get(key);
|
|
158
|
+
if (!row || row.count === 0)
|
|
159
|
+
return false;
|
|
160
|
+
// Also check expiration
|
|
161
|
+
const entry = await this.get(key);
|
|
162
|
+
return entry !== null;
|
|
163
|
+
}
|
|
164
|
+
catch {
|
|
165
|
+
return false;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
async delete(key) {
|
|
169
|
+
this.ensureDb();
|
|
170
|
+
try {
|
|
171
|
+
const result = this.stmtDelete.run(key);
|
|
172
|
+
return result.changes > 0;
|
|
173
|
+
}
|
|
174
|
+
catch {
|
|
175
|
+
return false;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
async clear() {
|
|
179
|
+
this.ensureDb();
|
|
180
|
+
try {
|
|
181
|
+
this.db.exec(`DELETE FROM ${this.config.tableName}`);
|
|
182
|
+
this.log('Cache cleared');
|
|
183
|
+
}
|
|
184
|
+
catch (error) {
|
|
185
|
+
this.log(`Clear error: ${error.message}`);
|
|
186
|
+
throw error;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
async size() {
|
|
190
|
+
this.ensureDb();
|
|
191
|
+
try {
|
|
192
|
+
const row = this.stmtSize.get();
|
|
193
|
+
return row?.count ?? 0;
|
|
194
|
+
}
|
|
195
|
+
catch {
|
|
196
|
+
return 0;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
async *keys() {
|
|
200
|
+
this.ensureDb();
|
|
201
|
+
const stmt = this.db.prepare(`SELECT key FROM ${this.config.tableName}`);
|
|
202
|
+
for (const row of stmt.iterate()) {
|
|
203
|
+
yield row.key;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
async pruneExpired(maxAgeMs) {
|
|
207
|
+
this.ensureDb();
|
|
208
|
+
try {
|
|
209
|
+
const threshold = Date.now() - maxAgeMs;
|
|
210
|
+
const result = this.stmtPrune.run(threshold);
|
|
211
|
+
if (result.changes > 0) {
|
|
212
|
+
this.log(`Pruned ${result.changes} expired entries`);
|
|
213
|
+
}
|
|
214
|
+
return result.changes;
|
|
215
|
+
}
|
|
216
|
+
catch (error) {
|
|
217
|
+
this.log(`Prune error: ${error.message}`);
|
|
218
|
+
return 0;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Get backend statistics
|
|
223
|
+
*/
|
|
224
|
+
async getStats() {
|
|
225
|
+
const size = await this.size();
|
|
226
|
+
let dbSizeBytes = 0;
|
|
227
|
+
if (this.db) {
|
|
228
|
+
try {
|
|
229
|
+
const row = this.db.prepare('SELECT page_count * page_size as size FROM pragma_page_count(), pragma_page_size()').get();
|
|
230
|
+
dbSizeBytes = row?.size ?? 0;
|
|
231
|
+
}
|
|
232
|
+
catch {
|
|
233
|
+
dbSizeBytes = size * types_js_1.BYTES_PER_ENTRY;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
return {
|
|
237
|
+
name: this.name,
|
|
238
|
+
type: this.type,
|
|
239
|
+
size,
|
|
240
|
+
memoryUsageBytes: dbSizeBytes,
|
|
241
|
+
healthy: this.initialized,
|
|
242
|
+
lastHealthCheck: new Date(),
|
|
243
|
+
metrics: {
|
|
244
|
+
walMode: this.config.walMode ? 1 : 0,
|
|
245
|
+
defaultTtlMs: this.config.defaultTtlMs,
|
|
246
|
+
},
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Run VACUUM to reclaim space
|
|
251
|
+
*/
|
|
252
|
+
async vacuum() {
|
|
253
|
+
this.ensureDb();
|
|
254
|
+
this.db.exec('VACUUM');
|
|
255
|
+
this.log('VACUUM completed');
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Get database file size in bytes
|
|
259
|
+
*/
|
|
260
|
+
async getDatabaseSize() {
|
|
261
|
+
this.ensureDb();
|
|
262
|
+
try {
|
|
263
|
+
const row = this.db.prepare('SELECT page_count * page_size as size FROM pragma_page_count(), pragma_page_size()').get();
|
|
264
|
+
return row?.size ?? 0;
|
|
265
|
+
}
|
|
266
|
+
catch {
|
|
267
|
+
return 0;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
// ============================================
|
|
271
|
+
// Private Methods
|
|
272
|
+
// ============================================
|
|
273
|
+
prepareStatements() {
|
|
274
|
+
const table = this.config.tableName;
|
|
275
|
+
this.stmtGet = this.db.prepare(`SELECT embedding, model, timestamp FROM ${table} WHERE key = ?`);
|
|
276
|
+
this.stmtSet = this.db.prepare(`INSERT OR REPLACE INTO ${table} (key, embedding, model, timestamp) VALUES (?, ?, ?, ?)`);
|
|
277
|
+
this.stmtHas = this.db.prepare(`SELECT COUNT(*) as count FROM ${table} WHERE key = ?`);
|
|
278
|
+
this.stmtDelete = this.db.prepare(`DELETE FROM ${table} WHERE key = ?`);
|
|
279
|
+
this.stmtSize = this.db.prepare(`SELECT COUNT(*) as count FROM ${table}`);
|
|
280
|
+
this.stmtPrune = this.db.prepare(`DELETE FROM ${table} WHERE timestamp < ?`);
|
|
281
|
+
}
|
|
282
|
+
serializeEmbedding(embedding) {
|
|
283
|
+
// Store as Float64Array for precision
|
|
284
|
+
const buffer = Buffer.alloc(embedding.length * 8);
|
|
285
|
+
for (let i = 0; i < embedding.length; i++) {
|
|
286
|
+
buffer.writeDoubleLE(embedding[i], i * 8);
|
|
287
|
+
}
|
|
288
|
+
return buffer;
|
|
289
|
+
}
|
|
290
|
+
deserializeEmbedding(buffer) {
|
|
291
|
+
const embedding = [];
|
|
292
|
+
for (let i = 0; i < buffer.length; i += 8) {
|
|
293
|
+
embedding.push(buffer.readDoubleLE(i));
|
|
294
|
+
}
|
|
295
|
+
return embedding;
|
|
296
|
+
}
|
|
297
|
+
isExpired(timestamp) {
|
|
298
|
+
if (this.config.defaultTtlMs === 0)
|
|
299
|
+
return false;
|
|
300
|
+
return Date.now() - timestamp > this.config.defaultTtlMs;
|
|
301
|
+
}
|
|
302
|
+
ensureDb() {
|
|
303
|
+
if (!this.db || !this.initialized) {
|
|
304
|
+
throw new Error('SQLite database not initialized. Call initialize() first.');
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
log(message) {
|
|
308
|
+
if (this.config.debug) {
|
|
309
|
+
console.log(`[SQLiteBackend] ${message}`);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
exports.SQLiteStorageBackend = SQLiteStorageBackend;
|
|
314
|
+
//# sourceMappingURL=SQLiteBackend.js.map
|