@nxuss/lemma 0.9.3 → 1.0.1

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 (93) hide show
  1. package/README.md +35 -4
  2. package/bin/cli.js +97 -0
  3. package/bin/init.js +307 -0
  4. package/cache-proxy.js +191 -0
  5. package/dist/cjs/autopilot/AutopilotWatcher.d.ts +3 -2
  6. package/dist/cjs/autopilot/AutopilotWatcher.d.ts.map +1 -1
  7. package/dist/cjs/autopilot/AutopilotWatcher.js +48 -54
  8. package/dist/cjs/autopilot/AutopilotWatcher.js.map +1 -1
  9. package/dist/cjs/autopilot/Notifier.d.ts +5 -0
  10. package/dist/cjs/autopilot/Notifier.d.ts.map +1 -0
  11. package/dist/cjs/autopilot/Notifier.js +59 -0
  12. package/dist/cjs/autopilot/Notifier.js.map +1 -0
  13. package/dist/cjs/autopilot/PatchStore.d.ts +26 -0
  14. package/dist/cjs/autopilot/PatchStore.d.ts.map +1 -0
  15. package/dist/cjs/autopilot/PatchStore.js +88 -0
  16. package/dist/cjs/autopilot/PatchStore.js.map +1 -0
  17. package/dist/cjs/cli/lemma-proxy.d.ts.map +1 -1
  18. package/dist/cjs/cli/lemma-proxy.js +123 -4
  19. package/dist/cjs/cli/lemma-proxy.js.map +1 -1
  20. package/dist/cjs/mcp/index.js +1 -1
  21. package/dist/cjs/mcp/tools.d.ts.map +1 -1
  22. package/dist/cjs/mcp/tools.js +303 -77
  23. package/dist/cjs/mcp/tools.js.map +1 -1
  24. package/dist/cjs/subconscious/TheBrainV2.d.ts +102 -0
  25. package/dist/cjs/subconscious/TheBrainV2.d.ts.map +1 -0
  26. package/dist/cjs/subconscious/TheBrainV2.js +444 -0
  27. package/dist/cjs/subconscious/TheBrainV2.js.map +1 -0
  28. package/dist/cjs/utils/ContextCollapser.d.ts +21 -0
  29. package/dist/cjs/utils/ContextCollapser.d.ts.map +1 -0
  30. package/dist/cjs/utils/ContextCollapser.js +132 -0
  31. package/dist/cjs/utils/ContextCollapser.js.map +1 -0
  32. package/dist/cjs/utils/ExecutiveReport.d.ts +29 -0
  33. package/dist/cjs/utils/ExecutiveReport.d.ts.map +1 -0
  34. package/dist/cjs/utils/ExecutiveReport.js +111 -0
  35. package/dist/cjs/utils/ExecutiveReport.js.map +1 -0
  36. package/dist/cjs/utils/SurgicalASTInsert.d.ts +21 -0
  37. package/dist/cjs/utils/SurgicalASTInsert.d.ts.map +1 -0
  38. package/dist/cjs/utils/SurgicalASTInsert.js +173 -0
  39. package/dist/cjs/utils/SurgicalASTInsert.js.map +1 -0
  40. package/dist/cjs/utils/SymbolSurgicalContext.d.ts +25 -0
  41. package/dist/cjs/utils/SymbolSurgicalContext.d.ts.map +1 -0
  42. package/dist/cjs/utils/SymbolSurgicalContext.js +265 -0
  43. package/dist/cjs/utils/SymbolSurgicalContext.js.map +1 -0
  44. package/dist/cjs/utils/WormholeCompressor.d.ts +22 -0
  45. package/dist/cjs/utils/WormholeCompressor.d.ts.map +1 -0
  46. package/dist/cjs/utils/WormholeCompressor.js +152 -0
  47. package/dist/cjs/utils/WormholeCompressor.js.map +1 -0
  48. package/dist/esm/autopilot/AutopilotWatcher.d.ts +3 -2
  49. package/dist/esm/autopilot/AutopilotWatcher.d.ts.map +1 -1
  50. package/dist/esm/autopilot/AutopilotWatcher.js +48 -54
  51. package/dist/esm/autopilot/AutopilotWatcher.js.map +1 -1
  52. package/dist/esm/autopilot/Notifier.d.ts +5 -0
  53. package/dist/esm/autopilot/Notifier.d.ts.map +1 -0
  54. package/dist/esm/autopilot/Notifier.js +51 -0
  55. package/dist/esm/autopilot/Notifier.js.map +1 -0
  56. package/dist/esm/autopilot/PatchStore.d.ts +26 -0
  57. package/dist/esm/autopilot/PatchStore.d.ts.map +1 -0
  58. package/dist/esm/autopilot/PatchStore.js +77 -0
  59. package/dist/esm/autopilot/PatchStore.js.map +1 -0
  60. package/dist/esm/cli/lemma-proxy.d.ts.map +1 -1
  61. package/dist/esm/cli/lemma-proxy.js +123 -4
  62. package/dist/esm/cli/lemma-proxy.js.map +1 -1
  63. package/dist/esm/mcp/index.js +1 -1
  64. package/dist/esm/mcp/tools.d.ts.map +1 -1
  65. package/dist/esm/mcp/tools.js +303 -77
  66. package/dist/esm/mcp/tools.js.map +1 -1
  67. package/dist/esm/subconscious/TheBrainV2.d.ts +102 -0
  68. package/dist/esm/subconscious/TheBrainV2.d.ts.map +1 -0
  69. package/dist/esm/subconscious/TheBrainV2.js +431 -0
  70. package/dist/esm/subconscious/TheBrainV2.js.map +1 -0
  71. package/dist/esm/utils/ContextCollapser.d.ts +21 -0
  72. package/dist/esm/utils/ContextCollapser.d.ts.map +1 -0
  73. package/dist/esm/utils/ContextCollapser.js +128 -0
  74. package/dist/esm/utils/ContextCollapser.js.map +1 -0
  75. package/dist/esm/utils/ExecutiveReport.d.ts +29 -0
  76. package/dist/esm/utils/ExecutiveReport.d.ts.map +1 -0
  77. package/dist/esm/utils/ExecutiveReport.js +105 -0
  78. package/dist/esm/utils/ExecutiveReport.js.map +1 -0
  79. package/dist/esm/utils/SurgicalASTInsert.d.ts +21 -0
  80. package/dist/esm/utils/SurgicalASTInsert.d.ts.map +1 -0
  81. package/dist/esm/utils/SurgicalASTInsert.js +134 -0
  82. package/dist/esm/utils/SurgicalASTInsert.js.map +1 -0
  83. package/dist/esm/utils/SymbolSurgicalContext.d.ts +25 -0
  84. package/dist/esm/utils/SymbolSurgicalContext.d.ts.map +1 -0
  85. package/dist/esm/utils/SymbolSurgicalContext.js +226 -0
  86. package/dist/esm/utils/SymbolSurgicalContext.js.map +1 -0
  87. package/dist/esm/utils/WormholeCompressor.d.ts +22 -0
  88. package/dist/esm/utils/WormholeCompressor.d.ts.map +1 -0
  89. package/dist/esm/utils/WormholeCompressor.js +148 -0
  90. package/dist/esm/utils/WormholeCompressor.js.map +1 -0
  91. package/lemma-proxy.cjs +31 -14
  92. package/mcp-server.js +220 -0
  93. package/package.json +7 -2
