cursor-recursive-rag 0.2.0-alpha.2 ā 0.2.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.
- package/README.md +179 -203
- package/dist/adapters/llm/anthropic.d.ts +27 -0
- package/dist/adapters/llm/anthropic.d.ts.map +1 -0
- package/dist/adapters/llm/anthropic.js +287 -0
- package/dist/adapters/llm/anthropic.js.map +1 -0
- package/dist/adapters/llm/base.d.ts +62 -0
- package/dist/adapters/llm/base.d.ts.map +1 -0
- package/dist/adapters/llm/base.js +140 -0
- package/dist/adapters/llm/base.js.map +1 -0
- package/dist/adapters/llm/deepseek.d.ts +24 -0
- package/dist/adapters/llm/deepseek.d.ts.map +1 -0
- package/dist/adapters/llm/deepseek.js +228 -0
- package/dist/adapters/llm/deepseek.js.map +1 -0
- package/dist/adapters/llm/groq.d.ts +25 -0
- package/dist/adapters/llm/groq.d.ts.map +1 -0
- package/dist/adapters/llm/groq.js +265 -0
- package/dist/adapters/llm/groq.js.map +1 -0
- package/dist/adapters/llm/index.d.ts +62 -0
- package/dist/adapters/llm/index.d.ts.map +1 -0
- package/dist/adapters/llm/index.js +380 -0
- package/dist/adapters/llm/index.js.map +1 -0
- package/dist/adapters/llm/ollama.d.ts +23 -0
- package/dist/adapters/llm/ollama.d.ts.map +1 -0
- package/dist/adapters/llm/ollama.js +261 -0
- package/dist/adapters/llm/ollama.js.map +1 -0
- package/dist/adapters/llm/openai.d.ts +22 -0
- package/dist/adapters/llm/openai.d.ts.map +1 -0
- package/dist/adapters/llm/openai.js +232 -0
- package/dist/adapters/llm/openai.js.map +1 -0
- package/dist/adapters/llm/openrouter.d.ts +27 -0
- package/dist/adapters/llm/openrouter.d.ts.map +1 -0
- package/dist/adapters/llm/openrouter.js +305 -0
- package/dist/adapters/llm/openrouter.js.map +1 -0
- package/dist/adapters/vector/index.d.ts.map +1 -1
- package/dist/adapters/vector/index.js +8 -0
- package/dist/adapters/vector/index.js.map +1 -1
- package/dist/adapters/vector/redis-native.d.ts +35 -0
- package/dist/adapters/vector/redis-native.d.ts.map +1 -0
- package/dist/adapters/vector/redis-native.js +170 -0
- package/dist/adapters/vector/redis-native.js.map +1 -0
- package/dist/cli/commands/chat.d.ts +4 -0
- package/dist/cli/commands/chat.d.ts.map +1 -0
- package/dist/cli/commands/chat.js +374 -0
- package/dist/cli/commands/chat.js.map +1 -0
- package/dist/cli/commands/maintenance.d.ts +4 -0
- package/dist/cli/commands/maintenance.d.ts.map +1 -0
- package/dist/cli/commands/maintenance.js +237 -0
- package/dist/cli/commands/maintenance.js.map +1 -0
- package/dist/cli/commands/rules.d.ts +9 -0
- package/dist/cli/commands/rules.d.ts.map +1 -0
- package/dist/cli/commands/rules.js +639 -0
- package/dist/cli/commands/rules.js.map +1 -0
- package/dist/cli/commands/setup.js +5 -4
- package/dist/cli/commands/setup.js.map +1 -1
- package/dist/cli/index.js +6 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/config/memoryConfig.d.ts +427 -0
- package/dist/config/memoryConfig.d.ts.map +1 -0
- package/dist/config/memoryConfig.js +258 -0
- package/dist/config/memoryConfig.js.map +1 -0
- package/dist/config/rulesConfig.d.ts +486 -0
- package/dist/config/rulesConfig.d.ts.map +1 -0
- package/dist/config/rulesConfig.js +345 -0
- package/dist/config/rulesConfig.js.map +1 -0
- package/dist/dashboard/coreTools.d.ts +14 -0
- package/dist/dashboard/coreTools.d.ts.map +1 -0
- package/dist/dashboard/coreTools.js +413 -0
- package/dist/dashboard/coreTools.js.map +1 -0
- package/dist/dashboard/public/index.html +1982 -13
- package/dist/dashboard/server.d.ts +1 -8
- package/dist/dashboard/server.d.ts.map +1 -1
- package/dist/dashboard/server.js +846 -13
- package/dist/dashboard/server.js.map +1 -1
- package/dist/dashboard/toolRegistry.d.ts +192 -0
- package/dist/dashboard/toolRegistry.d.ts.map +1 -0
- package/dist/dashboard/toolRegistry.js +322 -0
- package/dist/dashboard/toolRegistry.js.map +1 -0
- package/dist/proxy/index.d.ts +1 -1
- package/dist/proxy/index.d.ts.map +1 -1
- package/dist/proxy/index.js +9 -6
- package/dist/proxy/index.js.map +1 -1
- package/dist/server/index.js +21 -0
- package/dist/server/index.js.map +1 -1
- package/dist/server/tools/crawl.d.ts.map +1 -1
- package/dist/server/tools/crawl.js +8 -0
- package/dist/server/tools/crawl.js.map +1 -1
- package/dist/server/tools/index.d.ts.map +1 -1
- package/dist/server/tools/index.js +19 -1
- package/dist/server/tools/index.js.map +1 -1
- package/dist/server/tools/ingest.d.ts.map +1 -1
- package/dist/server/tools/ingest.js +5 -0
- package/dist/server/tools/ingest.js.map +1 -1
- package/dist/server/tools/memory.d.ts +250 -0
- package/dist/server/tools/memory.d.ts.map +1 -0
- package/dist/server/tools/memory.js +472 -0
- package/dist/server/tools/memory.js.map +1 -0
- package/dist/server/tools/recursive-query.d.ts.map +1 -1
- package/dist/server/tools/recursive-query.js +6 -0
- package/dist/server/tools/recursive-query.js.map +1 -1
- package/dist/server/tools/search.d.ts.map +1 -1
- package/dist/server/tools/search.js +6 -0
- package/dist/server/tools/search.js.map +1 -1
- package/dist/services/activity-log.d.ts +10 -0
- package/dist/services/activity-log.d.ts.map +1 -0
- package/dist/services/activity-log.js +53 -0
- package/dist/services/activity-log.js.map +1 -0
- package/dist/services/categoryManager.d.ts +110 -0
- package/dist/services/categoryManager.d.ts.map +1 -0
- package/dist/services/categoryManager.js +549 -0
- package/dist/services/categoryManager.js.map +1 -0
- package/dist/services/contextEnvironment.d.ts +206 -0
- package/dist/services/contextEnvironment.d.ts.map +1 -0
- package/dist/services/contextEnvironment.js +481 -0
- package/dist/services/contextEnvironment.js.map +1 -0
- package/dist/services/conversationProcessor.d.ts +99 -0
- package/dist/services/conversationProcessor.d.ts.map +1 -0
- package/dist/services/conversationProcessor.js +311 -0
- package/dist/services/conversationProcessor.js.map +1 -0
- package/dist/services/cursorChatReader.d.ts +129 -0
- package/dist/services/cursorChatReader.d.ts.map +1 -0
- package/dist/services/cursorChatReader.js +419 -0
- package/dist/services/cursorChatReader.js.map +1 -0
- package/dist/services/decayCalculator.d.ts +85 -0
- package/dist/services/decayCalculator.d.ts.map +1 -0
- package/dist/services/decayCalculator.js +182 -0
- package/dist/services/decayCalculator.js.map +1 -0
- package/dist/services/enhancedVectorStore.d.ts +102 -0
- package/dist/services/enhancedVectorStore.d.ts.map +1 -0
- package/dist/services/enhancedVectorStore.js +245 -0
- package/dist/services/enhancedVectorStore.js.map +1 -0
- package/dist/services/hybridScorer.d.ts +120 -0
- package/dist/services/hybridScorer.d.ts.map +1 -0
- package/dist/services/hybridScorer.js +334 -0
- package/dist/services/hybridScorer.js.map +1 -0
- package/dist/services/knowledgeExtractor.d.ts +45 -0
- package/dist/services/knowledgeExtractor.d.ts.map +1 -0
- package/dist/services/knowledgeExtractor.js +436 -0
- package/dist/services/knowledgeExtractor.js.map +1 -0
- package/dist/services/knowledgeStorage.d.ts +102 -0
- package/dist/services/knowledgeStorage.d.ts.map +1 -0
- package/dist/services/knowledgeStorage.js +383 -0
- package/dist/services/knowledgeStorage.js.map +1 -0
- package/dist/services/maintenanceScheduler.d.ts +89 -0
- package/dist/services/maintenanceScheduler.d.ts.map +1 -0
- package/dist/services/maintenanceScheduler.js +479 -0
- package/dist/services/maintenanceScheduler.js.map +1 -0
- package/dist/services/memoryMetadataStore.d.ts +62 -0
- package/dist/services/memoryMetadataStore.d.ts.map +1 -0
- package/dist/services/memoryMetadataStore.js +570 -0
- package/dist/services/memoryMetadataStore.js.map +1 -0
- package/dist/services/recursiveRetrieval.d.ts +122 -0
- package/dist/services/recursiveRetrieval.d.ts.map +1 -0
- package/dist/services/recursiveRetrieval.js +443 -0
- package/dist/services/recursiveRetrieval.js.map +1 -0
- package/dist/services/relationshipGraph.d.ts +77 -0
- package/dist/services/relationshipGraph.d.ts.map +1 -0
- package/dist/services/relationshipGraph.js +411 -0
- package/dist/services/relationshipGraph.js.map +1 -0
- package/dist/services/rlmSafeguards.d.ts +273 -0
- package/dist/services/rlmSafeguards.d.ts.map +1 -0
- package/dist/services/rlmSafeguards.js +705 -0
- package/dist/services/rlmSafeguards.js.map +1 -0
- package/dist/services/rulesAnalyzer.d.ts +119 -0
- package/dist/services/rulesAnalyzer.d.ts.map +1 -0
- package/dist/services/rulesAnalyzer.js +768 -0
- package/dist/services/rulesAnalyzer.js.map +1 -0
- package/dist/services/rulesMerger.d.ts +75 -0
- package/dist/services/rulesMerger.d.ts.map +1 -0
- package/dist/services/rulesMerger.js +404 -0
- package/dist/services/rulesMerger.js.map +1 -0
- package/dist/services/rulesParser.d.ts +127 -0
- package/dist/services/rulesParser.d.ts.map +1 -0
- package/dist/services/rulesParser.js +594 -0
- package/dist/services/rulesParser.js.map +1 -0
- package/dist/services/smartChunker.d.ts +110 -0
- package/dist/services/smartChunker.d.ts.map +1 -0
- package/dist/services/smartChunker.js +520 -0
- package/dist/services/smartChunker.js.map +1 -0
- package/dist/types/categories.d.ts +105 -0
- package/dist/types/categories.d.ts.map +1 -0
- package/dist/types/categories.js +108 -0
- package/dist/types/categories.js.map +1 -0
- package/dist/types/extractedKnowledge.d.ts +233 -0
- package/dist/types/extractedKnowledge.d.ts.map +1 -0
- package/dist/types/extractedKnowledge.js +56 -0
- package/dist/types/extractedKnowledge.js.map +1 -0
- package/dist/types/index.d.ts +9 -2
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +12 -1
- package/dist/types/index.js.map +1 -1
- package/dist/types/llmProvider.d.ts +282 -0
- package/dist/types/llmProvider.d.ts.map +1 -0
- package/dist/types/llmProvider.js +48 -0
- package/dist/types/llmProvider.js.map +1 -0
- package/dist/types/memory.d.ts +227 -0
- package/dist/types/memory.d.ts.map +1 -0
- package/dist/types/memory.js +76 -0
- package/dist/types/memory.js.map +1 -0
- package/dist/types/relationships.d.ts +167 -0
- package/dist/types/relationships.d.ts.map +1 -0
- package/dist/types/relationships.js +106 -0
- package/dist/types/relationships.js.map +1 -0
- package/dist/types/rulesOptimizer.d.ts +345 -0
- package/dist/types/rulesOptimizer.d.ts.map +1 -0
- package/dist/types/rulesOptimizer.js +22 -0
- package/dist/types/rulesOptimizer.js.map +1 -0
- package/docs/cursor-recursive-rag-memory-spec.md +4569 -0
- package/docs/cursor-recursive-rag-tasks.md +1355 -0
- package/package.json +6 -3
- package/restart-rag.sh +16 -0
|
@@ -3,6 +3,7 @@ import { QdrantAdapter } from './qdrant.js';
|
|
|
3
3
|
import { VectorizeAdapter } from './vectorize.js';
|
|
4
4
|
import { MemoryAdapter } from './memory.js';
|
|
5
5
|
import { RedisAdapter } from './redis.js';
|
|
6
|
+
import { RedisNativeAdapter } from './redis-native.js';
|
|
6
7
|
export function createVectorStore(type, config) {
|
|
7
8
|
switch (type) {
|
|
8
9
|
case 'memory':
|
|
@@ -12,6 +13,13 @@ export function createVectorStore(type, config) {
|
|
|
12
13
|
case 'qdrant':
|
|
13
14
|
return new QdrantAdapter(config);
|
|
14
15
|
case 'redis':
|
|
16
|
+
// Use native Redis 8.x adapter by default, fall back to RediSearch if specified
|
|
17
|
+
if (config.vectorStoreConfig?.useRediSearch) {
|
|
18
|
+
return new RedisAdapter(config);
|
|
19
|
+
}
|
|
20
|
+
return new RedisNativeAdapter(config);
|
|
21
|
+
case 'redis-stack':
|
|
22
|
+
// Explicit Redis Stack/RediSearch adapter
|
|
15
23
|
return new RedisAdapter(config);
|
|
16
24
|
case 'vectorize':
|
|
17
25
|
return new VectorizeAdapter(config);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/adapters/vector/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/adapters/vector/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAKvD,MAAM,UAAU,iBAAiB,CAAC,IAAY,EAAE,MAAiB;IAC/D,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,QAAQ;YACX,OAAO,IAAI,aAAa,CAAC,MAAM,CAAC,CAAC;QACnC,KAAK,QAAQ;YACX,OAAO,IAAI,aAAa,CAAC,MAAM,CAAC,CAAC;QACnC,KAAK,QAAQ;YACX,OAAO,IAAI,aAAa,CAAC,MAAM,CAAC,CAAC;QACnC,KAAK,OAAO;YACV,gFAAgF;YAChF,IAAI,MAAM,CAAC,iBAAiB,EAAE,aAAa,EAAE,CAAC;gBAC5C,OAAO,IAAI,YAAY,CAAC,MAAM,CAAC,CAAC;YAClC,CAAC;YACD,OAAO,IAAI,kBAAkB,CAAC,MAAM,CAAC,CAAC;QACxC,KAAK,aAAa;YAChB,0CAA0C;YAC1C,OAAO,IAAI,YAAY,CAAC,MAAM,CAAC,CAAC;QAClC,KAAK,WAAW;YACd,OAAO,IAAI,gBAAgB,CAAC,MAAM,CAAC,CAAC;QACtC;YACE,MAAM,IAAI,KAAK,CAAC,yBAAyB,IAAI,EAAE,CAAC,CAAC;IACrD,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { VectorStore, VectorDocument, SearchResult, SearchOptions } from '../../types/index.js';
|
|
2
|
+
import type { RAGConfig } from '../../types/index.js';
|
|
3
|
+
/**
|
|
4
|
+
* Redis 8.x Native Vector Adapter
|
|
5
|
+
*
|
|
6
|
+
* Uses Redis 8.x native vector commands (VADD, VSIM, VREM, VCARD).
|
|
7
|
+
* Works with standard Redis 8.x installed via Homebrew or other methods.
|
|
8
|
+
*
|
|
9
|
+
* Command syntax (Redis 8.x):
|
|
10
|
+
* - VADD key VALUES dim v1 v2 ... vN element [CAS] [NOQUANT|BIN|Q8]
|
|
11
|
+
* - VSIM key VALUES dim v1 v2 ... vN [WITHSCORES] [COUNT count]
|
|
12
|
+
* - VREM key element [element ...]
|
|
13
|
+
* - VCARD key
|
|
14
|
+
*
|
|
15
|
+
* Features:
|
|
16
|
+
* - Persistent storage
|
|
17
|
+
* - HNSW index for approximate nearest neighbor search
|
|
18
|
+
* - No additional modules required (uses native Redis 8.x vector support)
|
|
19
|
+
*/
|
|
20
|
+
export declare class RedisNativeAdapter implements VectorStore {
|
|
21
|
+
private client;
|
|
22
|
+
private setName;
|
|
23
|
+
private metadataPrefix;
|
|
24
|
+
private vectorDim;
|
|
25
|
+
private isConnected;
|
|
26
|
+
private redisUrl;
|
|
27
|
+
constructor(config: RAGConfig);
|
|
28
|
+
private initialize;
|
|
29
|
+
add(docs: VectorDocument[]): Promise<void>;
|
|
30
|
+
search(embedding: number[], options: SearchOptions): Promise<SearchResult[]>;
|
|
31
|
+
delete(ids: string[]): Promise<void>;
|
|
32
|
+
count(): Promise<number>;
|
|
33
|
+
disconnect(): Promise<void>;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=redis-native.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redis-native.d.ts","sourceRoot":"","sources":["../../../src/adapters/vector/redis-native.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrG,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAItD;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,kBAAmB,YAAW,WAAW;IACpD,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,OAAO,CAAwB;IACvC,OAAO,CAAC,cAAc,CAAsB;IAC5C,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,QAAQ,CAAS;gBAEb,MAAM,EAAE,SAAS;YAUf,UAAU;IAgBlB,GAAG,CAAC,IAAI,EAAE,cAAc,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAuC1C,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAqE5E,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAapC,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC;IAWxB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;CAMlC"}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import { createClient } from 'redis';
|
|
2
|
+
/**
|
|
3
|
+
* Redis 8.x Native Vector Adapter
|
|
4
|
+
*
|
|
5
|
+
* Uses Redis 8.x native vector commands (VADD, VSIM, VREM, VCARD).
|
|
6
|
+
* Works with standard Redis 8.x installed via Homebrew or other methods.
|
|
7
|
+
*
|
|
8
|
+
* Command syntax (Redis 8.x):
|
|
9
|
+
* - VADD key VALUES dim v1 v2 ... vN element [CAS] [NOQUANT|BIN|Q8]
|
|
10
|
+
* - VSIM key VALUES dim v1 v2 ... vN [WITHSCORES] [COUNT count]
|
|
11
|
+
* - VREM key element [element ...]
|
|
12
|
+
* - VCARD key
|
|
13
|
+
*
|
|
14
|
+
* Features:
|
|
15
|
+
* - Persistent storage
|
|
16
|
+
* - HNSW index for approximate nearest neighbor search
|
|
17
|
+
* - No additional modules required (uses native Redis 8.x vector support)
|
|
18
|
+
*/
|
|
19
|
+
export class RedisNativeAdapter {
|
|
20
|
+
client;
|
|
21
|
+
setName = 'cursor-rag-vectors';
|
|
22
|
+
metadataPrefix = 'cursor-rag:meta:';
|
|
23
|
+
vectorDim;
|
|
24
|
+
isConnected = false;
|
|
25
|
+
redisUrl;
|
|
26
|
+
constructor(config) {
|
|
27
|
+
this.redisUrl = config.apiKeys?.redis?.url || config.vectorStoreConfig?.redisUrl || 'redis://localhost:6379';
|
|
28
|
+
this.vectorDim = config.vectorStoreConfig?.vectorDim || 384;
|
|
29
|
+
this.client = createClient({ url: this.redisUrl });
|
|
30
|
+
this.client.on('error', (err) => {
|
|
31
|
+
console.error('Redis Client Error:', err.message);
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
async initialize() {
|
|
35
|
+
if (!this.isConnected) {
|
|
36
|
+
try {
|
|
37
|
+
await this.client.connect();
|
|
38
|
+
this.isConnected = true;
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
const err = error;
|
|
42
|
+
throw new Error(`Failed to connect to Redis at ${this.redisUrl}. ` +
|
|
43
|
+
`Ensure Redis 8.x is running.\n` +
|
|
44
|
+
`Error: ${err.message}`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
async add(docs) {
|
|
49
|
+
await this.initialize();
|
|
50
|
+
for (const doc of docs) {
|
|
51
|
+
// VADD key VALUES dim v1 v2 ... vN element
|
|
52
|
+
// Build command: VADD cursor-rag-vectors VALUES 384 0.1 0.2 ... element_id
|
|
53
|
+
const cmd = [
|
|
54
|
+
'VADD',
|
|
55
|
+
this.setName,
|
|
56
|
+
'VALUES',
|
|
57
|
+
doc.embedding.length.toString(),
|
|
58
|
+
...doc.embedding.map(v => v.toString()),
|
|
59
|
+
doc.id
|
|
60
|
+
];
|
|
61
|
+
try {
|
|
62
|
+
await this.client.sendCommand(cmd);
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
const err = error;
|
|
66
|
+
if (err.message?.includes('unknown command')) {
|
|
67
|
+
throw new Error('Redis native vector commands not available. ' +
|
|
68
|
+
'Ensure you have Redis 8.x with vector support or use Redis Stack.');
|
|
69
|
+
}
|
|
70
|
+
throw error;
|
|
71
|
+
}
|
|
72
|
+
// Store metadata separately
|
|
73
|
+
const metadataKey = `${this.metadataPrefix}${doc.id}`;
|
|
74
|
+
await this.client.hSet(metadataKey, {
|
|
75
|
+
id: doc.id,
|
|
76
|
+
content: doc.content,
|
|
77
|
+
source: doc.metadata?.source || 'unknown',
|
|
78
|
+
metadata: JSON.stringify(doc.metadata || {})
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
async search(embedding, options) {
|
|
83
|
+
await this.initialize();
|
|
84
|
+
const topK = options.topK || 10;
|
|
85
|
+
try {
|
|
86
|
+
// VSIM key VALUES dim v1 v2 ... vN COUNT count WITHSCORES
|
|
87
|
+
const cmd = [
|
|
88
|
+
'VSIM',
|
|
89
|
+
this.setName,
|
|
90
|
+
'VALUES',
|
|
91
|
+
embedding.length.toString(),
|
|
92
|
+
...embedding.map(v => v.toString()),
|
|
93
|
+
'COUNT', topK.toString(),
|
|
94
|
+
'WITHSCORES'
|
|
95
|
+
];
|
|
96
|
+
const results = await this.client.sendCommand(cmd);
|
|
97
|
+
if (!results || results.length === 0) {
|
|
98
|
+
return [];
|
|
99
|
+
}
|
|
100
|
+
// Results come as [id1, score1, id2, score2, ...]
|
|
101
|
+
const searchResults = [];
|
|
102
|
+
for (let i = 0; i < results.length; i += 2) {
|
|
103
|
+
const id = results[i];
|
|
104
|
+
const score = parseFloat(results[i + 1]);
|
|
105
|
+
// Get metadata
|
|
106
|
+
const metadataKey = `${this.metadataPrefix}${id}`;
|
|
107
|
+
const metadataRaw = await this.client.hGetAll(metadataKey);
|
|
108
|
+
if (metadataRaw && metadataRaw.content) {
|
|
109
|
+
let metadata = { source: metadataRaw.source || 'unknown' };
|
|
110
|
+
try {
|
|
111
|
+
metadata = JSON.parse(metadataRaw.metadata || '{}');
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
// Keep default
|
|
115
|
+
}
|
|
116
|
+
// Apply source filter if specified
|
|
117
|
+
if (options.filter?.source) {
|
|
118
|
+
const allowedSources = Array.isArray(options.filter.source.$in)
|
|
119
|
+
? options.filter.source.$in
|
|
120
|
+
: [options.filter.source];
|
|
121
|
+
if (!allowedSources.includes(metadata.source)) {
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
searchResults.push({
|
|
126
|
+
id,
|
|
127
|
+
content: metadataRaw.content,
|
|
128
|
+
metadata,
|
|
129
|
+
score // Redis 8 VSIM returns similarity score directly (1 = identical)
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return searchResults;
|
|
134
|
+
}
|
|
135
|
+
catch (error) {
|
|
136
|
+
const err = error;
|
|
137
|
+
console.error('Redis native search error:', err.message);
|
|
138
|
+
return [];
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
async delete(ids) {
|
|
142
|
+
await this.initialize();
|
|
143
|
+
for (const id of ids) {
|
|
144
|
+
try {
|
|
145
|
+
await this.client.sendCommand(['VREM', this.setName, id]);
|
|
146
|
+
await this.client.del(`${this.metadataPrefix}${id}`);
|
|
147
|
+
}
|
|
148
|
+
catch (error) {
|
|
149
|
+
// Ignore errors for non-existent keys
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
async count() {
|
|
154
|
+
await this.initialize();
|
|
155
|
+
try {
|
|
156
|
+
const result = await this.client.sendCommand(['VCARD', this.setName]);
|
|
157
|
+
return result || 0;
|
|
158
|
+
}
|
|
159
|
+
catch {
|
|
160
|
+
return 0;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
async disconnect() {
|
|
164
|
+
if (this.isConnected) {
|
|
165
|
+
await this.client.quit();
|
|
166
|
+
this.isConnected = false;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
//# sourceMappingURL=redis-native.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redis-native.js","sourceRoot":"","sources":["../../../src/adapters/vector/redis-native.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/chat.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAqBpC,QAAA,MAAM,WAAW,SACuC,CAAC;AA8czD,OAAO,EAAE,WAAW,EAAE,CAAC"}
|
|
@@ -0,0 +1,374 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import ora from 'ora';
|
|
4
|
+
import { loadConfig } from '../../services/config.js';
|
|
5
|
+
import { createVectorStore } from '../../adapters/vector/index.js';
|
|
6
|
+
import { createEmbedder } from '../../adapters/embeddings/index.js';
|
|
7
|
+
import { createCursorChatReader } from '../../services/cursorChatReader.js';
|
|
8
|
+
import { createConversationProcessor } from '../../services/conversationProcessor.js';
|
|
9
|
+
import { getMemoryMetadataStore } from '../../services/memoryMetadataStore.js';
|
|
10
|
+
import { createEnhancedVectorStore } from '../../services/enhancedVectorStore.js';
|
|
11
|
+
import { createKnowledgeExtractor } from '../../services/knowledgeExtractor.js';
|
|
12
|
+
import { createKnowledgeStorageService } from '../../services/knowledgeStorage.js';
|
|
13
|
+
import { countExtractedItems } from '../../types/extractedKnowledge.js';
|
|
14
|
+
const chatCommand = new Command('chat')
|
|
15
|
+
.description('Manage Cursor chat history integration');
|
|
16
|
+
chatCommand
|
|
17
|
+
.command('list')
|
|
18
|
+
.description('List available Cursor conversations')
|
|
19
|
+
.option('-n, --limit <n>', 'Maximum conversations to show', '20')
|
|
20
|
+
.option('--since <date>', 'Only show conversations since date (YYYY-MM-DD)')
|
|
21
|
+
.option('--code-only', 'Only show conversations with code blocks')
|
|
22
|
+
.option('--json', 'Output as JSON')
|
|
23
|
+
.action(async (options) => {
|
|
24
|
+
try {
|
|
25
|
+
const reader = createCursorChatReader();
|
|
26
|
+
if (!reader.isDatabaseAvailable()) {
|
|
27
|
+
console.error(chalk.red('Cursor database not found at: ' + reader.getDatabasePath()));
|
|
28
|
+
console.log(chalk.yellow('\nMake sure Cursor is installed and has been used at least once.'));
|
|
29
|
+
process.exit(1);
|
|
30
|
+
}
|
|
31
|
+
const filterOptions = {
|
|
32
|
+
limit: parseInt(options.limit, 10),
|
|
33
|
+
};
|
|
34
|
+
if (options.since) {
|
|
35
|
+
filterOptions.since = new Date(options.since);
|
|
36
|
+
}
|
|
37
|
+
if (options.codeOnly) {
|
|
38
|
+
filterOptions.hasCode = true;
|
|
39
|
+
}
|
|
40
|
+
const conversations = reader.listConversations(filterOptions);
|
|
41
|
+
if (options.json) {
|
|
42
|
+
console.log(JSON.stringify(conversations, null, 2));
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
console.log(chalk.cyan(`\nš Found ${conversations.length} conversations\n`));
|
|
46
|
+
if (conversations.length === 0) {
|
|
47
|
+
console.log(chalk.yellow('No conversations found matching your criteria.'));
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
const metadataStore = getMemoryMetadataStore();
|
|
51
|
+
for (const conv of conversations) {
|
|
52
|
+
const isProcessed = metadataStore.isConversationProcessed(conv.id);
|
|
53
|
+
const statusIcon = isProcessed ? chalk.green('ā') : chalk.gray('ā');
|
|
54
|
+
const dateStr = conv.updatedAt
|
|
55
|
+
? conv.updatedAt.toLocaleDateString() + ' ' + conv.updatedAt.toLocaleTimeString()
|
|
56
|
+
: 'Unknown date';
|
|
57
|
+
console.log(`${statusIcon} ${chalk.bold(conv.id.substring(0, 8))} ${chalk.gray(dateStr)}`);
|
|
58
|
+
console.log(` Messages: ${conv.messageCount} ${conv.hasCodeBlocks ? chalk.blue('š¦ Has code') : ''}`);
|
|
59
|
+
if (conv.preview) {
|
|
60
|
+
const preview = conv.preview.substring(0, 80).replace(/\n/g, ' ');
|
|
61
|
+
console.log(` ${chalk.gray(preview)}${conv.preview.length > 80 ? '...' : ''}`);
|
|
62
|
+
}
|
|
63
|
+
console.log('');
|
|
64
|
+
}
|
|
65
|
+
const processedCount = conversations.filter(c => metadataStore.isConversationProcessed(c.id)).length;
|
|
66
|
+
console.log(chalk.gray(`\nProcessed: ${processedCount}/${conversations.length}`));
|
|
67
|
+
console.log(chalk.gray(`Legend: ${chalk.green('ā')} processed ${chalk.gray('ā')} not processed`));
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
console.error(chalk.red(`Error: ${error instanceof Error ? error.message : 'Unknown error'}`));
|
|
71
|
+
process.exit(1);
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
chatCommand
|
|
75
|
+
.command('ingest')
|
|
76
|
+
.description('Ingest Cursor chat history into RAG knowledge base')
|
|
77
|
+
.option('-n, --limit <n>', 'Maximum conversations to process')
|
|
78
|
+
.option('--since <date>', 'Only process conversations since date (YYYY-MM-DD)')
|
|
79
|
+
.option('--code-only', 'Only process conversations with code blocks')
|
|
80
|
+
.option('--force', 'Re-process already processed conversations')
|
|
81
|
+
.option('--dry-run', 'Show what would be processed without actually doing it')
|
|
82
|
+
.option('--extract', 'Extract knowledge (solutions, patterns, decisions) using LLM')
|
|
83
|
+
.action(async (options) => {
|
|
84
|
+
const spinner = ora('Loading configuration...').start();
|
|
85
|
+
try {
|
|
86
|
+
const config = loadConfig();
|
|
87
|
+
const vectorStore = createVectorStore(config.vectorStore, config);
|
|
88
|
+
const embedder = await createEmbedder(config.embeddings, config);
|
|
89
|
+
const metadataStore = getMemoryMetadataStore();
|
|
90
|
+
const enhancedStore = createEnhancedVectorStore(vectorStore);
|
|
91
|
+
spinner.succeed('Configuration loaded');
|
|
92
|
+
const reader = createCursorChatReader();
|
|
93
|
+
if (!reader.isDatabaseAvailable()) {
|
|
94
|
+
console.error(chalk.red('Cursor database not found at: ' + reader.getDatabasePath()));
|
|
95
|
+
console.log(chalk.yellow('\nMake sure Cursor is installed and has been used at least once.'));
|
|
96
|
+
process.exit(1);
|
|
97
|
+
}
|
|
98
|
+
spinner.start('Scanning conversations...');
|
|
99
|
+
const filterOptions = {};
|
|
100
|
+
if (options.limit) {
|
|
101
|
+
filterOptions.limit = parseInt(options.limit, 10);
|
|
102
|
+
}
|
|
103
|
+
if (options.since) {
|
|
104
|
+
filterOptions.since = new Date(options.since);
|
|
105
|
+
}
|
|
106
|
+
if (options.codeOnly) {
|
|
107
|
+
filterOptions.hasCode = true;
|
|
108
|
+
}
|
|
109
|
+
const conversations = reader.listConversations(filterOptions);
|
|
110
|
+
const toProcess = options.force
|
|
111
|
+
? conversations
|
|
112
|
+
: conversations.filter(c => !metadataStore.isConversationProcessed(c.id));
|
|
113
|
+
spinner.succeed(`Found ${conversations.length} conversations, ${toProcess.length} to process`);
|
|
114
|
+
if (toProcess.length === 0) {
|
|
115
|
+
console.log(chalk.yellow('\nNo new conversations to process.'));
|
|
116
|
+
console.log(chalk.gray('Use --force to re-process already processed conversations.'));
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
if (options.dryRun) {
|
|
120
|
+
console.log(chalk.cyan('\nš Dry run - would process:\n'));
|
|
121
|
+
for (const conv of toProcess) {
|
|
122
|
+
console.log(` ${conv.id.substring(0, 8)} - ${conv.messageCount} messages`);
|
|
123
|
+
}
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
const processor = createConversationProcessor({
|
|
127
|
+
includeCodeChunks: true,
|
|
128
|
+
minExchangeLength: 50,
|
|
129
|
+
maxChunkSize: 2000,
|
|
130
|
+
extractEntities: true,
|
|
131
|
+
});
|
|
132
|
+
const knowledgeExtractor = options.extract ? createKnowledgeExtractor(config) : null;
|
|
133
|
+
const knowledgeStorage = options.extract
|
|
134
|
+
? createKnowledgeStorageService(enhancedStore, embedder)
|
|
135
|
+
: null;
|
|
136
|
+
if (options.extract) {
|
|
137
|
+
if (knowledgeExtractor?.isLLMAvailable()) {
|
|
138
|
+
console.log(chalk.blue('š Knowledge extraction enabled (LLM mode)'));
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
console.log(chalk.yellow('š Knowledge extraction enabled (heuristic mode - set OpenAI API key for better results)'));
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
let totalChunks = 0;
|
|
145
|
+
let totalKnowledge = 0;
|
|
146
|
+
let processedCount = 0;
|
|
147
|
+
console.log(chalk.cyan('\nš Processing conversations...\n'));
|
|
148
|
+
for (const summary of toProcess) {
|
|
149
|
+
const convSpinner = ora(`Processing ${summary.id.substring(0, 8)}...`).start();
|
|
150
|
+
try {
|
|
151
|
+
const conversation = reader.getConversation(summary.id);
|
|
152
|
+
if (!conversation) {
|
|
153
|
+
convSpinner.warn(`Skipped ${summary.id.substring(0, 8)}: Could not read conversation`);
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
const result = processor.processConversation(conversation);
|
|
157
|
+
if (result.chunks.length === 0) {
|
|
158
|
+
convSpinner.info(`Skipped ${summary.id.substring(0, 8)}: No meaningful content`);
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
const documents = await Promise.all(result.chunks.map(async (chunk) => {
|
|
162
|
+
const embedding = await embedder.embed(chunk.content);
|
|
163
|
+
return {
|
|
164
|
+
id: chunk.id,
|
|
165
|
+
content: chunk.content,
|
|
166
|
+
embedding,
|
|
167
|
+
metadata: {
|
|
168
|
+
...chunk.metadata,
|
|
169
|
+
source: chunk.source,
|
|
170
|
+
chunkType: chunk.chunkType,
|
|
171
|
+
importance: chunk.importance,
|
|
172
|
+
sourceConversationId: chunk.sourceConversationId,
|
|
173
|
+
sourceMessageIndex: chunk.sourceMessageIndex,
|
|
174
|
+
},
|
|
175
|
+
};
|
|
176
|
+
}));
|
|
177
|
+
await enhancedStore.add(documents);
|
|
178
|
+
let knowledgeCount = 0;
|
|
179
|
+
if (knowledgeExtractor && knowledgeStorage) {
|
|
180
|
+
try {
|
|
181
|
+
const extracted = await knowledgeExtractor.extract(conversation);
|
|
182
|
+
knowledgeCount = countExtractedItems(extracted);
|
|
183
|
+
if (knowledgeCount > 0) {
|
|
184
|
+
await knowledgeStorage.store(extracted);
|
|
185
|
+
totalKnowledge += knowledgeCount;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
catch (extractError) {
|
|
189
|
+
console.warn(chalk.yellow(` Warning: Knowledge extraction failed for ${summary.id.substring(0, 8)}`));
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
metadataStore.markConversationProcessed(summary.id, summary.messageCount, result.chunks.length, knowledgeCount);
|
|
193
|
+
totalChunks += result.chunks.length;
|
|
194
|
+
processedCount++;
|
|
195
|
+
const knowledgeInfo = knowledgeCount > 0 ? `, ${knowledgeCount} knowledge items` : '';
|
|
196
|
+
convSpinner.succeed(`Processed ${summary.id.substring(0, 8)}: ` +
|
|
197
|
+
`${result.chunks.length} chunks, ` +
|
|
198
|
+
`${result.metadata.codeBlockCount} code blocks${knowledgeInfo}`);
|
|
199
|
+
}
|
|
200
|
+
catch (error) {
|
|
201
|
+
convSpinner.fail(`Failed ${summary.id.substring(0, 8)}: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
console.log(chalk.green(`\nā
Ingestion complete!`));
|
|
205
|
+
console.log(chalk.cyan(` Conversations processed: ${processedCount}`));
|
|
206
|
+
console.log(chalk.cyan(` Total chunks created: ${totalChunks}`));
|
|
207
|
+
if (options.extract) {
|
|
208
|
+
console.log(chalk.cyan(` Knowledge items extracted: ${totalKnowledge}`));
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
catch (error) {
|
|
212
|
+
spinner.fail('Ingestion failed');
|
|
213
|
+
console.error(chalk.red(`Error: ${error instanceof Error ? error.message : 'Unknown error'}`));
|
|
214
|
+
process.exit(1);
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
chatCommand
|
|
218
|
+
.command('watch')
|
|
219
|
+
.description('Watch for new Cursor conversations and ingest automatically')
|
|
220
|
+
.option('--interval <seconds>', 'Check interval in seconds', '60')
|
|
221
|
+
.option('--code-only', 'Only process conversations with code blocks')
|
|
222
|
+
.action(async (options) => {
|
|
223
|
+
console.log(chalk.cyan('\nš Watching for new Cursor conversations...\n'));
|
|
224
|
+
console.log(chalk.gray(`Check interval: ${options.interval} seconds`));
|
|
225
|
+
console.log(chalk.gray('Press Ctrl+C to stop\n'));
|
|
226
|
+
const config = loadConfig();
|
|
227
|
+
const vectorStore = createVectorStore(config.vectorStore, config);
|
|
228
|
+
const embedder = await createEmbedder(config.embeddings, config);
|
|
229
|
+
const metadataStore = getMemoryMetadataStore();
|
|
230
|
+
const enhancedStore = createEnhancedVectorStore(vectorStore);
|
|
231
|
+
const reader = createCursorChatReader();
|
|
232
|
+
const processor = createConversationProcessor();
|
|
233
|
+
if (!reader.isDatabaseAvailable()) {
|
|
234
|
+
console.error(chalk.red('Cursor database not found at: ' + reader.getDatabasePath()));
|
|
235
|
+
process.exit(1);
|
|
236
|
+
}
|
|
237
|
+
let lastCheck = new Date();
|
|
238
|
+
let totalIngested = 0;
|
|
239
|
+
const checkForNewConversations = async () => {
|
|
240
|
+
try {
|
|
241
|
+
const filterOptions = {
|
|
242
|
+
since: lastCheck,
|
|
243
|
+
};
|
|
244
|
+
if (options.codeOnly) {
|
|
245
|
+
filterOptions.hasCode = true;
|
|
246
|
+
}
|
|
247
|
+
const conversations = reader.listConversations(filterOptions);
|
|
248
|
+
const newConversations = conversations.filter(c => !metadataStore.isConversationProcessed(c.id));
|
|
249
|
+
if (newConversations.length > 0) {
|
|
250
|
+
console.log(chalk.cyan(`\nš„ Found ${newConversations.length} new conversation(s)`));
|
|
251
|
+
for (const summary of newConversations) {
|
|
252
|
+
const conversation = reader.getConversation(summary.id);
|
|
253
|
+
if (!conversation)
|
|
254
|
+
continue;
|
|
255
|
+
const result = processor.processConversation(conversation);
|
|
256
|
+
if (result.chunks.length === 0)
|
|
257
|
+
continue;
|
|
258
|
+
const documents = await Promise.all(result.chunks.map(async (chunk) => {
|
|
259
|
+
const embedding = await embedder.embed(chunk.content);
|
|
260
|
+
return {
|
|
261
|
+
id: chunk.id,
|
|
262
|
+
content: chunk.content,
|
|
263
|
+
embedding,
|
|
264
|
+
metadata: {
|
|
265
|
+
...chunk.metadata,
|
|
266
|
+
source: chunk.source,
|
|
267
|
+
chunkType: chunk.chunkType,
|
|
268
|
+
importance: chunk.importance,
|
|
269
|
+
sourceConversationId: chunk.sourceConversationId,
|
|
270
|
+
},
|
|
271
|
+
};
|
|
272
|
+
}));
|
|
273
|
+
await enhancedStore.add(documents);
|
|
274
|
+
metadataStore.markConversationProcessed(summary.id, summary.messageCount, result.chunks.length, 0);
|
|
275
|
+
totalIngested++;
|
|
276
|
+
console.log(chalk.green(` ā Ingested ${summary.id.substring(0, 8)}: ${result.chunks.length} chunks`));
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
lastCheck = new Date();
|
|
280
|
+
}
|
|
281
|
+
catch (error) {
|
|
282
|
+
console.error(chalk.red(`Watch error: ${error instanceof Error ? error.message : 'Unknown error'}`));
|
|
283
|
+
}
|
|
284
|
+
};
|
|
285
|
+
await checkForNewConversations();
|
|
286
|
+
const intervalMs = parseInt(options.interval, 10) * 1000;
|
|
287
|
+
const intervalId = setInterval(checkForNewConversations, intervalMs);
|
|
288
|
+
process.on('SIGINT', () => {
|
|
289
|
+
clearInterval(intervalId);
|
|
290
|
+
console.log(chalk.yellow(`\n\nš Stopped watching. Total ingested: ${totalIngested} conversations`));
|
|
291
|
+
process.exit(0);
|
|
292
|
+
});
|
|
293
|
+
});
|
|
294
|
+
chatCommand
|
|
295
|
+
.command('stats')
|
|
296
|
+
.description('Show chat history ingestion statistics')
|
|
297
|
+
.action(async () => {
|
|
298
|
+
try {
|
|
299
|
+
const reader = createCursorChatReader();
|
|
300
|
+
const metadataStore = getMemoryMetadataStore();
|
|
301
|
+
if (!reader.isDatabaseAvailable()) {
|
|
302
|
+
console.error(chalk.red('Cursor database not found.'));
|
|
303
|
+
process.exit(1);
|
|
304
|
+
}
|
|
305
|
+
const totalConversations = reader.getConversationCount();
|
|
306
|
+
const allConversations = reader.listConversations({ limit: 10000 });
|
|
307
|
+
let processedCount = 0;
|
|
308
|
+
let totalMessages = 0;
|
|
309
|
+
let conversationsWithCode = 0;
|
|
310
|
+
for (const conv of allConversations) {
|
|
311
|
+
if (metadataStore.isConversationProcessed(conv.id)) {
|
|
312
|
+
processedCount++;
|
|
313
|
+
}
|
|
314
|
+
totalMessages += conv.messageCount;
|
|
315
|
+
if (conv.hasCodeBlocks) {
|
|
316
|
+
conversationsWithCode++;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
const memoryStats = metadataStore.getMemoryStats();
|
|
320
|
+
console.log(chalk.cyan('\nš Chat History Statistics\n'));
|
|
321
|
+
console.log(chalk.bold('Cursor Database:'));
|
|
322
|
+
console.log(` Total conversations: ${totalConversations}`);
|
|
323
|
+
console.log(` Total messages: ${totalMessages}`);
|
|
324
|
+
console.log(` Conversations with code: ${conversationsWithCode}`);
|
|
325
|
+
console.log(chalk.bold('\nIngestion Status:'));
|
|
326
|
+
console.log(` Processed: ${processedCount}/${totalConversations} (${Math.round(processedCount / totalConversations * 100)}%)`);
|
|
327
|
+
console.log(` Pending: ${totalConversations - processedCount}`);
|
|
328
|
+
console.log(chalk.bold('\nMemory Store:'));
|
|
329
|
+
console.log(` Total chunks: ${memoryStats.totalChunks}`);
|
|
330
|
+
console.log(` Active chunks: ${memoryStats.activeChunks}`);
|
|
331
|
+
console.log(` Archived chunks: ${memoryStats.archivedChunks}`);
|
|
332
|
+
console.log(` Avg decay score: ${memoryStats.avgDecayScore.toFixed(3)}`);
|
|
333
|
+
if (Object.keys(memoryStats.chunksByType).length > 0) {
|
|
334
|
+
console.log(chalk.bold('\nChunks by Type:'));
|
|
335
|
+
for (const [type, count] of Object.entries(memoryStats.chunksByType)) {
|
|
336
|
+
console.log(` ${type}: ${count}`);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
console.log('');
|
|
340
|
+
}
|
|
341
|
+
catch (error) {
|
|
342
|
+
console.error(chalk.red(`Error: ${error instanceof Error ? error.message : 'Unknown error'}`));
|
|
343
|
+
process.exit(1);
|
|
344
|
+
}
|
|
345
|
+
});
|
|
346
|
+
chatCommand
|
|
347
|
+
.command('reset')
|
|
348
|
+
.description('Reset chat history processing status (does not delete ingested data)')
|
|
349
|
+
.option('--confirm', 'Confirm reset operation')
|
|
350
|
+
.action(async (options) => {
|
|
351
|
+
if (!options.confirm) {
|
|
352
|
+
console.log(chalk.yellow('\nā ļø This will reset the processing status for all conversations.'));
|
|
353
|
+
console.log(chalk.yellow(' Ingested data will NOT be deleted, but conversations will be'));
|
|
354
|
+
console.log(chalk.yellow(' marked as unprocessed and can be re-ingested.\n'));
|
|
355
|
+
console.log(chalk.gray('Run with --confirm to proceed.\n'));
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
const spinner = ora('Resetting processing status...').start();
|
|
359
|
+
try {
|
|
360
|
+
const metadataStore = getMemoryMetadataStore();
|
|
361
|
+
const db = metadataStore.db;
|
|
362
|
+
db.prepare('DELETE FROM processed_conversations').run();
|
|
363
|
+
spinner.succeed('Processing status reset');
|
|
364
|
+
console.log(chalk.green('\nAll conversations marked as unprocessed.'));
|
|
365
|
+
console.log(chalk.gray('Run `cursor-rag chat ingest` to re-process them.\n'));
|
|
366
|
+
}
|
|
367
|
+
catch (error) {
|
|
368
|
+
spinner.fail('Reset failed');
|
|
369
|
+
console.error(chalk.red(`Error: ${error instanceof Error ? error.message : 'Unknown error'}`));
|
|
370
|
+
process.exit(1);
|
|
371
|
+
}
|
|
372
|
+
});
|
|
373
|
+
export { chatCommand };
|
|
374
|
+
//# sourceMappingURL=chat.js.map
|