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.
Files changed (210) hide show
  1. package/README.md +179 -203
  2. package/dist/adapters/llm/anthropic.d.ts +27 -0
  3. package/dist/adapters/llm/anthropic.d.ts.map +1 -0
  4. package/dist/adapters/llm/anthropic.js +287 -0
  5. package/dist/adapters/llm/anthropic.js.map +1 -0
  6. package/dist/adapters/llm/base.d.ts +62 -0
  7. package/dist/adapters/llm/base.d.ts.map +1 -0
  8. package/dist/adapters/llm/base.js +140 -0
  9. package/dist/adapters/llm/base.js.map +1 -0
  10. package/dist/adapters/llm/deepseek.d.ts +24 -0
  11. package/dist/adapters/llm/deepseek.d.ts.map +1 -0
  12. package/dist/adapters/llm/deepseek.js +228 -0
  13. package/dist/adapters/llm/deepseek.js.map +1 -0
  14. package/dist/adapters/llm/groq.d.ts +25 -0
  15. package/dist/adapters/llm/groq.d.ts.map +1 -0
  16. package/dist/adapters/llm/groq.js +265 -0
  17. package/dist/adapters/llm/groq.js.map +1 -0
  18. package/dist/adapters/llm/index.d.ts +62 -0
  19. package/dist/adapters/llm/index.d.ts.map +1 -0
  20. package/dist/adapters/llm/index.js +380 -0
  21. package/dist/adapters/llm/index.js.map +1 -0
  22. package/dist/adapters/llm/ollama.d.ts +23 -0
  23. package/dist/adapters/llm/ollama.d.ts.map +1 -0
  24. package/dist/adapters/llm/ollama.js +261 -0
  25. package/dist/adapters/llm/ollama.js.map +1 -0
  26. package/dist/adapters/llm/openai.d.ts +22 -0
  27. package/dist/adapters/llm/openai.d.ts.map +1 -0
  28. package/dist/adapters/llm/openai.js +232 -0
  29. package/dist/adapters/llm/openai.js.map +1 -0
  30. package/dist/adapters/llm/openrouter.d.ts +27 -0
  31. package/dist/adapters/llm/openrouter.d.ts.map +1 -0
  32. package/dist/adapters/llm/openrouter.js +305 -0
  33. package/dist/adapters/llm/openrouter.js.map +1 -0
  34. package/dist/adapters/vector/index.d.ts.map +1 -1
  35. package/dist/adapters/vector/index.js +8 -0
  36. package/dist/adapters/vector/index.js.map +1 -1
  37. package/dist/adapters/vector/redis-native.d.ts +35 -0
  38. package/dist/adapters/vector/redis-native.d.ts.map +1 -0
  39. package/dist/adapters/vector/redis-native.js +170 -0
  40. package/dist/adapters/vector/redis-native.js.map +1 -0
  41. package/dist/cli/commands/chat.d.ts +4 -0
  42. package/dist/cli/commands/chat.d.ts.map +1 -0
  43. package/dist/cli/commands/chat.js +374 -0
  44. package/dist/cli/commands/chat.js.map +1 -0
  45. package/dist/cli/commands/maintenance.d.ts +4 -0
  46. package/dist/cli/commands/maintenance.d.ts.map +1 -0
  47. package/dist/cli/commands/maintenance.js +237 -0
  48. package/dist/cli/commands/maintenance.js.map +1 -0
  49. package/dist/cli/commands/rules.d.ts +9 -0
  50. package/dist/cli/commands/rules.d.ts.map +1 -0
  51. package/dist/cli/commands/rules.js +639 -0
  52. package/dist/cli/commands/rules.js.map +1 -0
  53. package/dist/cli/commands/setup.js +5 -4
  54. package/dist/cli/commands/setup.js.map +1 -1
  55. package/dist/cli/index.js +6 -0
  56. package/dist/cli/index.js.map +1 -1
  57. package/dist/config/memoryConfig.d.ts +427 -0
  58. package/dist/config/memoryConfig.d.ts.map +1 -0
  59. package/dist/config/memoryConfig.js +258 -0
  60. package/dist/config/memoryConfig.js.map +1 -0
  61. package/dist/config/rulesConfig.d.ts +486 -0
  62. package/dist/config/rulesConfig.d.ts.map +1 -0
  63. package/dist/config/rulesConfig.js +345 -0
  64. package/dist/config/rulesConfig.js.map +1 -0
  65. package/dist/dashboard/coreTools.d.ts +14 -0
  66. package/dist/dashboard/coreTools.d.ts.map +1 -0
  67. package/dist/dashboard/coreTools.js +413 -0
  68. package/dist/dashboard/coreTools.js.map +1 -0
  69. package/dist/dashboard/public/index.html +1982 -13
  70. package/dist/dashboard/server.d.ts +1 -8
  71. package/dist/dashboard/server.d.ts.map +1 -1
  72. package/dist/dashboard/server.js +846 -13
  73. package/dist/dashboard/server.js.map +1 -1
  74. package/dist/dashboard/toolRegistry.d.ts +192 -0
  75. package/dist/dashboard/toolRegistry.d.ts.map +1 -0
  76. package/dist/dashboard/toolRegistry.js +322 -0
  77. package/dist/dashboard/toolRegistry.js.map +1 -0
  78. package/dist/proxy/index.d.ts +1 -1
  79. package/dist/proxy/index.d.ts.map +1 -1
  80. package/dist/proxy/index.js +9 -6
  81. package/dist/proxy/index.js.map +1 -1
  82. package/dist/server/index.js +21 -0
  83. package/dist/server/index.js.map +1 -1
  84. package/dist/server/tools/crawl.d.ts.map +1 -1
  85. package/dist/server/tools/crawl.js +8 -0
  86. package/dist/server/tools/crawl.js.map +1 -1
  87. package/dist/server/tools/index.d.ts.map +1 -1
  88. package/dist/server/tools/index.js +19 -1
  89. package/dist/server/tools/index.js.map +1 -1
  90. package/dist/server/tools/ingest.d.ts.map +1 -1
  91. package/dist/server/tools/ingest.js +5 -0
  92. package/dist/server/tools/ingest.js.map +1 -1
  93. package/dist/server/tools/memory.d.ts +250 -0
  94. package/dist/server/tools/memory.d.ts.map +1 -0
  95. package/dist/server/tools/memory.js +472 -0
  96. package/dist/server/tools/memory.js.map +1 -0
  97. package/dist/server/tools/recursive-query.d.ts.map +1 -1
  98. package/dist/server/tools/recursive-query.js +6 -0
  99. package/dist/server/tools/recursive-query.js.map +1 -1
  100. package/dist/server/tools/search.d.ts.map +1 -1
  101. package/dist/server/tools/search.js +6 -0
  102. package/dist/server/tools/search.js.map +1 -1
  103. package/dist/services/activity-log.d.ts +10 -0
  104. package/dist/services/activity-log.d.ts.map +1 -0
  105. package/dist/services/activity-log.js +53 -0
  106. package/dist/services/activity-log.js.map +1 -0
  107. package/dist/services/categoryManager.d.ts +110 -0
  108. package/dist/services/categoryManager.d.ts.map +1 -0
  109. package/dist/services/categoryManager.js +549 -0
  110. package/dist/services/categoryManager.js.map +1 -0
  111. package/dist/services/contextEnvironment.d.ts +206 -0
  112. package/dist/services/contextEnvironment.d.ts.map +1 -0
  113. package/dist/services/contextEnvironment.js +481 -0
  114. package/dist/services/contextEnvironment.js.map +1 -0
  115. package/dist/services/conversationProcessor.d.ts +99 -0
  116. package/dist/services/conversationProcessor.d.ts.map +1 -0
  117. package/dist/services/conversationProcessor.js +311 -0
  118. package/dist/services/conversationProcessor.js.map +1 -0
  119. package/dist/services/cursorChatReader.d.ts +129 -0
  120. package/dist/services/cursorChatReader.d.ts.map +1 -0
  121. package/dist/services/cursorChatReader.js +419 -0
  122. package/dist/services/cursorChatReader.js.map +1 -0
  123. package/dist/services/decayCalculator.d.ts +85 -0
  124. package/dist/services/decayCalculator.d.ts.map +1 -0
  125. package/dist/services/decayCalculator.js +182 -0
  126. package/dist/services/decayCalculator.js.map +1 -0
  127. package/dist/services/enhancedVectorStore.d.ts +102 -0
  128. package/dist/services/enhancedVectorStore.d.ts.map +1 -0
  129. package/dist/services/enhancedVectorStore.js +245 -0
  130. package/dist/services/enhancedVectorStore.js.map +1 -0
  131. package/dist/services/hybridScorer.d.ts +120 -0
  132. package/dist/services/hybridScorer.d.ts.map +1 -0
  133. package/dist/services/hybridScorer.js +334 -0
  134. package/dist/services/hybridScorer.js.map +1 -0
  135. package/dist/services/knowledgeExtractor.d.ts +45 -0
  136. package/dist/services/knowledgeExtractor.d.ts.map +1 -0
  137. package/dist/services/knowledgeExtractor.js +436 -0
  138. package/dist/services/knowledgeExtractor.js.map +1 -0
  139. package/dist/services/knowledgeStorage.d.ts +102 -0
  140. package/dist/services/knowledgeStorage.d.ts.map +1 -0
  141. package/dist/services/knowledgeStorage.js +383 -0
  142. package/dist/services/knowledgeStorage.js.map +1 -0
  143. package/dist/services/maintenanceScheduler.d.ts +89 -0
  144. package/dist/services/maintenanceScheduler.d.ts.map +1 -0
  145. package/dist/services/maintenanceScheduler.js +479 -0
  146. package/dist/services/maintenanceScheduler.js.map +1 -0
  147. package/dist/services/memoryMetadataStore.d.ts +62 -0
  148. package/dist/services/memoryMetadataStore.d.ts.map +1 -0
  149. package/dist/services/memoryMetadataStore.js +570 -0
  150. package/dist/services/memoryMetadataStore.js.map +1 -0
  151. package/dist/services/recursiveRetrieval.d.ts +122 -0
  152. package/dist/services/recursiveRetrieval.d.ts.map +1 -0
  153. package/dist/services/recursiveRetrieval.js +443 -0
  154. package/dist/services/recursiveRetrieval.js.map +1 -0
  155. package/dist/services/relationshipGraph.d.ts +77 -0
  156. package/dist/services/relationshipGraph.d.ts.map +1 -0
  157. package/dist/services/relationshipGraph.js +411 -0
  158. package/dist/services/relationshipGraph.js.map +1 -0
  159. package/dist/services/rlmSafeguards.d.ts +273 -0
  160. package/dist/services/rlmSafeguards.d.ts.map +1 -0
  161. package/dist/services/rlmSafeguards.js +705 -0
  162. package/dist/services/rlmSafeguards.js.map +1 -0
  163. package/dist/services/rulesAnalyzer.d.ts +119 -0
  164. package/dist/services/rulesAnalyzer.d.ts.map +1 -0
  165. package/dist/services/rulesAnalyzer.js +768 -0
  166. package/dist/services/rulesAnalyzer.js.map +1 -0
  167. package/dist/services/rulesMerger.d.ts +75 -0
  168. package/dist/services/rulesMerger.d.ts.map +1 -0
  169. package/dist/services/rulesMerger.js +404 -0
  170. package/dist/services/rulesMerger.js.map +1 -0
  171. package/dist/services/rulesParser.d.ts +127 -0
  172. package/dist/services/rulesParser.d.ts.map +1 -0
  173. package/dist/services/rulesParser.js +594 -0
  174. package/dist/services/rulesParser.js.map +1 -0
  175. package/dist/services/smartChunker.d.ts +110 -0
  176. package/dist/services/smartChunker.d.ts.map +1 -0
  177. package/dist/services/smartChunker.js +520 -0
  178. package/dist/services/smartChunker.js.map +1 -0
  179. package/dist/types/categories.d.ts +105 -0
  180. package/dist/types/categories.d.ts.map +1 -0
  181. package/dist/types/categories.js +108 -0
  182. package/dist/types/categories.js.map +1 -0
  183. package/dist/types/extractedKnowledge.d.ts +233 -0
  184. package/dist/types/extractedKnowledge.d.ts.map +1 -0
  185. package/dist/types/extractedKnowledge.js +56 -0
  186. package/dist/types/extractedKnowledge.js.map +1 -0
  187. package/dist/types/index.d.ts +9 -2
  188. package/dist/types/index.d.ts.map +1 -1
  189. package/dist/types/index.js +12 -1
  190. package/dist/types/index.js.map +1 -1
  191. package/dist/types/llmProvider.d.ts +282 -0
  192. package/dist/types/llmProvider.d.ts.map +1 -0
  193. package/dist/types/llmProvider.js +48 -0
  194. package/dist/types/llmProvider.js.map +1 -0
  195. package/dist/types/memory.d.ts +227 -0
  196. package/dist/types/memory.d.ts.map +1 -0
  197. package/dist/types/memory.js +76 -0
  198. package/dist/types/memory.js.map +1 -0
  199. package/dist/types/relationships.d.ts +167 -0
  200. package/dist/types/relationships.d.ts.map +1 -0
  201. package/dist/types/relationships.js +106 -0
  202. package/dist/types/relationships.js.map +1 -0
  203. package/dist/types/rulesOptimizer.d.ts +345 -0
  204. package/dist/types/rulesOptimizer.d.ts.map +1 -0
  205. package/dist/types/rulesOptimizer.js +22 -0
  206. package/dist/types/rulesOptimizer.js.map +1 -0
  207. package/docs/cursor-recursive-rag-memory-spec.md +4569 -0
  208. package/docs/cursor-recursive-rag-tasks.md +1355 -0
  209. package/package.json +6 -3
  210. package/restart-rag.sh +16 -0
