@nxuss/lemma 0.8.0 → 0.8.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 (86) hide show
  1. package/README.md +56 -1
  2. package/dist/cjs/cli/lemma-proxy.d.ts.map +1 -1
  3. package/dist/cjs/cli/lemma-proxy.js +80 -126
  4. package/dist/cjs/cli/lemma-proxy.js.map +1 -1
  5. package/dist/cjs/cloud/server.d.ts.map +1 -1
  6. package/dist/cjs/cloud/server.js +81 -3
  7. package/dist/cjs/cloud/server.js.map +1 -1
  8. package/dist/cjs/config/index.d.ts.map +1 -1
  9. package/dist/cjs/config/index.js +2 -1
  10. package/dist/cjs/config/index.js.map +1 -1
  11. package/dist/cjs/mcp/tools.js +23 -0
  12. package/dist/cjs/mcp/tools.js.map +1 -1
  13. package/dist/cjs/mcp/utils.d.ts +13 -0
  14. package/dist/cjs/mcp/utils.d.ts.map +1 -1
  15. package/dist/cjs/mcp/utils.js +61 -0
  16. package/dist/cjs/mcp/utils.js.map +1 -1
  17. package/dist/cjs/observability/IdeContextSync.js +3 -3
  18. package/dist/cjs/observability/IdeContextSync.js.map +1 -1
  19. package/dist/cjs/proxy/KeyManager.d.ts.map +1 -1
  20. package/dist/cjs/proxy/KeyManager.js +9 -1
  21. package/dist/cjs/proxy/KeyManager.js.map +1 -1
  22. package/dist/cjs/proxy/ProjectStore.d.ts +2 -0
  23. package/dist/cjs/proxy/ProjectStore.d.ts.map +1 -1
  24. package/dist/cjs/proxy/ProjectStore.js +3 -1
  25. package/dist/cjs/proxy/ProjectStore.js.map +1 -1
  26. package/dist/cjs/proxy/SseRelay.d.ts +4 -25
  27. package/dist/cjs/proxy/SseRelay.d.ts.map +1 -1
  28. package/dist/cjs/proxy/SseRelay.js +60 -63
  29. package/dist/cjs/proxy/SseRelay.js.map +1 -1
  30. package/dist/cjs/types/index.d.ts +1 -0
  31. package/dist/cjs/types/index.d.ts.map +1 -1
  32. package/dist/esm/cli/lemma-proxy.d.ts.map +1 -1
  33. package/dist/esm/cli/lemma-proxy.js +52 -98
  34. package/dist/esm/cli/lemma-proxy.js.map +1 -1
  35. package/dist/esm/cloud/server.d.ts.map +1 -1
  36. package/dist/esm/cloud/server.js +81 -3
  37. package/dist/esm/cloud/server.js.map +1 -1
  38. package/dist/esm/config/index.d.ts.map +1 -1
  39. package/dist/esm/config/index.js +2 -1
  40. package/dist/esm/config/index.js.map +1 -1
  41. package/dist/esm/mcp/tools.js +24 -1
  42. package/dist/esm/mcp/tools.js.map +1 -1
  43. package/dist/esm/mcp/utils.d.ts +13 -0
  44. package/dist/esm/mcp/utils.d.ts.map +1 -1
  45. package/dist/esm/mcp/utils.js +59 -0
  46. package/dist/esm/mcp/utils.js.map +1 -1
  47. package/dist/esm/observability/IdeContextSync.js +1 -1
  48. package/dist/esm/observability/IdeContextSync.js.map +1 -1
  49. package/dist/esm/proxy/KeyManager.d.ts.map +1 -1
  50. package/dist/esm/proxy/KeyManager.js +9 -1
  51. package/dist/esm/proxy/KeyManager.js.map +1 -1
  52. package/dist/esm/proxy/ProjectStore.d.ts +2 -0
  53. package/dist/esm/proxy/ProjectStore.d.ts.map +1 -1
  54. package/dist/esm/proxy/ProjectStore.js +2 -0
  55. package/dist/esm/proxy/ProjectStore.js.map +1 -1
  56. package/dist/esm/proxy/SseRelay.d.ts +4 -25
  57. package/dist/esm/proxy/SseRelay.d.ts.map +1 -1
  58. package/dist/esm/proxy/SseRelay.js +60 -60
  59. package/dist/esm/proxy/SseRelay.js.map +1 -1
  60. package/dist/esm/types/index.d.ts +1 -0
  61. package/dist/esm/types/index.d.ts.map +1 -1
  62. package/package.json +4 -1
  63. package/dist/cjs/protocol/iap.d.ts +0 -54
  64. package/dist/cjs/protocol/iap.d.ts.map +0 -1
  65. package/dist/cjs/protocol/iap.js +0 -108
  66. package/dist/cjs/protocol/iap.js.map +0 -1
  67. package/dist/cjs/subconscious/cache.d.ts +0 -34
  68. package/dist/cjs/subconscious/cache.d.ts.map +0 -1
  69. package/dist/cjs/subconscious/cache.js +0 -156
  70. package/dist/cjs/subconscious/cache.js.map +0 -1
  71. package/dist/cjs/subconscious/embeddings.d.ts +0 -25
  72. package/dist/cjs/subconscious/embeddings.d.ts.map +0 -1
  73. package/dist/cjs/subconscious/embeddings.js +0 -65
  74. package/dist/cjs/subconscious/embeddings.js.map +0 -1
  75. package/dist/esm/protocol/iap.d.ts +0 -54
  76. package/dist/esm/protocol/iap.d.ts.map +0 -1
  77. package/dist/esm/protocol/iap.js +0 -104
  78. package/dist/esm/protocol/iap.js.map +0 -1
  79. package/dist/esm/subconscious/cache.d.ts +0 -34
  80. package/dist/esm/subconscious/cache.d.ts.map +0 -1
  81. package/dist/esm/subconscious/cache.js +0 -152
  82. package/dist/esm/subconscious/cache.js.map +0 -1
  83. package/dist/esm/subconscious/embeddings.d.ts +0 -25
  84. package/dist/esm/subconscious/embeddings.d.ts.map +0 -1
  85. package/dist/esm/subconscious/embeddings.js +0 -58
  86. package/dist/esm/subconscious/embeddings.js.map +0 -1