package/mcp-server.js ADDED
@@ -0,0 +1,220 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ const fs = require('fs');
5
+ const path = require('path');
6
+ const os = require('os');
7
+
8
+ const BRAIN_FILE = path.join(os.homedir(), '.lemma-cache', 'lemma_brain.json');
9
+ const INPUT_COST = 3.00 / 1000000;
10
+ const OUTPUT_COST = 15.00 / 1000000;
11
+
12
+ function loadBrain() {
13
+ try {
14
+ if (!fs.existsSync(BRAIN_FILE)) {
15
+ fs.mkdirSync(path.dirname(BRAIN_FILE), { recursive: true });
16
+ fs.writeFileSync(BRAIN_FILE, '[]', 'utf8');
17
+ return [];
18
+ }
19
+ const raw = fs.readFileSync(BRAIN_FILE, 'utf8');
20
+ return JSON.parse(raw);
21
+ } catch (e) {
22
+ console.error('[lemma-mcp] Failed to load brain, initializing empty:', e.message);
23
+ return [];
24
+ }
25
+ }
26
+
27
+ function saveBrain(data) {
28
+ try {
29
+ fs.mkdirSync(path.dirname(BRAIN_FILE), { recursive: true });
30
+ fs.writeFileSync(BRAIN_FILE, JSON.stringify(data), 'utf8');
31
+ } catch (e) {
32
+ console.error('[lemma-mcp] Failed to save brain:', e.message);
33
+ }
34
+ }
35
+
36
+ function tokenize(text) {
37
+ const stopWords = new Set(['the','a','an','is','are','was','were','be','been','being','have','has','had','do','does','did','will','would','could','should','may','might','shall','can','need','dare','ought','used','to','of','in','for','on','with','at','by','from','as','into','through','during','before','after','above','below','between','out','off','over','under','again','further','then','once','here','there','when','where','why','how','all','each','every','both','few','more','most','other','some','such','no','nor','not','only','own','same','so','than','too','very','just','because','but','and','or','if','while','although','since','until','unless','about','up','it','its','this','that','these','those','i','me','my','myself','we','our','ours','ourselves','you','your','yours','yourself','yourselves','he','him','his','himself','she','her','hers','herself','they','them','their','theirs','themselves','what','which','who','whom','this']);
38
+ return text.toLowerCase().replace(/[^a-z0-9\s]/g, '').split(/\s+/).filter(w => w.length > 1 && !stopWords.has(w));
39
+ }
40
+
41
+ function idf(corpusTokens) {
42
+ const df = {};
43
+ const N = corpusTokens.length;
44
+ for (const tokens of corpusTokens) {
45
+ const seen = new Set(tokens);
46
+ for (const t of seen) df[t] = (df[t] || 0) + 1;
47
+ }
48
+ const scores = {};
49
+ for (const [t, count] of Object.entries(df)) {
50
+ scores[t] = Math.log(1 + (N - count + 0.5) / (count + 0.5));
51
+ }
52
+ return scores;
53
+ }
54
+
55
+ function bm25(queryTokens, docTokens, idfScores, avgDocLen) {
56
+ const k1 = 1.5;
57
+ const b = 0.75;
58
+ let score = 0;
59
+ const docLen = docTokens.length;
60
+ const tf = {};
61
+ for (const t of docTokens) tf[t] = (tf[t] || 0) + 1;
62
+ for (const q of queryTokens) {
63
+ const f = tf[q] || 0;
64
+ const idfVal = idfScores[q] || 0;
65
+ if (f === 0) continue;
66
+ score += idfVal * ((f * (k1 + 1)) / (f + k1 * (1 - b + b * (docLen / avgDocLen))));
67
+ }
68
+ return score;
69
+ }
70
+
71
+ function buildIndex(entries) {
72
+ if (!entries || entries.length === 0) return { corpusTokens: [], idfScores: {}, avgDocLen: 0 };
73
+ const corpusTokens = entries.map(e => tokenize(e.prompt || ''));
74
+ const avgDocLen = corpusTokens.reduce((s, t) => s + t.length, 0) / corpusTokens.length;
75
+ const idfScores = idf(corpusTokens);
76
+ return { corpusTokens, idfScores, avgDocLen };
77
+ }
78
+
79
+ function search(entries, query, threshold) {
80
+ if (!entries || entries.length === 0) return [];
81
+ const qt = tokenize(query);
82
+ if (qt.length === 0) return [];
83
+ const idx = buildIndex(entries);
84
+ const maxScore = bm25(qt, qt, idx.idfScores, idx.avgDocLen);
85
+ const results = entries.map((entry, i) => {
86
+ const raw = bm25(qt, idx.corpusTokens[i], idx.idfScores, idx.avgDocLen);
87
+ const similarity = maxScore > 0 ? raw / maxScore : 0;
88
+ return { entry, similarity, index: i };
89
+ }).filter(r => r.similarity >= threshold).sort((a, b) => b.similarity - a.similarity);
90
+ return results;
91
+ }
92
+
93
+ const tools = [
94
+ {
95
+ name: 'get_cached_solution',
96
+ description: 'Search the semantic cache (BM25) for a similar prompt. Hit >= 85% returns cached response.',
97
+ inputSchema: {
98
+ type: 'object',
99
+ properties: {
100
+ prompt: { type: 'string', description: 'The prompt to search for' },
101
+ threshold: { type: 'number', description: 'Similarity threshold 0-1', default: 0.85 }
102
+ },
103
+ required: ['prompt']
104
+ }
105
+ },
106
+ {
107
+ name: 'store_cached_solution',
108
+ description: 'Store a prompt-response pair in the semantic cache for future lookups.',
109
+ inputSchema: {
110
+ type: 'object',
111
+ properties: {
112
+ prompt: { type: 'string', description: 'The prompt' },
113
+ response: { type: 'string', description: 'The response' }
114
+ },
115
+ required: ['prompt', 'response']
116
+ }
117
+ }
118
+ ];
119
+
120
+ const toolHandlers = {
121
+ get_cached_solution: async (args) => {
122
+ const prompt = args.prompt;
123
+ const threshold = args.threshold || 0.85;
124
+ if (!prompt) throw new Error('prompt is required');
125
+ const brain = loadBrain();
126
+ const results = search(brain, prompt, threshold);
127
+ if (results.length > 0) {
128
+ const hit = results[0];
129
+ brain[hit.index].hits = (brain[hit.index].hits || 0) + 1;
130
+ saveBrain(brain);
131
+ return {
132
+ content: [{ type: 'text', text: JSON.stringify({
133
+ hit: true,
134
+ similarity: hit.similarity,
135
+ response: hit.entry.response,
136
+ hits: brain[hit.index].hits
137
+ }) }]
138
+ };
139
+ }
140
+ return { content: [{ type: 'text', text: JSON.stringify({ hit: false }) }] };
141
+ },
142
+ store_cached_solution: async (args) => {
143
+ const prompt = args.prompt;
144
+ const response = args.response;
145
+ if (!prompt || !response) throw new Error('prompt and response are required');
146
+ const brain = loadBrain();
147
+ brain.push({ prompt, response, hits: 0, createdAt: Date.now() });
148
+ saveBrain(brain);
149
+ return { content: [{ type: 'text', text: JSON.stringify({ success: true, total: brain.length }) }] };
150
+ }
151
+ };
152
+
153
+ const server = {
154
+ name: 'lemma-mcp-server',
155
+ version: '1.0.0',
156
+ tools,
157
+ toolHandlers
158
+ };
159
+
160
+ process.stdin.on('data', async (chunk) => {
161
+ const lines = chunk.toString().split('\n').filter(l => l.trim());
162
+ for (const line of lines) {
163
+ try {
164
+ const msg = JSON.parse(line);
165
+ if (msg.method === 'initialize') {
166
+ const resp = {
167
+ jsonrpc: '2.0',
168
+ id: msg.id,
169
+ result: {
170
+ protocolVersion: '2024-11-05',
171
+ serverInfo: { name: server.name, version: server.version },
172
+ capabilities: { tools: {} }
173
+ }
174
+ };
175
+ console.log(JSON.stringify(resp));
176
+ } else if (msg.method === 'tools/list') {
177
+ const resp = {
178
+ jsonrpc: '2.0',
179
+ id: msg.id,
180
+ result: { tools: server.tools }
181
+ };
182
+ console.log(JSON.stringify(resp));
183
+ } else if (msg.method === 'tools/call') {
184
+ const handler = server.toolHandlers[msg.params.name];
185
+ if (!handler) {
186
+ console.log(JSON.stringify({
187
+ jsonrpc: '2.0',
188
+ id: msg.id,
189
+ error: { code: -32601, message: `Tool not found: ${msg.params.name}` }
190
+ }));
191
+ continue;
192
+ }
193
+ try {
194
+ const result = await handler(msg.params.arguments || {});
195
+ console.log(JSON.stringify({ jsonrpc: '2.0', id: msg.id, result }));
196
+ } catch (e) {
197
+ console.log(JSON.stringify({
198
+ jsonrpc: '2.0',
199
+ id: msg.id,
200
+ error: { code: -32000, message: e.message }
201
+ }));
202
+ }
203
+ } else if (msg.method === 'notifications/initialized') {
204
+ } else if (msg.id) {
205
+ console.log(JSON.stringify({
206
+ jsonrpc: '2.0',
207
+ id: msg.id,
208
+ error: { code: -32601, message: `Method not found: ${msg.method}` }
209
+ }));
210
+ }
211
+ } catch (e) {
212
+ console.error('[lemma-mcp] Parse error:', e.message);
213
+ }
214
+ }
215
+ });
216
+
217
+ process.on('SIGINT', () => process.exit(0));
218
+ process.on('SIGTERM', () => process.exit(0));
219
+
220
+ console.error('[lemma-mcp] BM25 cache server ready on stdio');
package/package.json CHANGED
@@ -1,12 +1,13 @@
1
1
  {
2
2
  "name": "@nxuss/lemma",
3
- "version": "0.9.3",
3
+ "version": "1.0.1",
4
4
  "description": "Intelligent AI Gateway for IDEs & Agents — Semantic cache, Privacy Firewall, and Autonomous Cost-Optimization.",
5
5
  "main": "./dist/cjs/index.js",
6
6
  "module": "./dist/esm/index.js",
7
7
  "types": "./dist/esm/index.d.ts",
8
8
  "bin": {
9
- "lemma": "./lemma-proxy.cjs"
9
+ "lemma": "./lemma-proxy.cjs",
10
+ "lemma-mcp-server": "./mcp-server.js"
10
11
  },
11
12
  "exports": {
12
13
  ".": {
@@ -83,6 +84,10 @@
83
84
  "dist/cjs/**/*",
84
85
  "src/**/*.js",
85
86
  "lemma-proxy.cjs",
87
+ "mcp-server.js",
88
+ "cache-proxy.js",
89
+ "bin/init.js",
90
+ "bin/cli.js",
86
91
  "dashboard/dist/**/*",
87
92
  "!dist/examples/**",
88
93
  "README.md",