@@ -0,0 +1,110 @@
1
+ import { type CategoryDefinition, type CategoryClassification, type CategoryItemsOptions, type CategoryWithStats, type CategorySelectionOptions, type SelectedCategory, type SummaryEvolutionResult } from '../types/categories.js';
2
+ import type { Category, CategoryItem, EnhancedChunk } from '../types/memory.js';
3
+ import { MemoryMetadataStore } from './memoryMetadataStore.js';
4
+ /**
5
+ * Configuration for the CategoryManager
6
+ */
7
+ export interface CategoryManagerConfig {
8
+ minRelevanceScore: number;
9
+ maxCategoriesPerChunk: number;
10
+ summaryMaxItems: number;
11
+ useLLMForClassification: boolean;
12
+ useLLMForSummaries: boolean;
13
+ llmEndpoint?: string;
14
+ llmApiKey?: string;
15
+ llmModel?: string;
16
+ }
17
+ /**
18
+ * Manages category organization and summary evolution
19
+ *
20
+ * The CategoryManager provides:
21
+ * - Automatic initialization of default categories
22
+ * - Classification of chunks into relevant categories
23
+ * - Evolving summaries that integrate new knowledge
24
+ * - Query-based category selection for retrieval
25
+ */
26
+ export declare class CategoryManager {
27
+ private metadataStore;
28
+ private config;
29
+ private initialized;
30
+ constructor(metadataStore?: MemoryMetadataStore, config?: Partial<CategoryManagerConfig>);
31
+ /**
32
+ * Initialize default categories if they don't exist
33
+ */
34
+ initialize(): Promise<void>;
35
+ /**
36
+ * Classify a chunk into relevant categories
37
+ */
38
+ classifyChunk(chunk: EnhancedChunk): Promise<CategoryClassification[]>;
39
+ /**
40
+ * Heuristic-based classification using tags and content analysis
41
+ */
42
+ private classifyWithHeuristics;
43
+ /**
44
+ * LLM-based classification (when enabled)
45
+ */
46
+ private classifyWithLLM;
47
+ /**
48
+ * Add a chunk to a category
49
+ */
50
+ addToCategory(chunkId: string, categoryName: string, relevanceScore: number): void;
51
+ /**
52
+ * Classify and add a chunk to all relevant categories
53
+ */
54
+ classifyAndAssign(chunk: EnhancedChunk): Promise<CategoryClassification[]>;
55
+ /**
56
+ * Get items in a category
57
+ */
58
+ getCategoryItems(categoryName: string, options?: CategoryItemsOptions): CategoryItem[];
59
+ /**
60
+ * Evolve a category's summary with new items
61
+ */
62
+ evolveSummary(categoryName: string): Promise<SummaryEvolutionResult | null>;
63
+ /**
64
+ * Heuristic-based summary evolution
65
+ */
66
+ private evolveSummaryWithHeuristics;
67
+ /**
68
+ * LLM-based summary evolution
69
+ */
70
+ private evolveSummaryWithLLM;
71
+ /**
72
+ * Get category summary for retrieval
73
+ */
74
+ getCategorySummary(categoryName: string): string | null;
75
+ /**
76
+ * Select categories most relevant to a query
77
+ */
78
+ selectRelevantCategories(query: string, options?: CategorySelectionOptions): Promise<SelectedCategory[]>;
79
+ /**
80
+ * Heuristic-based category selection
81
+ */
82
+ private selectCategoriesWithHeuristics;
83
+ /**
84
+ * LLM-based category selection
85
+ */
86
+ private selectCategoriesWithLLM;
87
+ /**
88
+ * Get all categories with statistics
89
+ */
90
+ getAllCategoriesWithStats(): CategoryWithStats[];
91
+ /**
92
+ * Create a custom category
93
+ */
94
+ createCategory(definition: CategoryDefinition): Category;
95
+ /**
96
+ * Extract tags from a chunk for classification
97
+ */
98
+ private extractTagsFromChunk;
99
+ /**
100
+ * Match categories by keyword presence in content
101
+ */
102
+ private matchCategoriesByKeywords;
103
+ /**
104
+ * Call LLM endpoint
105
+ */
106
+ private callLLM;
107
+ }
108
+ export declare function getCategoryManager(metadataStore?: MemoryMetadataStore, config?: Partial<CategoryManagerConfig>): CategoryManager;
109
+ export declare function resetCategoryManager(): void;
110
+ //# sourceMappingURL=categoryManager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"categoryManager.d.ts","sourceRoot":"","sources":["../../src/services/categoryManager.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,kBAAkB,EACvB,KAAK,sBAAsB,EAC3B,KAAK,oBAAoB,EACzB,KAAK,iBAAiB,EACtB,KAAK,wBAAwB,EAC7B,KAAK,gBAAgB,EACrB,KAAK,sBAAsB,EAG5B,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,aAAa,EAAwB,MAAM,oBAAoB,CAAC;AACtG,OAAO,EAAE,mBAAmB,EAA0B,MAAM,0BAA0B,CAAC;AAEvF;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,qBAAqB,EAAE,MAAM,CAAC;IAC9B,eAAe,EAAE,MAAM,CAAC;IACxB,uBAAuB,EAAE,OAAO,CAAC;IACjC,kBAAkB,EAAE,OAAO,CAAC;IAC5B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAUD;;;;;;;;GAQG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,aAAa,CAAsB;IAC3C,OAAO,CAAC,MAAM,CAAwB;IACtC,OAAO,CAAC,WAAW,CAAkB;gBAGnC,aAAa,CAAC,EAAE,mBAAmB,EACnC,MAAM,CAAC,EAAE,OAAO,CAAC,qBAAqB,CAAC;IAMzC;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAqBjC;;OAEG;IACG,aAAa,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,sBAAsB,EAAE,CAAC;IAU5E;;OAEG;IACH,OAAO,CAAC,sBAAsB;IAkC9B;;OAEG;YACW,eAAe;IAoC7B;;OAEG;IACH,aAAa,CACX,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,MAAM,EACpB,cAAc,EAAE,MAAM,GACrB,IAAI;IAUP;;OAEG;IACG,iBAAiB,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,sBAAsB,EAAE,CAAC;IAUhF;;OAEG;IACH,gBAAgB,CACd,YAAY,EAAE,MAAM,EACpB,OAAO,GAAE,oBAAyB,GACjC,YAAY,EAAE;IA8BjB;;OAEG;IACG,aAAa,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,sBAAsB,GAAG,IAAI,CAAC;IAkCjF;;OAEG;IACH,OAAO,CAAC,2BAA2B;IA6CnC;;OAEG;YACW,oBAAoB;IAkDlC;;OAEG;IACH,kBAAkB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAKvD;;OAEG;IACG,wBAAwB,CAC5B,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,wBAA6B,GACrC,OAAO,CAAC,gBAAgB,EAAE,CAAC;IAkB9B;;OAEG;IACH,OAAO,CAAC,8BAA8B;IAqCtC;;OAEG;YACW,uBAAuB;IAsCrC;;OAEG;IACH,yBAAyB,IAAI,iBAAiB,EAAE;IAmBhD;;OAEG;IACH,cAAc,CAAC,UAAU,EAAE,kBAAkB,GAAG,QAAQ;IAexD;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAkC5B;;OAEG;IACH,OAAO,CAAC,yBAAyB;IAuEjC;;OAEG;YACW,OAAO;CAyBtB;AAID,wBAAgB,kBAAkB,CAChC,aAAa,CAAC,EAAE,mBAAmB,EACnC,MAAM,CAAC,EAAE,OAAO,CAAC,qBAAqB,CAAC,GACtC,eAAe,CAKjB;AAED,wBAAgB,oBAAoB,IAAI,IAAI,CAE3C"}
@@ -0,0 +1,549 @@
1
+ import { DEFAULT_CATEGORIES, scoreCategoryMatch, } from '../types/categories.js';
2
+ import { getMemoryMetadataStore } from './memoryMetadataStore.js';
3
+ const DEFAULT_CONFIG = {
4
+ minRelevanceScore: 0.4,
5
+ maxCategoriesPerChunk: 3,
6
+ summaryMaxItems: 20,
7
+ useLLMForClassification: false,
8
+ useLLMForSummaries: false,
9
+ };
10
+ /**
11
+ * Manages category organization and summary evolution
12
+ *
13
+ * The CategoryManager provides:
14
+ * - Automatic initialization of default categories
15
+ * - Classification of chunks into relevant categories
16
+ * - Evolving summaries that integrate new knowledge
17
+ * - Query-based category selection for retrieval
18
+ */
19
+ export class CategoryManager {
20
+ metadataStore;
21
+ config;
22
+ initialized = false;
23
+ constructor(metadataStore, config) {
24
+ this.metadataStore = metadataStore || getMemoryMetadataStore();
25
+ this.config = { ...DEFAULT_CONFIG, ...config };
26
+ }
27
+ /**
28
+ * Initialize default categories if they don't exist
29
+ */
30
+ async initialize() {
31
+ if (this.initialized)
32
+ return;
33
+ for (const catDef of DEFAULT_CATEGORIES) {
34
+ const existing = this.metadataStore.getCategoryByName(catDef.name);
35
+ if (!existing) {
36
+ const category = {
37
+ id: `cat:${catDef.name}`,
38
+ name: catDef.name,
39
+ description: catDef.description,
40
+ parentId: catDef.parentName ? `cat:${catDef.parentName}` : null,
41
+ summary: '',
42
+ chunkCount: 0,
43
+ };
44
+ this.metadataStore.upsertCategory(category);
45
+ }
46
+ }
47
+ this.initialized = true;
48
+ }
49
+ /**
50
+ * Classify a chunk into relevant categories
51
+ */
52
+ async classifyChunk(chunk) {
53
+ await this.initialize();
54
+ if (this.config.useLLMForClassification) {
55
+ return this.classifyWithLLM(chunk);
56
+ }
57
+ return this.classifyWithHeuristics(chunk);
58
+ }
59
+ /**
60
+ * Heuristic-based classification using tags and content analysis
61
+ */
62
+ classifyWithHeuristics(chunk) {
63
+ const classifications = [];
64
+ const contentTags = this.extractTagsFromChunk(chunk);
65
+ for (const catDef of DEFAULT_CATEGORIES) {
66
+ const score = scoreCategoryMatch(contentTags, catDef);
67
+ if (score >= this.config.minRelevanceScore) {
68
+ classifications.push({
69
+ category: catDef.name,
70
+ relevanceScore: score,
71
+ reason: `Matched tags: ${catDef.tags.filter(t => contentTags.some(ct => ct.toLowerCase().includes(t.toLowerCase()))).join(', ')}`,
72
+ });
73
+ }
74
+ }
75
+ const keywordMatches = this.matchCategoriesByKeywords(chunk.content);
76
+ for (const match of keywordMatches) {
77
+ const existing = classifications.find(c => c.category === match.category);
78
+ if (existing) {
79
+ existing.relevanceScore = Math.min(1.0, existing.relevanceScore + match.relevanceScore * 0.3);
80
+ }
81
+ else if (match.relevanceScore >= this.config.minRelevanceScore) {
82
+ classifications.push(match);
83
+ }
84
+ }
85
+ return classifications
86
+ .sort((a, b) => b.relevanceScore - a.relevanceScore)
87
+ .slice(0, this.config.maxCategoriesPerChunk);
88
+ }
89
+ /**
90
+ * LLM-based classification (when enabled)
91
+ */
92
+ async classifyWithLLM(chunk) {
93
+ if (!this.config.llmEndpoint) {
94
+ console.warn('LLM classification enabled but no endpoint configured, falling back to heuristics');
95
+ return this.classifyWithHeuristics(chunk);
96
+ }
97
+ const categories = this.metadataStore.listCategories();
98
+ const prompt = `Classify this knowledge item into one or more categories.
99
+
100
+ ## Item
101
+ Type: ${chunk.chunkType}
102
+ Content: ${chunk.content.substring(0, 2000)}
103
+
104
+ ## Available Categories
105
+ ${categories.map(c => `- ${c.name}: ${c.description}`).join('\n')}
106
+
107
+ ## Instructions
108
+ Return a JSON array of classifications:
109
+ [
110
+ { "category": "category_name", "relevanceScore": 0.0-1.0, "reason": "brief reason" }
111
+ ]
112
+
113
+ Only include categories with relevanceScore > ${this.config.minRelevanceScore}.
114
+ Maximum ${this.config.maxCategoriesPerChunk} categories.`;
115
+ try {
116
+ const response = await this.callLLM(prompt);
117
+ const parsed = JSON.parse(response);
118
+ return Array.isArray(parsed) ? parsed : [];
119
+ }
120
+ catch (error) {
121
+ console.error('LLM classification failed, falling back to heuristics:', error);
122
+ return this.classifyWithHeuristics(chunk);
123
+ }
124
+ }
125
+ /**
126
+ * Add a chunk to a category
127
+ */
128
+ addToCategory(chunkId, categoryName, relevanceScore) {
129
+ const category = this.metadataStore.getCategoryByName(categoryName);
130
+ if (!category) {
131
+ console.warn(`Category not found: ${categoryName}`);
132
+ return;
133
+ }
134
+ this.metadataStore.assignChunkToCategory(chunkId, category.id, relevanceScore);
135
+ }
136
+ /**
137
+ * Classify and add a chunk to all relevant categories
138
+ */
139
+ async classifyAndAssign(chunk) {
140
+ const classifications = await this.classifyChunk(chunk);
141
+ for (const classification of classifications) {
142
+ this.addToCategory(chunk.id, classification.category, classification.relevanceScore);
143
+ }
144
+ return classifications;
145
+ }
146
+ /**
147
+ * Get items in a category
148
+ */
149
+ getCategoryItems(categoryName, options = {}) {
150
+ const category = this.metadataStore.getCategoryByName(categoryName);
151
+ if (!category)
152
+ return [];
153
+ const allItems = this.metadataStore.getCategoryChunks(category.id);
154
+ let items = allItems;
155
+ if (options.minRelevance) {
156
+ items = items.filter(item => item.relevanceScore >= options.minRelevance);
157
+ }
158
+ if (options.since) {
159
+ const sinceStr = options.since.toISOString();
160
+ items = items.filter(item => item.assignedAt >= sinceStr);
161
+ }
162
+ if (options.sortBy === 'relevance') {
163
+ items.sort((a, b) => b.relevanceScore - a.relevanceScore);
164
+ }
165
+ else {
166
+ items.sort((a, b) => b.assignedAt.localeCompare(a.assignedAt));
167
+ }
168
+ if (options.limit) {
169
+ items = items.slice(0, options.limit);
170
+ }
171
+ return items;
172
+ }
173
+ /**
174
+ * Evolve a category's summary with new items
175
+ */
176
+ async evolveSummary(categoryName) {
177
+ const category = this.metadataStore.getCategoryByName(categoryName);
178
+ if (!category)
179
+ return null;
180
+ const recentItems = this.getCategoryItems(categoryName, {
181
+ limit: this.config.summaryMaxItems,
182
+ sortBy: 'date',
183
+ });
184
+ if (recentItems.length === 0) {
185
+ return {
186
+ categoryName,
187
+ previousSummary: category.summary,
188
+ newSummary: category.summary,
189
+ itemsIntegrated: 0,
190
+ hadContradictions: false,
191
+ };
192
+ }
193
+ const itemContents = [];
194
+ for (const item of recentItems) {
195
+ const metadata = this.metadataStore.getChunkMetadata(item.chunkId);
196
+ if (metadata) {
197
+ itemContents.push(`[${metadata.chunkType}] Relevance: ${item.relevanceScore.toFixed(2)}`);
198
+ }
199
+ }
200
+ if (this.config.useLLMForSummaries && this.config.llmEndpoint) {
201
+ return this.evolveSummaryWithLLM(category, itemContents);
202
+ }
203
+ return this.evolveSummaryWithHeuristics(category, recentItems);
204
+ }
205
+ /**
206
+ * Heuristic-based summary evolution
207
+ */
208
+ evolveSummaryWithHeuristics(category, items) {
209
+ const previousSummary = category.summary;
210
+ const chunkTypes = new Map();
211
+ for (const item of items) {
212
+ const metadata = this.metadataStore.getChunkMetadata(item.chunkId);
213
+ if (metadata) {
214
+ const count = chunkTypes.get(metadata.chunkType) || 0;
215
+ chunkTypes.set(metadata.chunkType, count + 1);
216
+ }
217
+ }
218
+ const typeBreakdown = Array.from(chunkTypes.entries())
219
+ .map(([type, count]) => `${count} ${type}(s)`)
220
+ .join(', ');
221
+ const avgRelevance = items.reduce((sum, i) => sum + i.relevanceScore, 0) / items.length;
222
+ const newSummary = `## ${category.name}
223
+
224
+ **Items**: ${category.chunkCount}
225
+ **Recent**: ${items.length} items (${typeBreakdown})
226
+ **Avg Relevance**: ${avgRelevance.toFixed(2)}
227
+
228
+ ${previousSummary ? `### Previous Summary\n${previousSummary}` : 'No previous summary.'}
229
+
230
+ *Last updated: ${new Date().toISOString()}*`;
231
+ this.metadataStore.upsertCategory({
232
+ ...category,
233
+ summary: newSummary,
234
+ });
235
+ return {
236
+ categoryName: category.name,
237
+ previousSummary,
238
+ newSummary,
239
+ itemsIntegrated: items.length,
240
+ hadContradictions: false,
241
+ };
242
+ }
243
+ /**
244
+ * LLM-based summary evolution
245
+ */
246
+ async evolveSummaryWithLLM(category, itemContents) {
247
+ const prompt = `You are a Memory Synchronisation Specialist.
248
+
249
+ ## Category: ${category.name}
250
+ ${category.description}
251
+
252
+ ## Current Summary
253
+ ${category.summary || 'No existing summary.'}
254
+
255
+ ## New Items to Integrate (${itemContents.length} items)
256
+ ${itemContents.slice(0, 10).join('\n')}
257
+ ${itemContents.length > 10 ? `\n... and ${itemContents.length - 10} more items` : ''}
258
+
259
+ ## Instructions
260
+ 1. Update the summary to incorporate new information
261
+ 2. If new items conflict with existing summary, update to reflect the latest state
262
+ 3. Keep the summary concise but comprehensive (max 500 words)
263
+ 4. Use markdown formatting
264
+ 5. Focus on actionable knowledge, patterns, and decisions
265
+
266
+ Return ONLY the updated summary markdown.`;
267
+ try {
268
+ const newSummary = await this.callLLM(prompt);
269
+ const hadContradictions = newSummary.toLowerCase().includes('previously') ||
270
+ newSummary.toLowerCase().includes('updated') ||
271
+ newSummary.toLowerCase().includes('changed from');
272
+ this.metadataStore.upsertCategory({
273
+ ...category,
274
+ summary: newSummary,
275
+ });
276
+ return {
277
+ categoryName: category.name,
278
+ previousSummary: category.summary,
279
+ newSummary,
280
+ itemsIntegrated: itemContents.length,
281
+ hadContradictions,
282
+ };
283
+ }
284
+ catch (error) {
285
+ console.error('LLM summary evolution failed:', error);
286
+ return this.evolveSummaryWithHeuristics(category, []);
287
+ }
288
+ }
289
+ /**
290
+ * Get category summary for retrieval
291
+ */
292
+ getCategorySummary(categoryName) {
293
+ const category = this.metadataStore.getCategoryByName(categoryName);
294
+ return category?.summary || null;
295
+ }
296
+ /**
297
+ * Select categories most relevant to a query
298
+ */
299
+ async selectRelevantCategories(query, options = {}) {
300
+ await this.initialize();
301
+ const maxCategories = options.maxCategories ?? 3;
302
+ const minItemCount = options.minItemCount ?? 1;
303
+ const categories = this.metadataStore.listCategories()
304
+ .filter(c => c.chunkCount >= minItemCount);
305
+ if (categories.length === 0)
306
+ return [];
307
+ if (this.config.useLLMForClassification && this.config.llmEndpoint) {
308
+ return this.selectCategoriesWithLLM(query, categories, options);
309
+ }
310
+ return this.selectCategoriesWithHeuristics(query, categories, options);
311
+ }
312
+ /**
313
+ * Heuristic-based category selection
314
+ */
315
+ selectCategoriesWithHeuristics(query, categories, options) {
316
+ const queryLower = query.toLowerCase();
317
+ const queryWords = queryLower.split(/\s+/).filter(w => w.length > 2);
318
+ const scored = [];
319
+ for (const category of categories) {
320
+ const catDef = DEFAULT_CATEGORIES.find(c => c.name === category.name);
321
+ if (!catDef)
322
+ continue;
323
+ let relevance = 0;
324
+ for (const word of queryWords) {
325
+ if (catDef.name.includes(word))
326
+ relevance += 0.3;
327
+ if (catDef.description.toLowerCase().includes(word))
328
+ relevance += 0.2;
329
+ if (catDef.tags.some(t => t.includes(word) || word.includes(t)))
330
+ relevance += 0.25;
331
+ }
332
+ if (relevance > 0) {
333
+ scored.push({
334
+ name: category.name,
335
+ relevance: Math.min(1.0, relevance),
336
+ summary: options.includeSummaries ? category.summary : undefined,
337
+ itemCount: category.chunkCount,
338
+ });
339
+ }
340
+ }
341
+ return scored
342
+ .sort((a, b) => b.relevance - a.relevance)
343
+ .slice(0, options.maxCategories ?? 3);
344
+ }
345
+ /**
346
+ * LLM-based category selection
347
+ */
348
+ async selectCategoriesWithLLM(query, categories, options) {
349
+ const prompt = `Query: ${query}
350
+
351
+ Available Categories:
352
+ ${categories.map(c => `- ${c.name}: ${c.description} (${c.chunkCount} items)`).join('\n')}
353
+
354
+ Return a JSON array of the ${options.maxCategories ?? 3} most relevant category names:
355
+ ["category1", "category2", ...]
356
+
357
+ Only include categories clearly relevant to the query.`;
358
+ try {
359
+ const response = await this.callLLM(prompt);
360
+ const names = JSON.parse(response);
361
+ const results = [];
362
+ for (const name of names) {
363
+ const cat = categories.find(c => c.name === name);
364
+ if (cat) {
365
+ results.push({
366
+ name: cat.name,
367
+ relevance: 0.8,
368
+ summary: options.includeSummaries ? cat.summary : undefined,
369
+ itemCount: cat.chunkCount,
370
+ });
371
+ }
372
+ }
373
+ return results;
374
+ }
375
+ catch (error) {
376
+ console.error('LLM category selection failed:', error);
377
+ return this.selectCategoriesWithHeuristics(query, categories, options);
378
+ }
379
+ }
380
+ /**
381
+ * Get all categories with statistics
382
+ */
383
+ getAllCategoriesWithStats() {
384
+ const categories = this.metadataStore.listCategories();
385
+ return categories.map(cat => {
386
+ const catDef = DEFAULT_CATEGORIES.find(c => c.name === cat.name);
387
+ const items = this.getCategoryItems(cat.name, { limit: 100 });
388
+ const avgRelevance = items.length > 0
389
+ ? items.reduce((sum, i) => sum + i.relevanceScore, 0) / items.length
390
+ : 0;
391
+ return {
392
+ ...cat,
393
+ recentItemCount: items.length,
394
+ avgRelevanceScore: avgRelevance,
395
+ topTags: catDef?.tags.slice(0, 5) ?? [],
396
+ };
397
+ });
398
+ }
399
+ /**
400
+ * Create a custom category
401
+ */
402
+ createCategory(definition) {
403
+ const category = {
404
+ id: `cat:${definition.name}`,
405
+ name: definition.name,
406
+ description: definition.description,
407
+ parentId: definition.parentName ? `cat:${definition.parentName}` : null,
408
+ summary: '',
409
+ chunkCount: 0,
410
+ };
411
+ this.metadataStore.upsertCategory(category);
412
+ return this.metadataStore.getCategoryByName(definition.name);
413
+ }
414
+ /**
415
+ * Extract tags from a chunk for classification
416
+ */
417
+ extractTagsFromChunk(chunk) {
418
+ const tags = [];
419
+ if (chunk.entities) {
420
+ for (const entity of chunk.entities) {
421
+ tags.push(entity.value.toLowerCase());
422
+ }
423
+ }
424
+ const content = chunk.content.toLowerCase();
425
+ const techPatterns = [
426
+ /\b(typescript|javascript|python|php|java|go|rust|ruby)\b/gi,
427
+ /\b(react|vue|angular|svelte|next\.?js|nuxt)\b/gi,
428
+ /\b(postgresql|mysql|sqlite|mongodb|redis|elasticsearch)\b/gi,
429
+ /\b(docker|kubernetes|aws|gcp|azure|vercel|cloudflare)\b/gi,
430
+ /\b(api|rest|graphql|grpc|websocket)\b/gi,
431
+ /\b(test|spec|mock|fixture|coverage)\b/gi,
432
+ /\b(auth|login|session|jwt|oauth|token)\b/gi,
433
+ /\b(cache|performance|optimize|speed)\b/gi,
434
+ /\b(error|bug|fix|debug|issue|exception)\b/gi,
435
+ /\b(deploy|ci|cd|pipeline|build)\b/gi,
436
+ ];
437
+ for (const pattern of techPatterns) {
438
+ const matches = content.match(pattern);
439
+ if (matches) {
440
+ tags.push(...matches.map(m => m.toLowerCase()));
441
+ }
442
+ }
443
+ return [...new Set(tags)];
444
+ }
445
+ /**
446
+ * Match categories by keyword presence in content
447
+ */
448
+ matchCategoriesByKeywords(content) {
449
+ const contentLower = content.toLowerCase();
450
+ const classifications = [];
451
+ const keywordMap = {
452
+ 'authentication': [{ category: 'authentication', weight: 0.8 }],
453
+ 'login': [{ category: 'authentication', weight: 0.7 }],
454
+ 'password': [{ category: 'authentication', weight: 0.6 }],
455
+ 'jwt': [{ category: 'authentication', weight: 0.8 }],
456
+ 'oauth': [{ category: 'authentication', weight: 0.8 }],
457
+ 'database': [{ category: 'database', weight: 0.8 }],
458
+ 'query': [{ category: 'database', weight: 0.5 }],
459
+ 'migration': [{ category: 'database', weight: 0.7 }],
460
+ 'sql': [{ category: 'database', weight: 0.7 }],
461
+ 'api': [{ category: 'api', weight: 0.7 }],
462
+ 'endpoint': [{ category: 'api', weight: 0.7 }],
463
+ 'rest': [{ category: 'api', weight: 0.7 }],
464
+ 'graphql': [{ category: 'api', weight: 0.8 }],
465
+ 'test': [{ category: 'testing', weight: 0.6 }],
466
+ 'spec': [{ category: 'testing', weight: 0.6 }],
467
+ 'mock': [{ category: 'testing', weight: 0.7 }],
468
+ 'assert': [{ category: 'testing', weight: 0.7 }],
469
+ 'component': [{ category: 'frontend', weight: 0.6 }],
470
+ 'css': [{ category: 'frontend', weight: 0.7 }],
471
+ 'style': [{ category: 'frontend', weight: 0.5 }],
472
+ 'docker': [{ category: 'devops', weight: 0.8 }],
473
+ 'deploy': [{ category: 'devops', weight: 0.7 }],
474
+ 'ci/cd': [{ category: 'devops', weight: 0.8 }],
475
+ 'kubernetes': [{ category: 'devops', weight: 0.8 }],
476
+ 'pattern': [{ category: 'architecture', weight: 0.6 }],
477
+ 'architecture': [{ category: 'architecture', weight: 0.8 }],
478
+ 'design': [{ category: 'architecture', weight: 0.5 }],
479
+ 'performance': [{ category: 'performance', weight: 0.8 }],
480
+ 'cache': [{ category: 'performance', weight: 0.7 }],
481
+ 'optimize': [{ category: 'performance', weight: 0.7 }],
482
+ 'error': [{ category: 'debugging', weight: 0.6 }],
483
+ 'bug': [{ category: 'debugging', weight: 0.7 }],
484
+ 'fix': [{ category: 'debugging', weight: 0.5 }],
485
+ 'debug': [{ category: 'debugging', weight: 0.8 }],
486
+ 'convention': [{ category: 'standards', weight: 0.7 }],
487
+ 'standard': [{ category: 'standards', weight: 0.7 }],
488
+ 'best practice': [{ category: 'standards', weight: 0.8 }],
489
+ };
490
+ const categoryScores = new Map();
491
+ for (const [keyword, mappings] of Object.entries(keywordMap)) {
492
+ if (contentLower.includes(keyword)) {
493
+ for (const mapping of mappings) {
494
+ const existing = categoryScores.get(mapping.category) || { score: 0, reasons: [] };
495
+ existing.score += mapping.weight;
496
+ existing.reasons.push(keyword);
497
+ categoryScores.set(mapping.category, existing);
498
+ }
499
+ }
500
+ }
501
+ for (const [category, data] of categoryScores) {
502
+ const normalizedScore = Math.min(1.0, data.score / 2);
503
+ if (normalizedScore >= this.config.minRelevanceScore) {
504
+ classifications.push({
505
+ category,
506
+ relevanceScore: normalizedScore,
507
+ reason: `Keywords: ${data.reasons.slice(0, 3).join(', ')}`,
508
+ });
509
+ }
510
+ }
511
+ return classifications;
512
+ }
513
+ /**
514
+ * Call LLM endpoint
515
+ */
516
+ async callLLM(prompt) {
517
+ if (!this.config.llmEndpoint) {
518
+ throw new Error('LLM endpoint not configured');
519
+ }
520
+ const response = await fetch(this.config.llmEndpoint, {
521
+ method: 'POST',
522
+ headers: {
523
+ 'Content-Type': 'application/json',
524
+ ...(this.config.llmApiKey && { 'Authorization': `Bearer ${this.config.llmApiKey}` }),
525
+ },
526
+ body: JSON.stringify({
527
+ model: this.config.llmModel || 'gpt-4o-mini',
528
+ messages: [{ role: 'user', content: prompt }],
529
+ temperature: 0.3,
530
+ }),
531
+ });
532
+ if (!response.ok) {
533
+ throw new Error(`LLM request failed: ${response.status}`);
534
+ }
535
+ const data = await response.json();
536
+ return data.choices?.[0]?.message?.content || '';
537
+ }
538
+ }
539
+ let instance = null;
540
+ export function getCategoryManager(metadataStore, config) {
541
+ if (!instance) {
542
+ instance = new CategoryManager(metadataStore, config);
543
+ }
544
+ return instance;
545
+ }
546
+ export function resetCategoryManager() {
547
+ instance = null;
548
+ }
549
+ //# sourceMappingURL=categoryManager.js.map