@nxuss/lemma 0.5.0 → 0.5.2

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 (40) hide show
  1. package/README.md +61 -8
  2. package/dashboard/dist/assets/{index-B4TA31pA.js → index-CIlkFwDs.js} +98 -98
  3. package/dashboard/dist/assets/index-CIlkFwDs.js.map +1 -0
  4. package/dashboard/dist/index.html +1 -1
  5. package/dist/cjs/cli/lemma-proxy.d.ts +2 -0
  6. package/dist/cjs/cli/lemma-proxy.d.ts.map +1 -1
  7. package/dist/cjs/cli/lemma-proxy.js +243 -37
  8. package/dist/cjs/cli/lemma-proxy.js.map +1 -1
  9. package/dist/cjs/mcp/index.js +81 -0
  10. package/dist/cjs/mcp/index.js.map +1 -1
  11. package/dist/cjs/utils/ClipboardWatcher.d.ts.map +1 -1
  12. package/dist/cjs/utils/ClipboardWatcher.js +3 -0
  13. package/dist/cjs/utils/ClipboardWatcher.js.map +1 -1
  14. package/dist/cjs/utils/SavingsLedger.d.ts +52 -0
  15. package/dist/cjs/utils/SavingsLedger.d.ts.map +1 -0
  16. package/dist/cjs/utils/SavingsLedger.js +101 -0
  17. package/dist/cjs/utils/SavingsLedger.js.map +1 -0
  18. package/dist/cjs/utils/reportSavings.d.ts +24 -0
  19. package/dist/cjs/utils/reportSavings.d.ts.map +1 -0
  20. package/dist/cjs/utils/reportSavings.js +53 -0
  21. package/dist/cjs/utils/reportSavings.js.map +1 -0
  22. package/dist/esm/cli/lemma-proxy.d.ts +2 -0
  23. package/dist/esm/cli/lemma-proxy.d.ts.map +1 -1
  24. package/dist/esm/cli/lemma-proxy.js +241 -37
  25. package/dist/esm/cli/lemma-proxy.js.map +1 -1
  26. package/dist/esm/mcp/index.js +81 -0
  27. package/dist/esm/mcp/index.js.map +1 -1
  28. package/dist/esm/utils/ClipboardWatcher.d.ts.map +1 -1
  29. package/dist/esm/utils/ClipboardWatcher.js +3 -0
  30. package/dist/esm/utils/ClipboardWatcher.js.map +1 -1
  31. package/dist/esm/utils/SavingsLedger.d.ts +52 -0
  32. package/dist/esm/utils/SavingsLedger.d.ts.map +1 -0
  33. package/dist/esm/utils/SavingsLedger.js +98 -0
  34. package/dist/esm/utils/SavingsLedger.js.map +1 -0
  35. package/dist/esm/utils/reportSavings.d.ts +24 -0
  36. package/dist/esm/utils/reportSavings.d.ts.map +1 -0
  37. package/dist/esm/utils/reportSavings.js +47 -0
  38. package/dist/esm/utils/reportSavings.js.map +1 -0
  39. package/package.json +2 -2
  40. package/dashboard/dist/assets/index-B4TA31pA.js.map +0 -1
@@ -5,7 +5,7 @@
5
5
  <link rel="icon" type="image/svg+xml" href="/vite.svg" />
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
7
  <title>lemma Dashboard - Agent Orchestration Hub</title>
8
- <script type="module" crossorigin src="/dashboard/assets/index-B4TA31pA.js"></script>
8
+ <script type="module" crossorigin src="/dashboard/assets/index-CIlkFwDs.js"></script>
9
9
  <link rel="stylesheet" crossorigin href="/dashboard/assets/index-DNqq3gA9.css">
10
10
  </head>
11
11
  <body>
@@ -1,4 +1,6 @@
1
1
  #!/usr/bin/env node