@@ -38,25 +38,22 @@ import SemanticScrubber from '../security/SemanticScrubber';
38
38
  import CloudSyncClient from '../cloud/CloudSyncClient';
39
39
  import { pruneHistoryMessages, squeezePrompt } from '../utils/ContextSqueezer';
40
40
  import { AgentMultiplexer } from '../proxy/AgentMultiplexer';
41
+ import { SseRelay } from '../proxy/SseRelay';
42
+ import { KeyManager } from '../proxy/KeyManager';
43
+ import { Gatekeeper } from '../proxy/Gatekeeper';
41
44
  import { ProjectRegistry } from '../proxy/ProjectRegistry';
42
45
  import { shouldInject, buildMinimalContext, buildDeepContext, sniffProjectFromMessages } from '../proxy/ContextInjector';
43
46
  import { savingsLedger } from '../utils/SavingsLedger';
47
+ import { CACHE_DIR, PID_FILE, PORT_FILE, STATS_FILE, USAGE_FILE, LICENSE_FILE, CLIPBOARD_PID_FILE, FREE_TIER_LIMIT } from '../proxy/ProjectStore';
44
48
  const chroma = new ChromaClient({ host: 'localhost', port: 8000 });
45
49
  const dummyEmbeddingFunction = { generate: (texts) => Promise.resolve([]) };
46
50
  const complexityRouter = new ComplexityRouter();
47
51
  const semanticScrubber = new SemanticScrubber();
48
52
  const cloudSync = new CloudSyncClient();
49
53
  const agentMultiplexer = new AgentMultiplexer();
