@sylphx/flow 1.1.1 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/package.json +1 -1
  3. package/src/commands/flow-command.ts +28 -0
  4. package/src/commands/hook-command.ts +10 -230
  5. package/src/composables/index.ts +0 -1
  6. package/src/config/servers.ts +35 -78
  7. package/src/core/interfaces.ts +0 -33
  8. package/src/domains/index.ts +0 -2
  9. package/src/index.ts +0 -4
  10. package/src/services/mcp-service.ts +0 -16
  11. package/src/targets/claude-code.ts +3 -9
  12. package/src/targets/functional/claude-code-logic.ts +4 -22
  13. package/src/targets/opencode.ts +0 -6
  14. package/src/types/mcp.types.ts +29 -38
  15. package/src/types/target.types.ts +0 -2
  16. package/src/types.ts +0 -1
  17. package/src/utils/sync-utils.ts +106 -0
  18. package/src/commands/codebase-command.ts +0 -168
  19. package/src/commands/knowledge-command.ts +0 -161
  20. package/src/composables/useTargetConfig.ts +0 -45
  21. package/src/core/formatting/bytes.test.ts +0 -115
  22. package/src/core/validation/limit.test.ts +0 -155
  23. package/src/core/validation/query.test.ts +0 -44
  24. package/src/domains/codebase/index.ts +0 -5
  25. package/src/domains/codebase/tools.ts +0 -139
  26. package/src/domains/knowledge/index.ts +0 -10
  27. package/src/domains/knowledge/resources.ts +0 -537
  28. package/src/domains/knowledge/tools.ts +0 -174
  29. package/src/services/search/base-indexer.ts +0 -156
  30. package/src/services/search/codebase-indexer-types.ts +0 -38
  31. package/src/services/search/codebase-indexer.ts +0 -647
  32. package/src/services/search/embeddings-provider.ts +0 -455
  33. package/src/services/search/embeddings.ts +0 -316
  34. package/src/services/search/functional-indexer.ts +0 -323
  35. package/src/services/search/index.ts +0 -27
  36. package/src/services/search/indexer.ts +0 -380
  37. package/src/services/search/knowledge-indexer.ts +0 -422
  38. package/src/services/search/semantic-search.ts +0 -244
  39. package/src/services/search/tfidf.ts +0 -559
  40. package/src/services/search/unified-search-service.ts +0 -888
  41. package/src/services/storage/cache-storage.ts +0 -487
  42. package/src/services/storage/drizzle-storage.ts +0 -581
  43. package/src/services/storage/index.ts +0 -15
  44. package/src/services/storage/lancedb-vector-storage.ts +0 -494
  45. package/src/services/storage/memory-storage.ts +0 -268
  46. package/src/services/storage/separated-storage.ts +0 -467
  47. package/src/services/storage/vector-storage.ts +0 -13