2
+ export declare function autoConfigureAll(projectName?: string): void;
3
+ export declare function startBackgroundClipboardWatcher(): void;
2
4
  export declare function performAutoHeal(apply: boolean): Promise<{
3
5
  success: boolean;
4
6
  message: string;
@@ -1 +1 @@
1
- {"version":3,"file":"lemma-proxy.d.ts","sourceRoot":"","sources":["../../../src/cli/lemma-proxy.ts"],"names":[],"mappings":";AAw3CA,wBAAsB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CA6KhL"}
1
+ {"version":3,"file":"lemma-proxy.d.ts","sourceRoot":"","sources":["../../../src/cli/lemma-proxy.ts"],"names":[],"mappings":";AAoNA,wBAAgB,gBAAgB,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CA0I3D;AAED,wBAAgB,+BAA+B,IAAI,IAAI,CAyCtD;AAmsCD,wBAAsB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CA6KhL"}
@@ -4,6 +4,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  return (mod && mod.__esModule) ? mod : { "default": mod };
5
5
  };
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.autoConfigureAll = autoConfigureAll;
8
+ exports.startBackgroundClipboardWatcher = startBackgroundClipboardWatcher;
7
9
  exports.performAutoHeal = performAutoHeal;
8
10
  const commander_1 = require("commander");
9
11
  const express_1 = __importDefault(require("express"));
@@ -30,7 +32,7 @@ function getVersion() {
30
32
  catch { }
31
33
  }
32
34
  }
33
- return '0.4.6';
35
+ return '0.5.2';
34
36
  }
35
37
  const VERSION = getVersion();
36
38
  const ComplexityRouter_1 = __importDefault(require("../proxy/ComplexityRouter"));