54
+ const keyManager = new KeyManager();
55
+ const gatekeeper = new Gatekeeper(keyManager);
50
56
  // ── Paths ──────────────────────────────────────────────────────────────────────
51
- const HOME = os.homedir();
52
- const CACHE_DIR = path.join(HOME, '.lemma-cache');
53
- const PID_FILE = path.join(CACHE_DIR, 'proxy.pid');
54
- const PORT_FILE = path.join(CACHE_DIR, 'proxy.port');
55
- const STATS_FILE = path.join(CACHE_DIR, 'stats.json');
56
- const USAGE_FILE = path.join(CACHE_DIR, 'usage.json');
57
- const LICENSE_FILE = path.join(CACHE_DIR, 'license.json');
58
- const CLIPBOARD_PID_FILE = path.join(CACHE_DIR, 'clipboard.pid');
59
- const FREE_LIMIT = 300;
60
57
  const VALIDATE_URL = 'https://lemma.nxus.studio/api/validate-license';
61
58
  async function checkDependency(url) {
62
59
  try {
@@ -504,21 +501,8 @@ export function startBackgroundClipboardWatcher(cliOpts) {
504
501
  }
505
502
  }
506
503
  // ── License helpers ────────────────────────────────────────────────────────────
507
- let isProCached = null;
508
- let lastLicenseCheck = 0;
509
- const LICENSE_CACHE_TTL = 10000; // 10 seconds cache
510
- async function loadLicense() {
511
- return readJson(LICENSE_FILE, { isPro: false });
512
- }
513
- async function isPro() {
514
- const now = Date.now();
515
- if (isProCached !== null && (now - lastLicenseCheck) < LICENSE_CACHE_TTL) {
516
- return isProCached;
517
- }
518
- const l = await loadLicense();
519
- isProCached = !!(l && l.isPro);
520
- lastLicenseCheck = now;
521
- return isProCached;
504
+ function isPro() {
505
+ return gatekeeper.getMode() === 'pro';
522
506
  }
523
507
  async function validateKeyRemote(key) {
524
508
  return new Promise((resolve, reject) => {
@@ -642,7 +626,7 @@ async function getEmbedding(text) {
642
626
  }
643
627
  }
644
628
  async function semanticGet(provider, prompt, projectName = 'global') {
645
- if (!await isPro())
629
+ if (!isPro())
646
630
  return null;
647
631
  const emb = await getEmbedding(prompt);
648
632
  if (!emb)
@@ -735,7 +719,7 @@ async function semanticGet(provider, prompt, projectName = 'global') {
735
719
  return null;
736
720
  }
737
721
  async function semanticSet(provider, prompt, data, projectName = 'global') {
738
- if (!await isPro())
722
+ if (!isPro())
739
723
  return;
740
724
  const emb = await getEmbedding(prompt);
741
725
  if (!emb)
@@ -838,53 +822,6 @@ function setSseHeaders(res, fromCache, similarity, tier) {
838
822
  res.setHeader('X-Lemma-Similarity', (similarity || 1.0).toFixed(3));
839
823
  res.setHeader('X-Lemma-Tier', tier);
840
824
  }
841
- function buildOaiChunk(id, model, text, stop) {
842
- return { id, object: 'chat.completion.chunk', created: Math.floor(Date.now() / 1000), model,
843
- choices: [{ index: 0, delta: stop ? {} : { content: text }, finish_reason: stop ? 'stop' : null }] };
844
- }
845
- function buildAntChunk(text, stop) {
846
- if (stop)
847
- return { type: 'message_stop' };
848
- return { type: 'content_block_delta', index: 0, delta: { type: 'text_delta', text } };
849
- }
850
- function buildGemChunk(text, stop) {
851
- return { candidates: [{ content: { parts: [{ text }] }, finishReason: stop ? 'STOP' : undefined }] };
852
- }
853
- async function simulateHitStream(res, cachedData, provider, model, tier, similarity, cacheHeader = 'HIT') {
854
- setSseHeaders(res, cacheHeader, similarity, tier);
855
- const id = `lemma-${Date.now()}`;
856
- let text = '';
857
- try {
858
- if (provider === 'openai')
859
- text = cachedData?.choices?.[0]?.message?.content || '';
860
- else if (provider === 'anthropic') {
861
- const c = cachedData?.content;
862
- text = Array.isArray(c) ? c.map((x) => x.text || '').join('') : String(c || '');
863
- }
864
- else if (provider === 'gemini') {
865
- text = cachedData?.candidates?.[0]?.content?.parts?.[0]?.text || '';
866
- }
867
- }
868
- catch { }
869
- const chunkSize = 30;
870
- for (let i = 0; i < text.length; i += chunkSize) {
871
- const chunk = text.slice(i, i + chunkSize);
872
- let evt;
873
- if (provider === 'openai')
874
- evt = buildOaiChunk(id, model, chunk, false);
875
- else if (provider === 'anthropic')
876
- evt = buildAntChunk(chunk, false);
877
- else if (provider === 'gemini')
878
- evt = buildGemChunk(chunk, false);
879
- res.write(provider === 'gemini' ? `${JSON.stringify(evt)}\n` : `data: ${JSON.stringify(evt)}\n\n`);
880
- await new Promise(r => setTimeout(r, 15));
881
- }
882
- const stopEvt = provider === 'openai' ? buildOaiChunk(id, model, '', true) : (provider === 'anthropic' ? buildAntChunk('', true) : buildGemChunk('', true));
883
- res.write(provider === 'gemini' ? `${JSON.stringify(stopEvt)}\n` : `data: ${JSON.stringify(stopEvt)}\n\n`);
884
- if (provider !== 'gemini')
885
- res.write('data: [DONE]\n\n');
886
- res.end();
887
- }
888
825
  async function relayMissStream(res, body, provider, tier) {
889
826
  setSseHeaders(res, false, 1.0, tier);
890
827
  const apiKey = provider === 'openai' ? process.env.OPENAI_API_KEY : process.env.ANTHROPIC_API_KEY;
@@ -994,8 +931,8 @@ class LemmaServer {
994
931
  }
995
932
  setupRoutes() {
996
933
  this.app.get('/health', async (req, res) => {
997
- const pro = await isPro();
998
- res.json({ status: 'ok', project: this.projectName, mode: pro ? 'pro' : 'standard', tier: pro ? 'pro' : 'free', port: this.port });
934
+ const gs = gatekeeper.getStatus();
935
+ res.json({ status: 'ok', project: this.projectName, mode: gs.mode, tier: gs.isPro ? 'pro' : 'free', port: this.port });
999
936
  });
1000
937
  // MCP Status endpoint
1001
938
  this.app.get('/api/mcp-status', (req, res) => {
@@ -1094,7 +1031,7 @@ class LemmaServer {
1094
1031
  activeAgents,
1095
1032
  totalAgents,
1096
1033
  uptime: process.uptime(),
1097
- tier: (await isPro()) ? 'pro' : 'free'
1034
+ tier: (isPro()) ? 'pro' : 'free'
1098
1035
  });
1099
1036
  });
1100
1037
  this.app.get('/api/agents', async (req, res) => {
@@ -1681,14 +1618,14 @@ class LemmaServer {
1681
1618
  }
1682
1619
  async handleCompletion(req, res, provider) {
1683
1620
  const t0 = Date.now();
1684
- const pro = await isPro();
1621
+ const pro = isPro();
1685
1622
  const tier = pro ? 'pro' : 'standard';
1686
1623
  const isStream = !!req.body.stream;
1687
1624
  let historyTokensSaved = 0;
1688
1625
  if (!pro) {
1689
1626
  const usage = await loadUsage();
1690
- if (usage.count >= FREE_LIMIT) {
1691
- return res.status(429).json({ error: { message: `Free tier limit (${FREE_LIMIT}/mo). Upgrade: https://lemma.nxus.studio/upgrade` } });
1627
+ if (usage.count >= FREE_TIER_LIMIT) {
1628
+ return res.status(429).json({ error: { message: `Free tier limit (${FREE_TIER_LIMIT}/mo). Upgrade: https://lemma.nxus.studio/upgrade` } });
1692
1629
  }
1693
1630
  }
1694
1631
  const rawPrompt = extractPrompt(req.body, provider);
@@ -1707,7 +1644,7 @@ class LemmaServer {
1707
1644
  await recordStat(this.stats, this.projectName, true, Date.now() - t0, provider, cacheTokensSaved);
1708
1645
  const unmaskedData = semanticScrubber.unmask(hit.data, tokenMap);
1709
1646
  if (isStream)
1710
- return simulateHitStream(res, unmaskedData, provider, originalModel, tier, 1.0);
1647
+ return SseRelay.simulateHit(res, unmaskedData, { provider: provider, tier, similarity: 1.0 });
1711
1648
  res.setHeader('X-Lemma-Cache', 'HIT');
1712
1649
  res.setHeader('X-Lemma-Similarity', '1.000');
1713
1650
  res.setHeader('X-Lemma-Tier', tier);
@@ -1722,7 +1659,7 @@ class LemmaServer {
1722
1659
  const unmaskedData = semanticScrubber.unmask(semHit.data, tokenMap);
1723
1660
  const cacheHeader = semHit.hiveMind ? 'HIT-HIVE-MIND' : 'HIT';
1724
1661
  if (isStream)
1725
- return simulateHitStream(res, unmaskedData, provider, originalModel, tier, semHit.similarity, cacheHeader);
1662
+ return SseRelay.simulateHit(res, unmaskedData, { provider: provider, tier, similarity: semHit.similarity, cacheHeader });
1726
1663
  res.setHeader('X-Lemma-Cache', cacheHeader);
1727
1664
  res.setHeader('X-Lemma-Similarity', semHit.similarity.toFixed(3));
1728
1665
  res.setHeader('X-Lemma-Tier', tier);
@@ -1772,7 +1709,7 @@ Adjusted Answer:`;
1772
1709
  await recordStat(this.stats, this.projectName, true, Date.now() - t0, provider, 2000);
1773
1710
  const unmaskedData = semanticScrubber.unmask(synthesizedData, tokenMap);
1774
1711
  if (isStream) {
1775
- return simulateHitStream(res, unmaskedData, provider, originalModel, tier, semHit.similarity);
1712
+ return SseRelay.simulateHit(res, unmaskedData, { provider: provider, tier, similarity: semHit.similarity });
1776
1713
  }
1777
1714
  res.setHeader('X-Lemma-Cache', 'HIT-CARS');
1778
1715
  res.setHeader('X-Lemma-Similarity', semHit.similarity.toFixed(3));
@@ -1792,7 +1729,7 @@ Adjusted Answer:`;
1792
1729
  await recordStat(this.stats, this.projectName, true, Date.now() - t0, provider, 2000);
1793
1730
  const unmaskedData = semanticScrubber.unmask(cloudHit.data, tokenMap);
1794
1731
  if (isStream)
1795
- return simulateHitStream(res, unmaskedData, provider, originalModel, tier, cloudHit.similarity || 0.95);
1732
+ return SseRelay.simulateHit(res, unmaskedData, { provider: provider, tier, similarity: cloudHit.similarity || 0.95 });
1796
1733
  res.setHeader('X-Lemma-Cache', 'HIT');
1797
1734
  res.setHeader('X-Lemma-Similarity', (cloudHit.similarity || 0.95).toFixed(3));
1798
1735
  res.setHeader('X-Lemma-Tier', tier);
@@ -1999,14 +1936,23 @@ Adjusted Answer:`;
1999
1936
  }
2000
1937
  throw e;
2001
1938
  });
2002
- server.listen(this.port, async () => {
1939
+ const BIND_HOST = process.env.LEMMA_BIND_HOST || '127.0.0.1';
1940
+ server.listen(this.port, BIND_HOST, async () => {
2003
1941
  fs.writeFileSync(PID_FILE, String(process.pid));
2004
1942
  fs.writeFileSync(PORT_FILE, String(this.port));
2005
- const pro = await isPro();
1943
+ // Security warning if binding to all interfaces without auth
1944
+ if (BIND_HOST !== '127.0.0.1' && BIND_HOST !== 'localhost') {
1945
+ const authEnabled = process.env.AUTH_ENABLED === 'true';
1946
+ if (!authEnabled) {
1947
+ console.warn(`\n\x1b[33m⚠️ [SECURITY] Lemma proxy is bound to ${BIND_HOST} (all interfaces) with AUTH_ENABLED=false.`);
1948
+ console.warn(` Set AUTH_ENABLED=true and AUTH_REQUIRE_API_KEY=true before exposing to any network.\x1b[0m\n`);
1949
+ }
1950
+ }
1951
+ const pro = isPro();
2006
1952
  console.log(`\x1b[1m\x1b[35m┌──────────────────────────────────────────────────────────┐\x1b[0m`);
2007
1953
  console.log(`\x1b[1m\x1b[35m│ 🚀 LEMMA PROXY v${VERSION} — THE UNIVERSAL AI GATEWAY │\x1b[0m`);
2008
1954
  console.log(`\x1b[1m\x1b[35m└──────────────────────────────────────────────────────────┘\x1b[0m`);
2009
- console.log(`\n📁 Project : ${this.projectName}\n🔌 Port : ${this.port}`);
1955
+ console.log(`\n📁 Project : ${this.projectName}\n🔌 Port : ${this.port} (bound to ${BIND_HOST})`);
2010
1956
  if (this.dashboardPath && fs.existsSync(this.dashboardPath)) {
2011
1957
  console.log(`📊 Dashboard UI : \x1b[36mhttp://localhost:${this.port}/dashboard/\x1b[0m`);
2012
1958
  if (this.openBrowser) {
@@ -2045,12 +1991,19 @@ Adjusted Answer:`;
2045
1991
  console.log(`\n \x1b[1m\x1b[33mlemma mcp\x1b[0m\n`);
2046
1992
  console.log('────────────────────────────────────────────────\n');
2047
1993
  // Auto-start the Local Clipboard Optimizer Watcher in the background
2048
- try {
2049
- const { startClipboardWatcher } = require('../utils/ClipboardWatcher');
2050
- startClipboardWatcher(1000);
1994
+ const clipboardDisabled = process.env.LEMMA_DISABLE_CLIPBOARD === 'true';
1995
+ if (clipboardDisabled) {
1996
+ console.log(`📋 Clipboard Watcher : \x1b[90m[DISABLED via LEMMA_DISABLE_CLIPBOARD]\x1b[0m`);
2051
1997
  }
2052
- catch (err) {
2053
- console.warn(`⚠️ Could not auto-initialize Clipboard Watcher: ${err.message}`);
1998
+ else {
1999
+ console.log(`📋 Clipboard Watcher : \x1b[33m[ACTIVE]\x1b[0m polling clipboard every 1s (disable: LEMMA_DISABLE_CLIPBOARD=true)`);
2000
+ try {
2001
+ const { startClipboardWatcher } = require('../utils/ClipboardWatcher');
2002
+ startClipboardWatcher(1000);
2003
+ }
2004
+ catch (err) {
2005
+ console.warn(`⚠️ Could not auto-initialize Clipboard Watcher: ${err.message}`);
2006
+ }
2054
2007
  }
2055
2008
  });
2056
2009
  process.on('SIGTERM', () => server.close());
@@ -2089,7 +2042,7 @@ program
2089
2042
  .version(VERSION)
2090
2043
  .addHelpText('after', `
2091
2044
  \x1b[1mPlan Comparison\x1b[0m
2092
- \x1b[32mFree\x1b[0m ${FREE_LIMIT} req/mo · Exact cache · Privacy firewall · MCP tools
2045
+ \x1b[32mFree\x1b[0m ${FREE_TIER_LIMIT} req/mo · Exact cache · Privacy firewall · MCP tools
2093
2046
  \x1b[35mPro\x1b[0m Unlimited · Semantic cache · Cloud sync · Autopilot · Heal
2094
2047
  \x1b[36mhttps://lemma.nxus.studio/upgrade\x1b[0m
2095
2048
 
@@ -2165,7 +2118,7 @@ program.command('start')
2165
2118
  const runAutopilot = opts.autopilot || opts.stack;
2166
2119
  if (runAutopilot) {
2167
2120
  try {
2168
- const pro = await isPro();
2121
+ const pro = isPro();
2169
2122
  if (!pro) {
2170
2123
  if (opts.autopilot) {
2171
2124
  console.log(`\n🛸 \x1b[35m[Autopilot]\x1b[0m Active background auto-healing watcher is a Lemma Pro feature.`);
@@ -2309,9 +2262,9 @@ program.command('stats')
2309
2262
  console.log(`Cache Hits : ${s.hits} (${((s.hits / s.total || 0) * 100).toFixed(1)}%)`);
2310
2263
  console.log(`Tokens Saved : ${s.totalTokensSaved.toLocaleString()}`);
2311
2264
  console.log(`Avg Latency : ${(s.totalLatency / (s.total || 1)).toFixed(2)}ms`);
2312
- console.log(`Tier : ${(await isPro()) ? 'PRO' : 'FREE'}`);
2313
- if (!await isPro())
2314
- console.log(`Free Usage : ${usage.count}/${FREE_LIMIT} requests`);
2265
+ console.log(`Tier : ${(isPro()) ? 'PRO' : 'FREE'}`);
2266
+ if (!isPro())
2267
+ console.log(`Free Usage : ${usage.count}/${FREE_TIER_LIMIT} requests`);
2315
2268
  console.log(`──────────────────────────────────\n`);
2316
2269
  });
2317
2270
  program.command('activate <key>')
@@ -2327,6 +2280,7 @@ program.command('activate <key>')
2327
2280
  const res = await validateKeyRemote(key.trim());
2328
2281
  if (res.valid) {
2329
2282
  await writeJson(LICENSE_FILE, { key, isPro: true, activatedAt: new Date().toISOString(), validatedRemotely: true });
2283
+ gatekeeper.reload();
2330
2284
  console.log('✅ License activated! Enjoy Pro features (Server-verified).');
2331
2285
  }
2332
2286
  else {
@@ -2567,7 +2521,7 @@ program.command('heal')
2567
2521
  .option('--apply', 'Apply the auto-generated code fix automatically', false)
2568
2522
  .action(async (opts) => {
2569
2523
  try {
2570
- const pro = await isPro();
2524
+ const pro = isPro();
2571
2525
  if (!pro) {
2572
2526
  console.log(`\n🩺 \x1b[35m[Heal]\x1b[0m Guided code diagnostics and auto-healing is a Lemma Pro feature.`);
2573
2527
  console.log(`💡 Upgrade to Pro in your Dashboard or visit: \x1b[4mhttps://lemma.nxus.studio/upgrade\x1b[0m\n`);
@@ -2596,7 +2550,7 @@ program.command('autopilot')
2596
2550
  .option('--dir <directory>', 'Directory to monitor for changes', 'src')
2597
2551
  .action(async (opts) => {
2598
2552
  try {
2599
- const pro = await isPro();
2553
+ const pro = isPro();
2600
2554
  if (!pro) {
2601
2555
  console.log(`\n🛸 \x1b[35m[Autopilot]\x1b[0m Active background auto-healing watcher is a Lemma Pro feature.`);
2602
2556
  console.log(`💡 Upgrade to Pro in your Dashboard or visit: \x1b[4mhttps://lemma.nxus.studio/upgrade\x1b[0m\n`);