@sylphx/flow 1.0.1 → 1.0.3

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 (229) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/package.json +10 -9
  3. package/src/commands/codebase-command.ts +168 -0
  4. package/src/commands/flow-command.ts +1137 -0
  5. package/src/commands/flow-orchestrator.ts +296 -0
  6. package/src/commands/hook-command.ts +444 -0
  7. package/src/commands/init-command.ts +92 -0
  8. package/src/commands/init-core.ts +322 -0
  9. package/src/commands/knowledge-command.ts +161 -0
  10. package/src/commands/run-command.ts +120 -0
  11. package/src/components/benchmark-monitor.tsx +331 -0
  12. package/src/components/reindex-progress.tsx +261 -0
  13. package/src/composables/functional/index.ts +14 -0
  14. package/src/composables/functional/useEnvironment.ts +171 -0
  15. package/src/composables/functional/useFileSystem.ts +139 -0
  16. package/src/composables/index.ts +5 -0
  17. package/src/composables/useEnv.ts +13 -0
  18. package/src/composables/useRuntimeConfig.ts +27 -0
  19. package/src/composables/useTargetConfig.ts +45 -0
  20. package/src/config/ai-config.ts +376 -0
  21. package/src/config/constants.ts +35 -0
  22. package/src/config/index.ts +27 -0
  23. package/src/config/rules.ts +43 -0
  24. package/src/config/servers.ts +371 -0
  25. package/src/config/targets.ts +126 -0
  26. package/src/core/agent-loader.ts +141 -0
  27. package/src/core/agent-manager.ts +174 -0
  28. package/src/core/ai-sdk.ts +603 -0
  29. package/src/core/app-factory.ts +381 -0
  30. package/src/core/builtin-agents.ts +9 -0
  31. package/src/core/command-system.ts +550 -0
  32. package/src/core/config-system.ts +550 -0
  33. package/src/core/connection-pool.ts +390 -0
  34. package/src/core/di-container.ts +155 -0
  35. package/src/core/error-handling.ts +519 -0
  36. package/src/core/formatting/bytes.test.ts +115 -0
  37. package/src/core/formatting/bytes.ts +64 -0
  38. package/src/core/functional/async.ts +313 -0
  39. package/src/core/functional/either.ts +109 -0
  40. package/src/core/functional/error-handler.ts +135 -0
  41. package/src/core/functional/error-types.ts +311 -0
  42. package/src/core/functional/index.ts +19 -0
  43. package/src/core/functional/option.ts +142 -0
  44. package/src/core/functional/pipe.ts +189 -0
  45. package/src/core/functional/result.ts +204 -0
  46. package/src/core/functional/validation.ts +138 -0
  47. package/src/core/headless-display.ts +96 -0
  48. package/src/core/index.ts +6 -0
  49. package/src/core/installers/file-installer.ts +303 -0
  50. package/src/core/installers/mcp-installer.ts +213 -0
  51. package/src/core/interfaces/index.ts +22 -0
  52. package/src/core/interfaces/repository.interface.ts +91 -0
  53. package/src/core/interfaces/service.interface.ts +133 -0
  54. package/src/core/interfaces.ts +129 -0
  55. package/src/core/loop-controller.ts +200 -0
  56. package/src/core/result.ts +351 -0
  57. package/src/core/rule-loader.ts +147 -0
  58. package/src/core/rule-manager.ts +240 -0
  59. package/src/core/service-config.ts +252 -0
  60. package/src/core/session-service.ts +121 -0
  61. package/src/core/state-detector.ts +389 -0
  62. package/src/core/storage-factory.ts +115 -0
  63. package/src/core/stream-handler.ts +288 -0
  64. package/src/core/target-manager.ts +161 -0
  65. package/src/core/type-utils.ts +427 -0
  66. package/src/core/unified-storage.ts +456 -0
  67. package/src/core/upgrade-manager.ts +300 -0
  68. package/src/core/validation/limit.test.ts +155 -0
  69. package/src/core/validation/limit.ts +46 -0
  70. package/src/core/validation/query.test.ts +44 -0
  71. package/src/core/validation/query.ts +20 -0
  72. package/src/db/auto-migrate.ts +322 -0
  73. package/src/db/base-database-client.ts +144 -0
  74. package/src/db/cache-db.ts +218 -0
  75. package/src/db/cache-schema.ts +75 -0
  76. package/src/db/database.ts +70 -0
  77. package/src/db/index.ts +252 -0
  78. package/src/db/memory-db.ts +153 -0
  79. package/src/db/memory-schema.ts +29 -0
  80. package/src/db/schema.ts +289 -0
  81. package/src/db/session-repository.ts +733 -0
  82. package/src/domains/codebase/index.ts +5 -0
  83. package/src/domains/codebase/tools.ts +139 -0
  84. package/src/domains/index.ts +8 -0
  85. package/src/domains/knowledge/index.ts +10 -0
  86. package/src/domains/knowledge/resources.ts +537 -0
  87. package/src/domains/knowledge/tools.ts +174 -0
  88. package/src/domains/utilities/index.ts +6 -0
  89. package/src/domains/utilities/time/index.ts +5 -0
  90. package/src/domains/utilities/time/tools.ts +291 -0
  91. package/src/index.ts +211 -0
  92. package/src/services/agent-service.ts +273 -0
  93. package/src/services/claude-config-service.ts +252 -0
  94. package/src/services/config-service.ts +258 -0
  95. package/src/services/evaluation-service.ts +271 -0
  96. package/src/services/functional/evaluation-logic.ts +296 -0
  97. package/src/services/functional/file-processor.ts +273 -0
  98. package/src/services/functional/index.ts +12 -0
  99. package/src/services/index.ts +13 -0
  100. package/src/services/mcp-service.ts +432 -0
  101. package/src/services/memory.service.ts +476 -0
  102. package/src/services/search/base-indexer.ts +156 -0
  103. package/src/services/search/codebase-indexer-types.ts +38 -0
  104. package/src/services/search/codebase-indexer.ts +647 -0
  105. package/src/services/search/embeddings-provider.ts +455 -0
  106. package/src/services/search/embeddings.ts +316 -0
  107. package/src/services/search/functional-indexer.ts +323 -0
  108. package/src/services/search/index.ts +27 -0
  109. package/src/services/search/indexer.ts +380 -0
  110. package/src/services/search/knowledge-indexer.ts +422 -0
  111. package/src/services/search/semantic-search.ts +244 -0
  112. package/src/services/search/tfidf.ts +559 -0
  113. package/src/services/search/unified-search-service.ts +888 -0
  114. package/src/services/smart-config-service.ts +385 -0
  115. package/src/services/storage/cache-storage.ts +487 -0
  116. package/src/services/storage/drizzle-storage.ts +581 -0
  117. package/src/services/storage/index.ts +15 -0
  118. package/src/services/storage/lancedb-vector-storage.ts +494 -0
  119. package/src/services/storage/memory-storage.ts +268 -0
  120. package/src/services/storage/separated-storage.ts +467 -0
  121. package/src/services/storage/vector-storage.ts +13 -0
  122. package/src/shared/agents/index.ts +63 -0
  123. package/src/shared/files/index.ts +99 -0
  124. package/src/shared/index.ts +32 -0
  125. package/src/shared/logging/index.ts +24 -0
  126. package/src/shared/processing/index.ts +153 -0
  127. package/src/shared/types/index.ts +25 -0
  128. package/src/targets/claude-code.ts +574 -0
  129. package/src/targets/functional/claude-code-logic.ts +185 -0
  130. package/src/targets/functional/index.ts +6 -0
  131. package/src/targets/opencode.ts +529 -0
  132. package/src/types/agent.types.ts +32 -0
  133. package/src/types/api/batch.ts +108 -0
  134. package/src/types/api/errors.ts +118 -0
  135. package/src/types/api/index.ts +55 -0
  136. package/src/types/api/requests.ts +76 -0
  137. package/src/types/api/responses.ts +180 -0
  138. package/src/types/api/websockets.ts +85 -0
  139. package/src/types/api.types.ts +9 -0
  140. package/src/types/benchmark.ts +49 -0
  141. package/src/types/cli.types.ts +87 -0
  142. package/src/types/common.types.ts +35 -0
  143. package/src/types/database.types.ts +510 -0
  144. package/src/types/mcp-config.types.ts +448 -0
  145. package/src/types/mcp.types.ts +69 -0
  146. package/src/types/memory-types.ts +63 -0
  147. package/src/types/provider.types.ts +28 -0
  148. package/src/types/rule.types.ts +24 -0
  149. package/src/types/session.types.ts +214 -0
  150. package/src/types/target-config.types.ts +295 -0
  151. package/src/types/target.types.ts +140 -0
  152. package/src/types/todo.types.ts +25 -0
  153. package/src/types.ts +40 -0
  154. package/src/utils/advanced-tokenizer.ts +191 -0
  155. package/src/utils/agent-enhancer.ts +114 -0
  156. package/src/utils/ai-model-fetcher.ts +19 -0
  157. package/src/utils/async-file-operations.ts +516 -0
  158. package/src/utils/audio-player.ts +345 -0
  159. package/src/utils/cli-output.ts +266 -0
  160. package/src/utils/codebase-helpers.ts +211 -0
  161. package/src/utils/console-ui.ts +79 -0
  162. package/src/utils/database-errors.ts +140 -0
  163. package/src/utils/debug-logger.ts +49 -0
  164. package/src/utils/error-handler.ts +53 -0
  165. package/src/utils/file-operations.ts +310 -0
  166. package/src/utils/file-scanner.ts +259 -0
  167. package/src/utils/functional/array.ts +355 -0
  168. package/src/utils/functional/index.ts +15 -0
  169. package/src/utils/functional/object.ts +279 -0
  170. package/src/utils/functional/string.ts +281 -0
  171. package/src/utils/functional.ts +543 -0
  172. package/src/utils/help.ts +20 -0
  173. package/src/utils/immutable-cache.ts +106 -0
  174. package/src/utils/index.ts +78 -0
  175. package/src/utils/jsonc.ts +158 -0
  176. package/src/utils/logger.ts +396 -0
  177. package/src/utils/mcp-config.ts +249 -0
  178. package/src/utils/memory-tui.ts +414 -0
  179. package/src/utils/models-dev.ts +91 -0
  180. package/src/utils/notifications.ts +169 -0
  181. package/src/utils/object-utils.ts +51 -0
  182. package/src/utils/parallel-operations.ts +487 -0
  183. package/src/utils/paths.ts +143 -0
  184. package/src/utils/process-manager.ts +155 -0
  185. package/src/utils/prompts.ts +120 -0
  186. package/src/utils/search-tool-builder.ts +214 -0
  187. package/src/utils/secret-utils.ts +179 -0
  188. package/src/utils/security.ts +537 -0
  189. package/src/utils/session-manager.ts +168 -0
  190. package/src/utils/session-title.ts +87 -0
  191. package/src/utils/settings.ts +182 -0
  192. package/src/utils/simplified-errors.ts +410 -0
  193. package/src/utils/sync-utils.ts +159 -0
  194. package/src/utils/target-config.ts +570 -0
  195. package/src/utils/target-utils.ts +394 -0
  196. package/src/utils/template-engine.ts +94 -0
  197. package/src/utils/test-audio.ts +71 -0
  198. package/src/utils/todo-context.ts +46 -0
  199. package/src/utils/token-counter.ts +288 -0
  200. package/dist/index.d.ts +0 -10
  201. package/dist/index.js +0 -59554
  202. package/dist/lancedb.linux-x64-gnu-b7f0jgsz.node +0 -0
  203. package/dist/lancedb.linux-x64-musl-tgcv22rx.node +0 -0
  204. package/dist/shared/chunk-25dwp0dp.js +0 -89
  205. package/dist/shared/chunk-3pjb6063.js +0 -208
  206. package/dist/shared/chunk-4d6ydpw7.js +0 -2854
  207. package/dist/shared/chunk-4wjcadjk.js +0 -225
  208. package/dist/shared/chunk-5j4w74t6.js +0 -30
  209. package/dist/shared/chunk-5j8m3dh3.js +0 -58
  210. package/dist/shared/chunk-5thh3qem.js +0 -91
  211. package/dist/shared/chunk-6g9xy73m.js +0 -252
  212. package/dist/shared/chunk-7eq34c42.js +0 -23
  213. package/dist/shared/chunk-c2gwgx3r.js +0 -115
  214. package/dist/shared/chunk-cjd3mk4c.js +0 -1320
  215. package/dist/shared/chunk-g5cv6703.js +0 -368
  216. package/dist/shared/chunk-hpkhykhq.js +0 -574
  217. package/dist/shared/chunk-m2322pdk.js +0 -122
  218. package/dist/shared/chunk-nd5fdvaq.js +0 -26
  219. package/dist/shared/chunk-pgd3m6zf.js +0 -108
  220. package/dist/shared/chunk-qk8n91hw.js +0 -494
  221. package/dist/shared/chunk-rkkn8szp.js +0 -16855
  222. package/dist/shared/chunk-t16rfxh0.js +0 -61
  223. package/dist/shared/chunk-t4fbfa5v.js +0 -19
  224. package/dist/shared/chunk-t77h86w6.js +0 -276
  225. package/dist/shared/chunk-v0ez4aef.js +0 -71
  226. package/dist/shared/chunk-v29j2r3s.js +0 -32051
  227. package/dist/shared/chunk-vfbc6ew5.js +0 -765
  228. package/dist/shared/chunk-vmeqwm1c.js +0 -204
  229. package/dist/shared/chunk-x66eh37x.js +0 -137