@@ -38,6 +40,7 @@ const SemanticScrubber_1 = __importDefault(require("../security/SemanticScrubber
38
40
  const CloudSyncClient_1 = __importDefault(require("../cloud/CloudSyncClient"));
39
41
  const ContextSqueezer_1 = require("../utils/ContextSqueezer");
40
42
  const AgentMultiplexer_1 = require("../proxy/AgentMultiplexer");
43
+ const SavingsLedger_1 = require("../utils/SavingsLedger");
41
44
  const chroma = new chromadb_1.ChromaClient({ host: 'localhost', port: 8000 });
42
45
  const dummyEmbeddingFunction = { generate: (texts) => Promise.resolve([]) };
43
46
  const complexityRouter = new ComplexityRouter_1.default();
@@ -59,6 +62,13 @@ function logEvent(event) {
59
62
  EVENT_LOG.push(ev);
60
63
  if (EVENT_LOG.length > MAX_EVENTS)
61
64
  EVENT_LOG.shift();
65
+ // Print a terminal savings summary every 10 events
66
+ if (EVENT_LOG.length > 0 && EVENT_LOG.length % 10 === 0) {
67
+ const snap = SavingsLedger_1.savingsLedger.getSnapshot();
68
+ if (snap.total.tokensSaved > 0) {
69
+ console.log('\n' + SavingsLedger_1.savingsLedger.getTerminalSummary() + '\n');
70
+ }
71
+ }
62
72
  }
63
73
  const FREE_LIMIT = 500;
64
74
  const WARN_PCT = 0.8;
@@ -199,6 +209,182 @@ function ensureGitIgnore() {
199
209
  catch { }
200
210
  return added;
201
211
  }
212
+ const CLIPBOARD_PID_FILE = path_1.default.join(CACHE_DIR, 'clipboard.pid');
213
+ function autoConfigureAll(projectName) {
214
+ const project = projectName || detectProject();
215
+ const HOME = process.env.HOME || process.env.USERPROFILE || '~';
216
+ // 1. Claude Desktop Config
217
+ try {
218
+ const isWin = process.platform === 'win32';
219
+ const claudePath = isWin
220
+ ? path_1.default.join(process.env.APPDATA || '', 'Claude/claude_desktop_config.json')
221
+ : path_1.default.join(HOME, 'Library/Application Support/Claude/claude_desktop_config.json');
222
+ if (fs_1.default.existsSync(path_1.default.dirname(claudePath))) {
223
+ let config = { mcpServers: {} };
224
+ if (fs_1.default.existsSync(claudePath)) {
225
+ try {
226
+ config = JSON.parse(fs_1.default.readFileSync(claudePath, 'utf8'));
227
+ }
228
+ catch { }
229
+ }
230
+ if (!config.mcpServers)
231
+ config.mcpServers = {};
232
+ config.mcpServers.lemma = {
233
+ command: 'npx',
234
+ args: ['-y', '@nxuss/lemma', 'mcp'],
235
+ env: { LEMMA_PROJECT: project }
236
+ };
237
+ fs_1.default.writeFileSync(claudePath, JSON.stringify(config, null, 2));
238
+ console.log(`✅ [Claude Desktop] Configured automatically! (Restart Claude to activate)`);
239
+ }
240
+ }
241
+ catch (e) {
242
+ console.log(`⚠️ Could not auto-configure Claude Desktop: ${e.message}`);
243
+ }
244
+ // 2. Shell Profiles Environment Override
245
+ try {
246
+ const profiles = [
247
+ path_1.default.join(HOME, '.zshrc'),
248
+ path_1.default.join(HOME, '.bashrc'),
249
+ path_1.default.join(HOME, '.bash_profile'),
250
+ path_1.default.join(HOME, '.profile')
251
+ ];
252
+ const lines = [
253
+ '',
254
+ '# Lemma AI Gateway Overrides',
255
+ 'export OPENAI_BASE_URL="http://localhost:8081/v1"',
256
+ 'export ANTHROPIC_BASE_URL="http://localhost:8081"',
257
+ 'export LEMMA_PROJECT="' + project + '"',
258
+ ''
259
+ ].join('\n');
260
+ for (const profile of profiles) {
261
+ if (fs_1.default.existsSync(profile)) {
262
+ try {
263
+ const content = fs_1.default.readFileSync(profile, 'utf8');
264
+ if (!content.includes('OPENAI_BASE_URL') && !content.includes('LEMMA_PROJECT')) {
265
+ fs_1.default.appendFileSync(profile, lines);
266
+ console.log(`✅ [Shell Profile] Configured ${path_1.default.basename(profile)} with local redirect variables!`);
267
+ }
268
+ }
269
+ catch { }
270
+ }
271
+ }
272
+ }
273
+ catch (e) {
274
+ console.log(`⚠️ Could not auto-configure shell profiles: ${e.message}`);
275
+ }
276
+ // 3. Cursor & Windsurf settings.json updates
277
+ try {
278
+ const isWin = process.platform === 'win32';
279
+ const isMac = process.platform === 'darwin';
280
+ const candidates = [];
281
+ if (isMac) {
282
+ candidates.push({
283
+ name: 'Cursor',
284
+ path: path_1.default.join(HOME, 'Library/Application Support/Cursor/User/settings.json')
285
+ });
286
+ candidates.push({
287
+ name: 'Windsurf',
288
+ path: path_1.default.join(HOME, 'Library/Application Support/Windsurf/User/settings.json')
289
+ });
290
+ }
291
+ else if (isWin) {
292
+ const appData = process.env.APPDATA || '';
293
+ candidates.push({
294
+ name: 'Cursor',
295
+ path: path_1.default.join(appData, 'Cursor/User/settings.json')
296
+ });
297
+ candidates.push({
298
+ name: 'Windsurf',
299
+ path: path_1.default.join(appData, 'Windsurf/User/settings.json')
300
+ });
301
+ }
302
+ else {
303
+ candidates.push({
304
+ name: 'Cursor',
305
+ path: path_1.default.join(HOME, '.config/Cursor/User/settings.json')
306
+ });
307
+ candidates.push({
308
+ name: 'Windsurf',
309
+ path: path_1.default.join(HOME, '.config/Windsurf/User/settings.json')
310
+ });
311
+ }
312
+ for (const cand of candidates) {
313
+ const dir = path_1.default.dirname(cand.path);
314
+ if (fs_1.default.existsSync(dir)) {
315
+ let settings = {};
316
+ if (fs_1.default.existsSync(cand.path)) {
317
+ try {
318
+ settings = JSON.parse(fs_1.default.readFileSync(cand.path, 'utf8'));
319
+ }
320
+ catch { }
321
+ }
322
+ let updated = false;
323
+ // Settings configuration to route custom openai/anthropic models through the proxy
324
+ const updates = {
325
+ "openai.baseURL": "http://localhost:8081/v1",
326
+ "openai.apiKey": "dummy-key-for-lemma",
327
+ "anthropic.baseURL": "http://localhost:8081",
328
+ "anthropic.apiKey": "dummy-key-for-lemma"
329
+ };
330
+ for (const [key, value] of Object.entries(updates)) {
331
+ if (settings[key] !== value) {
332
+ settings[key] = value;
333
+ updated = true;
334
+ }
335
+ }
336
+ if (updated) {
337
+ fs_1.default.writeFileSync(cand.path, JSON.stringify(settings, null, 2));
338
+ console.log(`✅ [${cand.name}] Configured editor settings to route via local gateway!`);
339
+ }
340
+ }
341
+ }
342
+ }
343
+ catch (e) {
344
+ console.log(`⚠️ Could not auto-configure editor settings: ${e.message}`);
345
+ }
346
+ }
347
+ function startBackgroundClipboardWatcher() {
348
+ try {
349
+ if (fs_1.default.existsSync(CLIPBOARD_PID_FILE)) {
350
+ const oldPid = fs_1.default.readFileSync(CLIPBOARD_PID_FILE, 'utf8');
351
+ try {
352
+ process.kill(parseInt(oldPid, 10), 0); // Check if process is still alive
353
+ console.log(`✅ [Clipboard] Watcher is already running in background (PID: ${oldPid})`);
354
+ return;
355
+ }
356
+ catch {
357
+ // Process is dead, clean up pid file
358
+ try {
359
+ fs_1.default.unlinkSync(CLIPBOARD_PID_FILE);
360
+ }
361
+ catch { }
362
+ }
363
+ }
364
+ console.log(`🔄 Starting Clipboard Watcher in background...`);
365
+ const { spawn } = require('child_process');
366
+ // Resolve path of lemma command or script
367
+ const scriptPath = fs_1.default.existsSync(path_1.default.join(__dirname, 'dist', 'cjs', 'cli', 'lemma-proxy.js'))
368
+ ? path_1.default.join(__dirname, 'dist', 'cjs', 'cli', 'lemma-proxy.js')
369
+ : (fs_1.default.existsSync(path_1.default.join(__dirname, 'lemma-proxy.ts')) ? path_1.default.join(__dirname, 'lemma-proxy.ts') : __filename);
370
+ const isTs = scriptPath.endsWith('.ts');
371
+ const cmd = isTs ? 'npx' : 'node';
372
+ const args = isTs ? ['tsx', scriptPath, 'clipboard'] : [scriptPath, 'clipboard'];
373
+ const cp = spawn(cmd, args, {
374
+ stdio: 'ignore',
375
+ detached: true,
376
+ env: { ...process.env }
377
+ });
378
+ cp.unref();
379
+ if (cp.pid) {
380
+ fs_1.default.writeFileSync(CLIPBOARD_PID_FILE, String(cp.pid));
381
+ console.log(`✅ [Clipboard] Watcher has been started (PID: ${cp.pid})`);
382
+ }
383
+ }
384
+ catch (err) {
385
+ console.error(`❌ Failed to automatically start Clipboard Watcher in background: ${err.message}`);
386
+ }
387
+ }
202
388
  // ── License helpers ────────────────────────────────────────────────────────────
203
389
  async function loadLicense() {
204
390
  return readJson(LICENSE_FILE, { isPro: false });
@@ -703,6 +889,7 @@ class LemmaServer {
703
889
  const count = CACHE.size;
704
890
  CACHE.clear();
705
891
  EVENT_LOG.length = 0; // Clear live event log
892
+ SavingsLedger_1.savingsLedger.reset(); // Reset savings counters
706
893
  // Reset and persist statistics for the current project
707
894
  if (this.stats[this.projectName]) {
708
895
  this.stats[this.projectName] = {
@@ -717,6 +904,25 @@ class LemmaServer {
717
904
  }
718
905
  res.json({ success: true, clearedEntries: count });
719
906
  });
907
+ // Savings breakdown by source for the dashboard
908
+ this.app.get('/api/savings-breakdown', (req, res) => {
909
+ res.json(SavingsLedger_1.savingsLedger.getSnapshot());
910
+ });
911
+ // Cross-process savings reporter — MCP and other processes POST here
912
+ this.app.post('/api/savings-record', (req, res) => {
913
+ const { source, charsBefore, charsAfter, tokens } = req.body || {};
914
+ const validSources = ['clipboard', 'contextSqueeze', 'historyPrune', 'complexityRouting', 'cache'];
915
+ if (!source || !validSources.includes(source)) {
916
+ return res.status(400).json({ error: 'Invalid source' });
917
+ }
918
+ if (typeof tokens === 'number' && tokens > 0) {
919
+ SavingsLedger_1.savingsLedger.recordTokens(source, tokens);
920
+ }
921
+ else if (typeof charsBefore === 'number' && typeof charsAfter === 'number') {
922
+ SavingsLedger_1.savingsLedger.record(source, charsBefore, charsAfter);
923
+ }
924
+ res.json({ ok: true, snapshot: SavingsLedger_1.savingsLedger.getSnapshot().total });
925
+ });
720
926
  this.app.get('/dashboard/*', (req, res) => res.sendFile(path_1.default.join(this.dashboardPath, 'index.html')));
721
927
  }
722
928
  }
@@ -744,6 +950,13 @@ class LemmaServer {
744
950
  const model = routingDecision.model;
745
951
  if (req.body.model)
746
952
  req.body.model = model;
953
+ // Record complexity routing savings when model is downgraded
954
+ if (routingDecision.complexity === 'low' && model !== originalModel) {
955
+ // Estimated token savings: cheap model costs ~5x less, so avg prompt of ~800 tokens saves ~640 tokens
956
+ const estimatedPromptTokens = Math.floor(prompt.length / 4);
957
+ const routingSavings = Math.floor(estimatedPromptTokens * 0.8); // conservative 80% cost reduction
958
+ SavingsLedger_1.savingsLedger.recordTokens('complexityRouting', routingSavings);
959
+ }
747
960
  // Apply the Agent Multiplexer to local-verify the prompt in parallel
748
961
  const enrichedPrompt = await agentMultiplexer.multiplexPrompt(prompt, model);
749
962
  // Resolve conversation session key and retrieve/create the fileHistory map
@@ -766,6 +979,7 @@ class LemmaServer {
766
979
  const squeezedPrompt = squeezeResult.squeezed;
767
980
  const compressionSavings = squeezeResult.originalSize - squeezeResult.squeezedSize;
768
981
  if (compressionSavings > 0) {
982
+ SavingsLedger_1.savingsLedger.record('contextSqueeze', squeezeResult.originalSize, squeezeResult.squeezedSize);
769
983
  console.log(`⚡ [Squeezer] Compressed prompt from ${squeezeResult.originalSize} to ${squeezeResult.squeezedSize} chars (Saved ${(squeezeResult.compressionRatio * 100).toFixed(1)}% context tokens!)`);
770
984
  }
771
985
  if (provider === 'openai' || provider === 'anthropic') {
@@ -775,6 +989,9 @@ class LemmaServer {
775
989
  const pruneResult = (0, ContextSqueezer_1.pruneHistoryMessages)(req.body.messages);
776
990
  req.body.messages = pruneResult.messages;
777
991
  historyTokensSaved = pruneResult.tokensSavedEstimate + Math.floor(compressionSavings / 4);
992
+ if (pruneResult.tokensSavedEstimate > 0) {
993
+ SavingsLedger_1.savingsLedger.recordTokens('historyPrune', pruneResult.tokensSavedEstimate);
994
+ }
778
995
  }
779
996
  }
780
997
  else if (provider === 'gemini') {
@@ -787,7 +1004,9 @@ class LemmaServer {
787
1004
  }
788
1005
  const hit = cacheGet(provider, prompt);
789
1006
  if (hit) {
790
- await recordStat(this.stats, this.projectName, true, Date.now() - t0, provider, 2000 + historyTokensSaved);
1007
+ const cacheTokensSaved = 2000 + historyTokensSaved;
1008
+ SavingsLedger_1.savingsLedger.recordTokens('cache', cacheTokensSaved);
1009
+ await recordStat(this.stats, this.projectName, true, Date.now() - t0, provider, cacheTokensSaved);
791
1010
  const unmaskedData = semanticScrubber.unmask(hit.data, tokenMap);
792
1011
  if (isStream)
793
1012
  return simulateHitStream(res, unmaskedData, provider, model, tier, 1.0);
@@ -1052,10 +1271,17 @@ commander_1.program.command('start')
1052
1271
  if (resp.data && resp.data.status === 'ok') {
1053
1272
  console.log(`\n⚠️ Lemma Proxy is already running on port ${port} (Project: ${resp.data.project})`);
1054
1273
  console.log(`💡 Use 'lemma status' for details or 'lemma stop' to restart.\n`);
1274
+ // Keep configurations up to date even if server was already started
1275
+ const runningProject = resp.data.project || detectProject();
1276
+ autoConfigureAll(runningProject);
1277
+ startBackgroundClipboardWatcher();
1055
1278
  process.exit(0);
1056
1279
  }
1057
1280
  }
1058
1281
  catch { }
1282
+ const startProject = opts.project || detectProject();
1283
+ autoConfigureAll(startProject);
1284
+ startBackgroundClipboardWatcher();
1059
1285
  // Automatically enable autopilot if stack is enabled and user is Pro
1060
1286
  const runAutopilot = opts.autopilot || opts.stack;
1061
1287
  if (runAutopilot) {
@@ -1154,6 +1380,19 @@ commander_1.program.command('stop')
1154
1380
  }
1155
1381
  if (fs_1.default.existsSync(PID_FILE))
1156
1382
  fs_1.default.unlinkSync(PID_FILE);
1383
+ // Stop background Clipboard Watcher if active
1384
+ try {
1385
+ if (fs_1.default.existsSync(CLIPBOARD_PID_FILE)) {
1386
+ const cbPid = fs_1.default.readFileSync(CLIPBOARD_PID_FILE, 'utf8');
1387
+ try {
1388
+ process.kill(parseInt(cbPid, 10), 'SIGTERM');
1389
+ console.log(`✅ Stopped background Clipboard Watcher (PID: ${cbPid})`);
1390
+ }
1391
+ catch { }
1392
+ fs_1.default.unlinkSync(CLIPBOARD_PID_FILE);
1393
+ }
1394
+ }
1395
+ catch { }
1157
1396
  });
1158
1397
  commander_1.program.command('status')
1159
1398
  .description('Check proxy status')
@@ -1247,41 +1486,8 @@ commander_1.program.command('init')
1247
1486
  fs_1.default.writeFileSync(envFile, lemmaConfig);
1248
1487
  console.log('✅ Created .env with Lemma configuration');
1249
1488
  }
1250
- console.log('\n🧠 \x1b[35mAuto-Setup MCP for AI IDEs?\x1b[0m');
1251
- console.log(' Lemma can automatically configure Claude Desktop and open settings for Cursor/Windsurf.');
1252
- const { exec } = require('child_process');
1253
- const isWin = process.platform === 'win32';
1254
- const claudePath = isWin
1255
- ? path_1.default.join(process.env.APPDATA || '', 'Claude/claude_desktop_config.json')
1256
- : path_1.default.join(process.env.HOME || '~', 'Library/Application Support/Claude/claude_desktop_config.json');
1257
- if (fs_1.default.existsSync(path_1.default.dirname(claudePath))) {
1258
- try {
1259
- let config = { mcpServers: {} };
1260
- if (fs_1.default.existsSync(claudePath)) {
1261
- config = JSON.parse(fs_1.default.readFileSync(claudePath, 'utf8'));
1262
- }
1263
- if (!config.mcpServers)
1264
- config.mcpServers = {};
1265
- config.mcpServers.lemma = {
1266
- command: 'npx',
1267
- args: ['-y', '@nxuss/lemma', 'mcp'],
1268
- env: { LEMMA_PROJECT: project }
1269
- };
1270
- fs_1.default.writeFileSync(claudePath, JSON.stringify(config, null, 2));
1271
- console.log(`✅ \x1b[32mClaude Desktop configured automatically!\x1b[0m (Restart Claude to activate)`);
1272
- }
1273
- catch (e) {
1274
- console.log('⚠️ Could not auto-configure Claude Desktop. No worries, you can do it manually.');
1275
- }
1276
- }
1277
- console.log('🚀 Opening IDE configuration pages...');
1278
- const urls = [
1279
- 'https://docs.anthropic.com/en/docs/agents-and-tools/mcp#using-mcp-in-claude-desktop',
1280
- 'https://cursor.com',
1281
- 'https://codeium.com/windsurf'
1282
- ];
1283
- const opener = process.platform === 'darwin' ? 'open' : (process.platform === 'win32' ? 'start' : 'xdg-open');
1284
- urls.forEach(url => exec(`${opener} ${url}`));
1489
+ console.log('\n🧠 \x1b[35mAuto-Setup MCP and redirection overrides for AI IDEs...\x1b[0m');
1490
+ autoConfigureAll(project);
1285
1491
  console.log('\n✨ Project initialized for the Agentic Era!');
1286
1492
  console.log('🚀 Run "lemma start" to begin.\n');
1287
1493
  });