@nxuss/lemma 1.2.2 → 1.2.4
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/bin/cli.js +14 -3
- package/bin/init.js +35 -14
- package/cache-proxy.js +14 -2
- package/dist/cjs/mcp/tools.js +1 -1
- package/dist/cjs/mcp/tools.js.map +1 -1
- package/dist/esm/mcp/tools.js +1 -1
- package/dist/esm/mcp/tools.js.map +1 -1
- package/mcp-server.js +125 -194
- package/package.json +1 -2
package/bin/cli.js
CHANGED
|
@@ -8,7 +8,7 @@ const { execSync } = require('child_process');
|
|
|
8
8
|
|
|
9
9
|
const LEMMA_CACHE = path.join(os.homedir(), '.lemma-cache');
|
|
10
10
|
const BRAIN_FILE = path.join(LEMMA_CACHE, 'lemma_brain.json');
|
|
11
|
-
const
|
|
11
|
+
const PORT_FILE = path.join(LEMMA_CACHE, 'proxy.port');
|
|
12
12
|
|
|
13
13
|
const INPUT_COST = 3.00 / 1000000;
|
|
14
14
|
const OUTPUT_COST = 15.00 / 1000000;
|
|
@@ -21,6 +21,16 @@ function loadBrain() {
|
|
|
21
21
|
return null;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
function getPort() {
|
|
25
|
+
try {
|
|
26
|
+
if (fs.existsSync(PORT_FILE)) {
|
|
27
|
+
const port = fs.readFileSync(PORT_FILE, 'utf8').trim();
|
|
28
|
+
if (port) return port;
|
|
29
|
+
}
|
|
30
|
+
} catch {}
|
|
31
|
+
return process.env.LEMMA_PROXY_PORT || '8081';
|
|
32
|
+
}
|
|
33
|
+
|
|
24
34
|
function daemonStatus() {
|
|
25
35
|
try {
|
|
26
36
|
const isMac = process.platform === 'darwin';
|
|
@@ -34,7 +44,7 @@ function daemonStatus() {
|
|
|
34
44
|
}
|
|
35
45
|
} catch {}
|
|
36
46
|
try {
|
|
37
|
-
const port =
|
|
47
|
+
const port = getPort();
|
|
38
48
|
const http = require('http');
|
|
39
49
|
return new Promise(resolve => {
|
|
40
50
|
const req = http.get(`http://localhost:${port}/v1/models`, res => resolve('running'));
|
|
@@ -47,11 +57,12 @@ function daemonStatus() {
|
|
|
47
57
|
async function main() {
|
|
48
58
|
const brain = loadBrain();
|
|
49
59
|
const daemon = await daemonStatus();
|
|
60
|
+
const port = getPort();
|
|
50
61
|
|
|
51
62
|
process.stderr.write(`\n ${B}${C}═══ Lemma Cache Dashboard ═══${R}\n\n`);
|
|
52
63
|
|
|
53
64
|
const statusColor = daemon === 'running' ? G : Y;
|
|
54
|
-
process.stderr.write(` ${C}Proxy:${R} :${
|
|
65
|
+
process.stderr.write(` ${C}Proxy:${R} :${port} ${statusColor}${daemon === 'running' ? '● running' : '○ stopped'}${R}\n`);
|
|
55
66
|
process.stderr.write(` ${C}MCP Server:${R} lemma mcp\n`);
|
|
56
67
|
process.stderr.write(` ${C}Env File:${R} ${D}${LEMMA_CACHE}/env${R}\n\n`);
|
|
57
68
|
|
package/bin/init.js
CHANGED
|
@@ -9,9 +9,9 @@ const { execSync, spawn } = require('child_process');
|
|
|
9
9
|
const LEMMA_CACHE = path.join(os.homedir(), '.lemma-cache');
|
|
10
10
|
const BRAIN_FILE = path.join(LEMMA_CACHE, 'lemma_brain.json');
|
|
11
11
|
const ENV_FILE = path.join(LEMMA_CACHE, 'env');
|
|
12
|
-
const MCP_SERVER_PATH = path.join(__dirname, '..', 'mcp
|
|
12
|
+
const MCP_SERVER_PATH = path.join(__dirname, '..', 'dist', 'cjs', 'mcp', 'index.js');
|
|
13
13
|
const PROXY_PATH = path.join(__dirname, '..', 'cache-proxy.js');
|
|
14
|
-
const PORT = '
|
|
14
|
+
const PORT = '8081';
|
|
15
15
|
const CYAN = '\x1b[36m', GREEN = '\x1b[32m', YELLOW = '\x1b[33m', DIM = '\x1b[2m', RESET = '\x1b[0m', BOLD = '\x1b[1m';
|
|
16
16
|
|
|
17
17
|
function ensureDir(p) { try { fs.mkdirSync(p, { recursive: true }); } catch {} }
|
|
@@ -133,15 +133,20 @@ function configureCodexCliMcp() {
|
|
|
133
133
|
function configureOpenCodeMcp() {
|
|
134
134
|
const configDir = path.join(os.homedir(), '.opencode');
|
|
135
135
|
const configFile = path.join(configDir, 'mcp.json');
|
|
136
|
+
const lemmaServerConfig = {
|
|
137
|
+
command: 'node',
|
|
138
|
+
args: [MCP_SERVER_PATH],
|
|
139
|
+
type: 'local',
|
|
140
|
+
enabled: true
|
|
141
|
+
};
|
|
136
142
|
ensureDir(configDir);
|
|
137
143
|
let config = {};
|
|
138
144
|
try {
|
|
139
145
|
if (fs.existsSync(configFile)) config = JSON.parse(fs.readFileSync(configFile, 'utf8'));
|
|
140
146
|
} catch {}
|
|
141
147
|
if (!config.mcpServers) config.mcpServers = {};
|
|
142
|
-
config.mcpServers['lemma-mcp-server']
|
|
143
|
-
|
|
144
|
-
};
|
|
148
|
+
delete config.mcpServers['lemma-mcp-server'];
|
|
149
|
+
config.mcpServers.lemma = lemmaServerConfig;
|
|
145
150
|
fs.writeFileSync(configFile, JSON.stringify(config, null, 2), 'utf8');
|
|
146
151
|
|
|
147
152
|
const localOpenCode = path.join(process.cwd(), 'opencode.json');
|
|
@@ -149,29 +154,45 @@ function configureOpenCodeMcp() {
|
|
|
149
154
|
try {
|
|
150
155
|
const lc = JSON.parse(fs.readFileSync(localOpenCode, 'utf8'));
|
|
151
156
|
if (!lc.mcp) lc.mcp = {};
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
}
|
|
157
|
+
delete lc.mcp['lemma-mcp-server'];
|
|
158
|
+
lc.mcp.lemma = {
|
|
159
|
+
type: 'local',
|
|
160
|
+
command: ['node', MCP_SERVER_PATH],
|
|
161
|
+
enabled: true
|
|
162
|
+
};
|
|
163
|
+
fs.writeFileSync(localOpenCode, JSON.stringify(lc, null, 2), 'utf8');
|
|
158
164
|
} catch {}
|
|
159
165
|
}
|
|
160
166
|
return true;
|
|
161
167
|
}
|
|
162
168
|
|
|
169
|
+
function getClaudeDesktopConfigFile() {
|
|
170
|
+
if (process.platform === 'darwin') {
|
|
171
|
+
return path.join(os.homedir(), 'Library', 'Application Support', 'Claude', 'claude_desktop_config.json');
|
|
172
|
+
}
|
|
173
|
+
if (process.platform === 'win32' && process.env.APPDATA) {
|
|
174
|
+
return path.join(process.env.APPDATA, 'Claude', 'claude_desktop_config.json');
|
|
175
|
+
}
|
|
176
|
+
return path.join(os.homedir(), '.config', 'Claude', 'claude_desktop_config.json');
|
|
177
|
+
}
|
|
178
|
+
|
|
163
179
|
function configureClaudeDesktop() {
|
|
164
|
-
const
|
|
165
|
-
const
|
|
180
|
+
const configFile = getClaudeDesktopConfigFile();
|
|
181
|
+
const legacyConfigFile = path.join(os.homedir(), '.lemma-cache', 'claude_mcp.json');
|
|
166
182
|
let config = {};
|
|
167
183
|
try {
|
|
168
184
|
if (fs.existsSync(configFile)) config = JSON.parse(fs.readFileSync(configFile, 'utf8'));
|
|
169
185
|
} catch {}
|
|
186
|
+
ensureDir(path.dirname(configFile));
|
|
170
187
|
if (!config.mcpServers) config.mcpServers = {};
|
|
171
|
-
config.mcpServers['lemma-mcp-server']
|
|
188
|
+
delete config.mcpServers['lemma-mcp-server'];
|
|
189
|
+
config.mcpServers.lemma = {
|
|
172
190
|
command: 'node', args: [MCP_SERVER_PATH]
|
|
173
191
|
};
|
|
174
192
|
fs.writeFileSync(configFile, JSON.stringify(config, null, 2), 'utf8');
|
|
193
|
+
try {
|
|
194
|
+
if (fs.existsSync(legacyConfigFile)) fs.unlinkSync(legacyConfigFile);
|
|
195
|
+
} catch {}
|
|
175
196
|
return true;
|
|
176
197
|
}
|
|
177
198
|
|
package/cache-proxy.js
CHANGED
|
@@ -7,10 +7,21 @@ const fs = require('fs');
|
|
|
7
7
|
const path = require('path');
|
|
8
8
|
const os = require('os');
|
|
9
9
|
|
|
10
|
-
const
|
|
10
|
+
const CACHE_DIR = path.join(os.homedir(), '.lemma-cache');
|
|
11
|
+
const PORT_FILE = path.join(CACHE_DIR, 'proxy.port');
|
|
12
|
+
const PORT = parseInt(process.env.LEMMA_PROXY_PORT || '8081', 10);
|
|
11
13
|
const UPSTREAM = process.env.LEMMA_UPSTREAM || 'https://api.openai.com';
|
|
12
14
|
const API_KEY = process.env.LEMMA_API_KEY || process.env.OPENAI_API_KEY || '';
|
|
13
|
-
const BRAIN_FILE = path.join(
|
|
15
|
+
const BRAIN_FILE = path.join(CACHE_DIR, 'lemma_brain.json');
|
|
16
|
+
|
|
17
|
+
function persistPort() {
|
|
18
|
+
try {
|
|
19
|
+
fs.mkdirSync(CACHE_DIR, { recursive: true });
|
|
20
|
+
fs.writeFileSync(PORT_FILE, String(PORT), 'utf8');
|
|
21
|
+
} catch (e) {
|
|
22
|
+
console.error('[cache-proxy] Failed to persist proxy.port:', e.message);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
14
25
|
|
|
15
26
|
function loadBrain() {
|
|
16
27
|
try {
|
|
@@ -184,6 +195,7 @@ const server = http.createServer((req, res) => {
|
|
|
184
195
|
});
|
|
185
196
|
|
|
186
197
|
server.listen(PORT, () => {
|
|
198
|
+
persistPort();
|
|
187
199
|
console.error(`[cache-proxy] Lemma Cache Proxy on :${PORT}`);
|
|
188
200
|
console.error(`[cache-proxy] Upstream: ${UPSTREAM}`);
|
|
189
201
|
console.error(`[cache-proxy] Caching ANY provider via OpenAI-compatible endpoint`);
|
package/dist/cjs/mcp/tools.js
CHANGED
|
@@ -871,7 +871,7 @@ const toolDefinitions = [
|
|
|
871
871
|
name: "import_tree_context",
|
|
872
872
|
description: "Build a bidirectional import graph for a file. Shows what it imports, what imports it, and external dependencies. Zero LLM cost. Essential before refactors.",
|
|
873
873
|
inputSchema: {
|
|
874
|
-
type: "
|
|
874
|
+
type: "object",
|
|
875
875
|
properties: {
|
|
876
876
|
filePath: { type: "string", description: "Path relative to the project root" },
|
|
877
877
|
depth: { type: "number", description: "Traversal depth (default: 2)", default: 2 }
|