@@ -1,494 +0,0 @@
1
- /**
2
- * Simple LanceDB vector storage implementation
3
- * Local-only, no cloud services required
4
- */
5
-
6
- import { logger } from '../../utils/logger.js';
7
-
8
- /**
9
- * Generate mock embedding for testing/fallback
10
- */
11
- export function generateMockEmbedding(text: string, dimensions = 1536): number[] {
12
- const words = text.toLowerCase().split(/\s+/);
13
- const embedding = new Array(dimensions).fill(0);
14
-
15
- // Simple hash-based pseudo-embedding
16
- for (const word of words) {
17
- let hash = 0;
18
- for (let i = 0; i < word.length; i++) {
19
- hash = (hash << 5) - hash + word.charCodeAt(i);
20
- hash &= hash; // Convert to 32-bit integer
21
- }
22
-
23
- // Distribute hash across embedding dimensions
24
- for (let i = 0; i < dimensions; i++) {
25
- embedding[i] += Math.sin(hash * (i + 1)) * 0.1;
26
- }
27
- }
28
-
29
- // Normalize the embedding
30
- const norm = Math.sqrt(embedding.reduce((sum, val) => sum + val * val, 0));
31
- if (norm > 0) {
32
- return embedding.map((val) => val / norm);
33
- }
34
-
35
- return embedding;
36
- }
37
-
38
- import fs from 'node:fs';
39
- import path from 'node:path';
40
- import * as lancedb from '@lancedb/lancedb';
41
-
42
- export interface VectorDocument {
43
- id: string;
44
- embedding: number[];
45
- metadata: {
46
- type: 'knowledge' | 'code';
47
- content: string;
48
- category: string;
49
- language: string;
50
- [key: string]: string | number | boolean;
51
- };
52
- }
53
-
54
- export interface VectorStorageMetadata {
55
- dimensions: number;
56
- count: number;
57
- }
58
-
59
- export interface VectorSearchResult {
60
- doc: VectorDocument;
61
- similarity: number;
62
- }
63
-
64
- /**
65
- * LanceDB vector storage - Local only, no cloud services
66
- */
67
- export class VectorStorage {
68
- private db: any = null;
69
- private table: any = null;
70
- private metadata: VectorStorageMetadata;
71
- private indexPath: string;
72
- private dimensions: number;
73
- private tableName = 'vectors';
74
-
75
- constructor(indexPath: string, dimensions: number) {
76
- this.indexPath = indexPath;
77
- this.dimensions = dimensions;
78
-
79
- this.metadata = {
80
- dimensions,
81
- count: 0,
82
- };
83
- }
84
-
85
- /**
86
- * Initialize the database connection
87
- */
88
- async initialize(): Promise<void> {
89
- if (this.db) {
90
- return;
91
- }
92
-
93
- try {
94
- // Ensure directory exists
95
- const dir = path.dirname(this.indexPath);
96
- if (!fs.existsSync(dir)) {
97
- fs.mkdirSync(dir, { recursive: true });
98
- }
99
-
100
- // Connect to LanceDB (local only)
101
- this.db = await lancedb.connect(this.indexPath);
102
-
103
- // Check if table exists
104
- const tables = await this.db.tableNames();
105
- if (tables.includes(this.tableName)) {
106
- this.table = await this.db.openTable(this.tableName);
107
-
108
- // Update count
109
- try {
110
- this.metadata.count = await this.table.countRows();
111
- logger.info('Loaded LanceDB table', { count: this.metadata.count });
112
- } catch (_e) {
113
- this.metadata.count = 0;
114
- }
115
- } else {
116
- // Create simple table
117
- const data = [
118
- {
119
- id: 'init',
120
- vector: new Array(this.dimensions).fill(0),
121
- type: 'code',
122
- content: '',
123
- category: '',
124
- language: '',
125
- },
126
- ];
127
-
128
- this.table = await this.db.createTable(this.tableName, data);
129
-
130
- // Remove the init record
131
- await this.table.delete('id = ?', ['init']);
132
-
133
- logger.info('Created new LanceDB table', { tableName: this.tableName });
134
- }
135
- } catch (error) {
136
- logger.error('Failed to initialize LanceDB', { error });
137
- // Fallback to simple in-memory storage
138
- this.useFallback = true;
139
- }
140
- }
141
-
142
- private useFallback = false;
143
- private fallbackData: Map<string, VectorDocument> = new Map();
144
-
145
- /**
146
- * Save index to disk
147
- */
148
- async save(): Promise<void> {
149
- if (this.useFallback) {
150
- logger.warn('Using fallback storage - save is no-op');
151
- return;
152
- }
153
-
154
- // LanceDB automatically saves
155
- logger.debug('LanceDB saves automatically');
156
- }
157
-
158
- /**
159
- * Add document to index
160
- */
161
- async addDocument(doc: VectorDocument): Promise<void> {
162
- if (doc.embedding.length !== this.dimensions) {
163
- throw new Error(
164
- `Embedding dimension mismatch: expected ${this.dimensions}, got ${doc.embedding.length}`
165
- );
166
- }
167
-
168
- if (this.useFallback) {
169
- this.fallbackData.set(doc.id, doc);
170
- this.metadata.count = this.fallbackData.size;
171
- return;
172
- }
173
-
174
- await this.initialize();
175
-
176
- try {
177
- // Add to LanceDB
178
- await this.table.add([
179
- {
180
- id: doc.id,
181
- vector: doc.embedding,
182
- type: doc.metadata.type,
183
- content: doc.metadata.content,
184
- category: doc.metadata.category,
185
- language: doc.metadata.language,
186
- },
187
- ]);
188
-
189
- this.metadata.count++;
190
- } catch (error) {
191
- logger.error('Failed to add document, falling back', { error });
192
- this.useFallback = true;
193
- this.fallbackData.set(doc.id, doc);
194
- this.metadata.count = this.fallbackData.size;
195
- }
196
- }
197
-
198
- /**
199
- * Add multiple documents
200
- */
201
- async addDocuments(docs: VectorDocument[]): Promise<void> {
202
- if (docs.length === 0) {
203
- return;
204
- }
205
-
206
- // Validate all documents
207
- for (const doc of docs) {
208
- if (doc.embedding.length !== this.dimensions) {
209
- throw new Error(
210
- `Embedding dimension mismatch: expected ${this.dimensions}, got ${doc.embedding.length}`
211
- );
212
- }
213
- }
214
-
215
- if (this.useFallback) {
216
- for (const doc of docs) {
217
- this.fallbackData.set(doc.id, doc);
218
- }
219
- this.metadata.count = this.fallbackData.size;
220
- return;
221
- }
222
-
223
- await this.initialize();
224
-
225
- try {
226
- // Convert to LanceDB format
227
- const records = docs.map((doc) => ({
228
- id: doc.id,
229
- vector: doc.embedding,
230
- type: doc.metadata.type,
231
- content: doc.metadata.content,
232
- category: doc.metadata.category,
233
- language: doc.metadata.language,
234
- }));
235
-
236
- // Batch add to LanceDB
237
- await this.table.add(records);
238
- this.metadata.count += docs.length;
239
-
240
- logger.info('Added documents to LanceDB', { count: docs.length });
241
- } catch (error) {
242
- logger.error('Failed to add documents, falling back', { error });
243
- this.useFallback = true;
244
- for (const doc of docs) {
245
- this.fallbackData.set(doc.id, doc);
246
- }
247
- this.metadata.count = this.fallbackData.size;
248
- }
249
- }
250
-
251
- /**
252
- * Search for similar documents
253
- */
254
- async search(
255
- queryEmbedding: number[],
256
- options: {
257
- k?: number;
258
- filter?: (doc: VectorDocument) => boolean;
259
- } = {}
260
- ): Promise<VectorSearchResult[]> {
261
- if (queryEmbedding.length !== this.dimensions) {
262
- throw new Error(
263
- `Query embedding dimension mismatch: expected ${this.dimensions}, got ${queryEmbedding.length}`
264
- );
265
- }
266
-
267
- const { k = 5, filter } = options;
268
-
269
- if (this.useFallback) {
270
- // Simple fallback search
271
- const results: VectorSearchResult[] = [];
272
-
273
- for (const doc of this.fallbackData.values()) {
274
- if (filter && !filter(doc)) {
275
- continue;
276
- }
277
-
278
- const similarity = this.cosineSimilarity(queryEmbedding, doc.embedding);
279
- results.push({ doc, similarity });
280
- }
281
-
282
- return results.sort((a, b) => b.similarity - a.similarity).slice(0, k);
283
- }
284
-
285
- await this.initialize();
286
-
287
- try {
288
- // Search LanceDB
289
- const query = this.table.vectorSearch(queryEmbedding).limit(k * 2);
290
- const results = await query.toArray();
291
-
292
- const filteredResults: VectorSearchResult[] = [];
293
-
294
- for (const result of results) {
295
- // Convert back to our format
296
- const doc: VectorDocument = {
297
- id: result.id,
298
- embedding: result.vector,
299
- metadata: {
300
- type: result.type as 'knowledge' | 'code',
301
- content: result.content || '',
302
- category: result.category || '',
303
- language: result.language || '',
304
- },
305
- };
306
-
307
- // Apply filter if provided
308
- if (filter && !filter(doc)) {
309
- continue;
310
- }
311
-
312
- // Convert distance to similarity
313
- const distance = result._distance || 0;
314
- const similarity = 1 / (1 + distance);
315
-
316
- filteredResults.push({
317
- doc,
318
- similarity,
319
- });
320
-
321
- // Stop if we have enough results
322
- if (filteredResults.length >= k) {
323
- break;
324
- }
325
- }
326
-
327
- return filteredResults;
328
- } catch (error) {
329
- logger.error('Vector search failed, falling back', { error });
330
- // Fallback to simple search
331
- return this.search(queryEmbedding, options);
332
- }
333
- }
334
-
335
- /**
336
- * Get document by ID
337
- */
338
- async getDocument(id: string): Promise<VectorDocument | undefined> {
339
- if (this.useFallback) {
340
- return this.fallbackData.get(id);
341
- }
342
-
343
- await this.initialize();
344
-
345
- try {
346
- // Simple scan for now (LanceDB API might be different)
347
- const results = await this.table.limit(1000).toArray();
348
- const result = results.find((r: any) => r.id === id);
349
-
350
- if (!result) {
351
- return undefined;
352
- }
353
-
354
- return {
355
- id: result.id,
356
- embedding: result.vector,
357
- metadata: {
358
- type: result.type as 'knowledge' | 'code',
359
- content: result.content || '',
360
- category: result.category || '',
361
- language: result.language || '',
362
- },
363
- };
364
- } catch (error) {
365
- logger.error('Failed to get document', { error });
366
- return this.fallbackData.get(id);
367
- }
368
- }
369
-
370
- /**
371
- * Get all documents
372
- */
373
- async getAllDocuments(): Promise<VectorDocument[]> {
374
- if (this.useFallback) {
375
- return Array.from(this.fallbackData.values());
376
- }
377
-
378
- await this.initialize();
379
-
380
- try {
381
- const results = await this.table.toArray();
382
- return results.map((result: any) => ({
383
- id: result.id,
384
- embedding: result.vector,
385
- metadata: {
386
- type: result.type as 'knowledge' | 'code',
387
- content: result.content || '',
388
- category: result.category || '',
389
- language: result.language || '',
390
- },
391
- }));
392
- } catch (error) {
393
- logger.error('Failed to get all documents', { error });
394
- return Array.from(this.fallbackData.values());
395
- }
396
- }
397
-
398
- /**
399
- * Get metadata
400
- */
401
- getMetadata(): VectorStorageMetadata {
402
- return { ...this.metadata };
403
- }
404
-
405
- /**
406
- * Clear all documents
407
- */
408
- async clear(): Promise<void> {
409
- if (this.useFallback) {
410
- this.fallbackData.clear();
411
- this.metadata.count = 0;
412
- return;
413
- }
414
-
415
- await this.initialize();
416
-
417
- try {
418
- await this.db.dropTable(this.tableName);
419
-
420
- // Recreate empty table
421
- const data = [
422
- {
423
- id: 'init',
424
- vector: new Array(this.dimensions).fill(0),
425
- type: 'code',
426
- content: '',
427
- category: '',
428
- language: '',
429
- },
430
- ];
431
-
432
- this.table = await this.db.createTable(this.tableName, data);
433
- await this.table.delete('id = ?', ['init']);
434
-
435
- this.metadata.count = 0;
436
- logger.info('Cleared all vectors from LanceDB');
437
- } catch (error) {
438
- logger.error('Failed to clear vectors', { error });
439
- this.fallbackData.clear();
440
- this.metadata.count = 0;
441
- }
442
- }
443
-
444
- /**
445
- * Load existing storage from disk
446
- */
447
- static async load(indexPath: string): Promise<VectorStorage | null> {
448
- try {
449
- if (!fs.existsSync(indexPath)) {
450
- return null;
451
- }
452
-
453
- // Try to connect to see if it's a valid LanceDB
454
- const db = await lancedb.connect(indexPath);
455
- const tables = await db.tableNames();
456
-
457
- if (tables.length === 0) {
458
- return null;
459
- }
460
-
461
- // Default to OpenAI dimensions
462
- const storage = new VectorStorage(indexPath, 1536);
463
- return storage;
464
- } catch (error) {
465
- logger.error('Failed to load LanceDB storage', { error });
466
- return null;
467
- }
468
- }
469
-
470
- /**
471
- * Calculate cosine similarity
472
- */
473
- private cosineSimilarity(a: number[], b: number[]): number {
474
- if (a.length !== b.length) {
475
- return 0;
476
- }
477
-
478
- let dotProduct = 0;
479
- let normA = 0;
480
- let normB = 0;
481
-
482
- for (let i = 0; i < a.length; i++) {
483
- dotProduct += a[i] * b[i];
484
- normA += a[i] * a[i];
485
- normB += b[i] * b[i];
486
- }
487
-
488
- if (normA === 0 || normB === 0) {
489
- return 0;
490
- }
491
-
492
- return dotProduct / (Math.sqrt(normA) * Math.sqrt(normB));
493
- }
494
- }