@@ -0,0 +1,390 @@
1
+ /**
2
+ * Database Connection Pool
3
+ *
4
+ * Manages a pool of database connections for better performance and resource management
5
+ */
6
+
7
+ export interface ConnectionConfig {
8
+ maxConnections?: number;
9
+ minConnections?: number;
10
+ acquireTimeout?: number;
11
+ idleTimeout?: number;
12
+ maxLifetime?: number;
13
+ healthCheckInterval?: number;
14
+ }
15
+
16
+ export interface Connection<T = any> {
17
+ id: string;
18
+ instance: T;
19
+ createdAt: number;
20
+ lastUsed: number;
21
+ isInUse: boolean;
22
+ isHealthy: boolean;
23
+ }
24
+
25
+ export interface ConnectionPoolInstance<T> {
26
+ acquire(): Promise<T>;
27
+ release(connectionInstance: T): Promise<void>;
28
+ getStats(): {
29
+ totalConnections: number;
30
+ activeConnections: number;
31
+ idleConnections: number;
32
+ unhealthyConnections: number;
33
+ maxConnections?: number;
34
+ minConnections?: number;
35
+ };
36
+ dispose(): Promise<void>;
37
+ }
38
+
39
+ /**
40
+ * Create a connection pool for database connections
41
+ */
42
+ export function createConnectionPool<T>(
43
+ createConnection: () => Promise<T>,
44
+ destroyConnection: (connection: T) => Promise<void>,
45
+ healthCheck: (connection: T) => Promise<boolean>,
46
+ configInput: ConnectionConfig = {}
47
+ ): ConnectionPoolInstance<T> {
48
+ // Closure-based state
49
+ const connections = new Map<string, Connection<T>>();
50
+ let availableConnections: string[] = [];
51
+ let connectionCount = 0;
52
+ let healthCheckTimer: NodeJS.Timeout | undefined;
53
+ let isDisposing = false;
54
+
55
+ const config: Required<ConnectionConfig> = {
56
+ maxConnections: 10,
57
+ minConnections: 2,
58
+ acquireTimeout: 30000,
59
+ idleTimeout: 300000,
60
+ maxLifetime: 3600000,
61
+ healthCheckInterval: 60000,
62
+ ...configInput,
63
+ };
64
+
65
+ /**
66
+ * Generate a unique connection ID
67
+ */
68
+ const generateConnectionId = (): string => {
69
+ return `conn_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
70
+ };
71
+
72
+ /**
73
+ * Check if a connection is valid
74
+ */
75
+ const isConnectionValid = (connection: Connection<T>): boolean => {
76
+ const now = Date.now();
77
+
78
+ // Check age
79
+ if (now - connection.createdAt > config.maxLifetime) {
80
+ return false;
81
+ }
82
+
83
+ // Check if it's idle for too long (but only if not in use)
84
+ if (!connection.isInUse && now - connection.lastUsed > config.idleTimeout) {
85
+ return false;
86
+ }
87
+
88
+ // Check health
89
+ return connection.isHealthy;
90
+ };
91
+
92
+ /**
93
+ * Create a new connection
94
+ */
95
+ const createNewConnection = async (): Promise<T> => {
96
+ const startTime = Date.now();
97
+ const connectionInstance = await createConnection();
98
+ const createTime = Date.now() - startTime;
99
+
100
+ const connection: Connection<T> = {
101
+ id: generateConnectionId(),
102
+ instance: connectionInstance,
103
+ createdAt: Date.now(),
104
+ lastUsed: Date.now(),
105
+ isInUse: true,
106
+ isHealthy: true,
107
+ };
108
+
109
+ connections.set(connection.id, connection);
110
+ connectionCount++;
111
+
112
+ console.debug(
113
+ `New connection created in ${createTime}ms, total connections: ${connectionCount}`
114
+ );
115
+ return connectionInstance;
116
+ };
117
+
118
+ /**
119
+ * Wait for a connection to become available
120
+ */
121
+ const waitForConnection = async (): Promise<T> => {
122
+ const timeout = config.acquireTimeout;
123
+ const startTime = Date.now();
124
+
125
+ return new Promise((resolve, reject) => {
126
+ const checkInterval = setInterval(() => {
127
+ if (isDisposing) {
128
+ clearInterval(checkInterval);
129
+ reject(new Error('Connection pool is disposing'));
130
+ return;
131
+ }
132
+
133
+ if (availableConnections.length > 0) {
134
+ clearInterval(checkInterval);
135
+ const connectionId = availableConnections.shift()!;
136
+ const connection = connections.get(connectionId)!;
137
+
138
+ if (isConnectionValid(connection)) {
139
+ connection.isInUse = true;
140
+ connection.lastUsed = Date.now();
141
+ resolve(connection.instance);
142
+ } else {
143
+ // Remove invalid connection and try again
144
+ connections.delete(connectionId);
145
+ connectionCount--;
146
+ destroyConnection(connection.instance).catch(console.error);
147
+ return;
148
+ }
149
+ }
150
+
151
+ // Check timeout
152
+ if (Date.now() - startTime > timeout) {
153
+ clearInterval(checkInterval);
154
+ reject(new Error('Connection acquire timeout'));
155
+ }
156
+ }, 100);
157
+ });
158
+ };
159
+
160
+ /**
161
+ * Maintain minimum connections
162
+ */
163
+ const maintainMinConnections = async (): Promise<void> => {
164
+ const minConnections = config.minConnections;
165
+ const availableCount = availableConnections.length;
166
+
167
+ if (availableCount < minConnections && connectionCount < config.maxConnections) {
168
+ const needed = minConnections - availableCount;
169
+ for (let i = 0; i < needed; i++) {
170
+ createNewConnection()
171
+ .then((connection) => release(connection))
172
+ .catch((error) => console.error('Failed to maintain minimum connection:', error));
173
+ }
174
+ }
175
+ };
176
+
177
+ /**
178
+ * Start health check timer
179
+ */
180
+ const startHealthCheck = (): void => {
181
+ const interval = config.healthCheckInterval;
182
+
183
+ healthCheckTimer = setInterval(async () => {
184
+ if (isDisposing) {
185
+ return;
186
+ }
187
+
188
+ for (const [id, connection] of connections) {
189
+ try {
190
+ const isHealthy = await healthCheck(connection.instance);
191
+
192
+ if (isHealthy) {
193
+ connection.isHealthy = true;
194
+ } else {
195
+ connection.isHealthy = false;
196
+ console.warn(`Connection ${id} failed health check`);
197
+
198
+ // Remove unhealthy connection if not in use
199
+ if (!connection.isInUse) {
200
+ connections.delete(id);
201
+ connectionCount--;
202
+ const index = availableConnections.indexOf(id);
203
+ if (index > -1) {
204
+ availableConnections.splice(index, 1);
205
+ }
206
+ await destroyConnection(connection.instance);
207
+ }
208
+ }
209
+ } catch (error) {
210
+ console.error(`Health check failed for connection ${id}:`, error);
211
+ connection.isHealthy = false;
212
+ }
213
+ }
214
+
215
+ // Maintain minimum connections
216
+ await maintainMinConnections();
217
+ }, interval);
218
+ };
219
+
220
+ /**
221
+ * Initialize minimum connections
222
+ */
223
+ const initializeMinConnections = async (): Promise<void> => {
224
+ const minConnections = config.minConnections;
225
+ const promises = [];
226
+
227
+ for (let i = 0; i < minConnections; i++) {
228
+ promises.push(
229
+ createNewConnection()
230
+ .then((connection) => release(connection))
231
+ .catch((error) => console.error('Failed to initialize minimum connection:', error))
232
+ );
233
+ }
234
+
235
+ await Promise.all(promises);
236
+ };
237
+
238
+ /**
239
+ * Acquire a connection from the pool
240
+ */
241
+ const acquire = async (): Promise<T> => {
242
+ if (isDisposing) {
243
+ throw new Error('Connection pool is disposing');
244
+ }
245
+
246
+ // Try to get an available connection
247
+ while (availableConnections.length > 0) {
248
+ const connectionId = availableConnections.shift()!;
249
+ const connection = connections.get(connectionId)!;
250
+
251
+ if (isConnectionValid(connection)) {
252
+ connection.isInUse = true;
253
+ connection.lastUsed = Date.now();
254
+ return connection.instance;
255
+ }
256
+ // Remove invalid connection
257
+ connections.delete(connectionId);
258
+ connectionCount--;
259
+ await destroyConnection(connection.instance);
260
+ }
261
+
262
+ // Create new connection if under limit
263
+ if (connectionCount < config.maxConnections) {
264
+ return await createNewConnection();
265
+ }
266
+
267
+ // Wait for a connection to become available
268
+ return await waitForConnection();
269
+ };
270
+
271
+ /**
272
+ * Release a connection back to the pool
273
+ */
274
+ const release = async (connectionInstance: T): Promise<void> => {
275
+ for (const [id, connection] of connections) {
276
+ if (connection.instance === connectionInstance) {
277
+ connection.isInUse = false;
278
+ connection.lastUsed = Date.now();
279
+ availableConnections.push(id);
280
+ return;
281
+ }
282
+ }
283
+
284
+ // Connection not found in pool, destroy it
285
+ await destroyConnection(connectionInstance);
286
+ };
287
+
288
+ /**
289
+ * Get pool statistics
290
+ */
291
+ const getStats = () => {
292
+ const activeConnections = Array.from(connections.values()).filter((c) => c.isInUse).length;
293
+ const idleConnections = availableConnections.length;
294
+ const unhealthyConnections = Array.from(connections.values()).filter(
295
+ (c) => !c.isHealthy
296
+ ).length;
297
+
298
+ return {
299
+ totalConnections: connectionCount,
300
+ activeConnections,
301
+ idleConnections,
302
+ unhealthyConnections,
303
+ maxConnections: config.maxConnections,
304
+ minConnections: config.minConnections,
305
+ };
306
+ };
307
+
308
+ /**
309
+ * Close all connections and dispose the pool
310
+ */
311
+ const dispose = async (): Promise<void> => {
312
+ isDisposing = true;
313
+
314
+ if (healthCheckTimer) {
315
+ clearInterval(healthCheckTimer);
316
+ healthCheckTimer = undefined;
317
+ }
318
+
319
+ const destroyPromises = Array.from(connections.values()).map(async (connection) => {
320
+ try {
321
+ await destroyConnection(connection.instance);
322
+ } catch (error) {
323
+ console.error('Error destroying connection during pool disposal:', error);
324
+ }
325
+ });
326
+
327
+ await Promise.all(destroyPromises);
328
+
329
+ connections.clear();
330
+ availableConnections = [];
331
+ connectionCount = 0;
332
+
333
+ console.log('Connection pool disposed');
334
+ };
335
+
336
+ // Initialize pool
337
+ startHealthCheck();
338
+ initializeMinConnections();
339
+
340
+ return {
341
+ acquire,
342
+ release,
343
+ getStats,
344
+ dispose,
345
+ };
346
+ }
347
+
348
+ /**
349
+ * @deprecated Use createConnectionPool() for new code
350
+ */
351
+ export class ConnectionPool<T> {
352
+ private instance: ConnectionPoolInstance<T>;
353
+
354
+ constructor(
355
+ createConnection: () => Promise<T>,
356
+ destroyConnection: (connection: T) => Promise<void>,
357
+ healthCheck: (connection: T) => Promise<boolean>,
358
+ config: ConnectionConfig = {}
359
+ ) {
360
+ this.instance = createConnectionPool(createConnection, destroyConnection, healthCheck, config);
361
+ }
362
+
363
+ async acquire(): Promise<T> {
364
+ return this.instance.acquire();
365
+ }
366
+
367
+ async release(connectionInstance: T): Promise<void> {
368
+ return this.instance.release(connectionInstance);
369
+ }
370
+
371
+ getStats() {
372
+ return this.instance.getStats();
373
+ }
374
+
375
+ async dispose(): Promise<void> {
376
+ return this.instance.dispose();
377
+ }
378
+ }
379
+
380
+ /**
381
+ * Create a connection pool for database connections
382
+ */
383
+ export function createDatabaseConnectionPool(
384
+ createDbConnection: () => Promise<any>,
385
+ destroyDbConnection: (connection: any) => Promise<void>,
386
+ healthCheckFn: (connection: any) => Promise<boolean>,
387
+ config?: ConnectionConfig
388
+ ): ConnectionPoolInstance<any> {
389
+ return createConnectionPool(createDbConnection, destroyDbConnection, healthCheckFn, config);
390
+ }
@@ -0,0 +1,155 @@
1
+ /**
2
+ * Lightweight Dependency Injection Container
3
+ *
4
+ * A minimal DI container focusing on core services: database, logging, configuration
5
+ * Uses constructor injection pattern for better testability
6
+ */
7
+
8
+ export type ServiceFactory<T> = () => T | Promise<T>;
9
+ export type ServiceLifetime = 'singleton' | 'transient' | 'scoped';
10
+
11
+ export interface ServiceDescriptor<T = any> {
12
+ factory: ServiceFactory<T>;
13
+ lifetime: ServiceLifetime;
14
+ instance?: T;
15
+ isResolved?: boolean;
16
+ }
17
+
18
+ export class DIContainer {
19
+ private services = new Map<string, ServiceDescriptor>();
20
+ private scopedInstances = new Map<string, any>();
21
+
22
+ /**
23
+ * Register a service with the container
24
+ */
25
+ register<T>(
26
+ token: string,
27
+ factory: ServiceFactory<T>,
28
+ lifetime: ServiceLifetime = 'singleton'
29
+ ): void {
30
+ this.services.set(token, {
31
+ factory,
32
+ lifetime,
33
+ isResolved: false,
34
+ });
35
+ }
36
+
37
+ /**
38
+ * Register a singleton instance
39
+ */
40
+ registerInstance<T>(token: string, instance: T): void {
41
+ this.services.set(token, {
42
+ factory: () => instance,
43
+ lifetime: 'singleton',
44
+ instance,
45
+ isResolved: true,
46
+ });
47
+ }
48
+
49
+ /**
50
+ * Resolve a service from the container
51
+ */
52
+ async resolve<T>(token: string): Promise<T> {
53
+ const descriptor = this.services.get(token);
54
+
55
+ if (!descriptor) {
56
+ throw new Error(`Service not registered: ${token}`);
57
+ }
58
+
59
+ switch (descriptor.lifetime) {
60
+ case 'singleton':
61
+ return this.resolveSingleton<T>(descriptor);
62
+ case 'transient':
63
+ return this.resolveTransient<T>(descriptor);
64
+ case 'scoped':
65
+ return this.resolveScoped<T>(token, descriptor);
66
+ default:
67
+ throw new Error(`Unsupported service lifetime: ${descriptor.lifetime}`);
68
+ }
69
+ }
70
+
71
+ /**
72
+ * Check if a service is registered
73
+ */
74
+ isRegistered(token: string): boolean {
75
+ return this.services.has(token);
76
+ }
77
+
78
+ /**
79
+ * Create a new scope for scoped services
80
+ */
81
+ createScope(): DIContainer {
82
+ const scope = new DIContainer();
83
+ // Copy all service descriptors but not instances
84
+ for (const [token, descriptor] of this.services) {
85
+ scope.services.set(token, { ...descriptor });
86
+ }
87
+ return scope;
88
+ }
89
+
90
+ /**
91
+ * Clear scoped instances (useful for request cleanup)
92
+ */
93
+ clearScope(): void {
94
+ this.scopedInstances.clear();
95
+ }
96
+
97
+ /**
98
+ * Dispose all singleton services that have dispose method
99
+ */
100
+ async dispose(): Promise<void> {
101
+ for (const descriptor of this.services.values()) {
102
+ if (descriptor.instance && typeof descriptor.instance.dispose === 'function') {
103
+ try {
104
+ await descriptor.instance.dispose();
105
+ } catch (error) {
106
+ console.error('Error disposing service:', error);
107
+ }
108
+ }
109
+ }
110
+ this.services.clear();
111
+ this.scopedInstances.clear();
112
+ }
113
+
114
+ private async resolveSingleton<T>(descriptor: ServiceDescriptor<T>): Promise<T> {
115
+ if (descriptor.isResolved && descriptor.instance) {
116
+ return descriptor.instance;
117
+ }
118
+
119
+ const instance = await descriptor.factory();
120
+ descriptor.instance = instance;
121
+ descriptor.isResolved = true;
122
+
123
+ return instance;
124
+ }
125
+
126
+ private async resolveTransient<T>(descriptor: ServiceDescriptor<T>): Promise<T> {
127
+ return await descriptor.factory();
128
+ }
129
+
130
+ private async resolveScoped<T>(token: string, descriptor: ServiceDescriptor<T>): Promise<T> {
131
+ if (this.scopedInstances.has(token)) {
132
+ return this.scopedInstances.get(token);
133
+ }
134
+
135
+ const instance = await descriptor.factory();
136
+ this.scopedInstances.set(token, instance);
137
+
138
+ return instance;
139
+ }
140
+ }
141
+
142
+ // Global container instance
143
+ export const container = new DIContainer();
144
+
145
+ // Service tokens constants
146
+ export const SERVICE_TOKENS = {
147
+ DATABASE: 'database',
148
+ LOGGER: 'logger',
149
+ CONFIG: 'config',
150
+ MEMORY_STORAGE: 'memoryStorage',
151
+ SEARCH_SERVICE: 'searchService',
152
+ MCP_SERVICE: 'mcpService',
153
+ EMBEDDING_PROVIDER: 'embeddingProvider',
154
+ TARGET_MANAGER: 'targetManager',
155
+ } as const;