@nxuss/lemma 0.4.3 → 0.4.5
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/lemma-proxy.cjs +131 -12
- package/package.json +2 -1
package/lemma-proxy.cjs
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
'use strict';
|
|
3
3
|
/**
|
|
4
|
-
* Lemma Proxy
|
|
4
|
+
* Lemma Proxy — Universal AI Cache CLI
|
|
5
5
|
* Commands: start, stop, stats, status, activate <key>
|
|
6
6
|
*/
|
|
7
|
+
const pkg = require('./package.json');
|
|
8
|
+
const VERSION = pkg.version;
|
|
7
9
|
|
|
8
10
|
const { program } = require('commander');
|
|
9
11
|
const express = require('express');
|
|
@@ -76,6 +78,46 @@ function ensureProjectDir(name) {
|
|
|
76
78
|
return dir;
|
|
77
79
|
}
|
|
78
80
|
|
|
81
|
+
function getPidByPort(port) {
|
|
82
|
+
const { execSync } = require('child_process');
|
|
83
|
+
try {
|
|
84
|
+
if (process.platform === 'win32') {
|
|
85
|
+
const out = execSync(`netstat -ano | findstr :${port}`).toString();
|
|
86
|
+
const lines = out.split('\n').filter(l => l.includes('LISTENING'));
|
|
87
|
+
if (lines.length > 0) return lines[0].trim().split(/\s+/).pop();
|
|
88
|
+
} else {
|
|
89
|
+
const out = execSync(`lsof -t -i :${port}`).toString().trim();
|
|
90
|
+
return out.split('\n')[0]; // Take first if multiple
|
|
91
|
+
}
|
|
92
|
+
} catch { return null; }
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
async function checkDependency(url) {
|
|
97
|
+
try {
|
|
98
|
+
const res = await axios.get(url, { timeout: 1000, validateStatus: () => true });
|
|
99
|
+
return res.status >= 200 && res.status < 500;
|
|
100
|
+
} catch { return false; }
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function ensureGitIgnore() {
|
|
104
|
+
const gi = path.join(process.cwd(), '.gitignore');
|
|
105
|
+
const line = '.lemma/';
|
|
106
|
+
try {
|
|
107
|
+
if (fs.existsSync(gi)) {
|
|
108
|
+
const content = fs.readFileSync(gi, 'utf8');
|
|
109
|
+
if (!content.includes(line)) {
|
|
110
|
+
fs.appendFileSync(gi, `\n# Lemma Context Logs\n${line}\n`);
|
|
111
|
+
return true;
|
|
112
|
+
}
|
|
113
|
+
} else {
|
|
114
|
+
fs.writeFileSync(gi, `# Lemma Context Logs\n${line}\n`);
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
} catch {}
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
|
|
79
121
|
// ── License helpers ────────────────────────────────────────────────────────────
|
|
80
122
|
function loadLicense() {
|
|
81
123
|
return readJson(LICENSE_FILE, { isPro: false });
|
|
@@ -87,7 +129,7 @@ async function validateKeyRemote(key) {
|
|
|
87
129
|
const body = JSON.stringify({ key });
|
|
88
130
|
const u = new URL(VALIDATE_URL);
|
|
89
131
|
const req = https.request({ hostname: u.hostname, port: 443, path: u.pathname, method: 'POST',
|
|
90
|
-
headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(body), 'User-Agent':
|
|
132
|
+
headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(body), 'User-Agent': `lemma-proxy/${VERSION}` }
|
|
91
133
|
}, res => {
|
|
92
134
|
let d = '';
|
|
93
135
|
res.on('data', c => d += c);
|
|
@@ -464,17 +506,53 @@ class LemmaServer {
|
|
|
464
506
|
|
|
465
507
|
start() {
|
|
466
508
|
const server = http.createServer(this.app);
|
|
467
|
-
server.
|
|
509
|
+
server.on('error', (e) => {
|
|
510
|
+
if (e.code === 'EADDRINUSE') {
|
|
511
|
+
console.error(`\n❌ Error: Port ${this.port} is already in use.`);
|
|
512
|
+
console.error(`💡 Try stopping the existing process with 'lemma stop' or use a different port with '--port <number>'.\n`);
|
|
513
|
+
process.exit(1);
|
|
514
|
+
}
|
|
515
|
+
throw e;
|
|
516
|
+
});
|
|
517
|
+
server.listen(this.port, async () => {
|
|
468
518
|
fs.writeFileSync(PID_FILE, String(process.pid));
|
|
469
519
|
fs.writeFileSync(PORT_FILE, String(this.port));
|
|
470
|
-
|
|
520
|
+
|
|
521
|
+
const pro = isPro();
|
|
522
|
+
console.log(`\n🚀 Lemma Proxy v${VERSION} — ${pro ? 'PRO' : 'STANDARD'}`);
|
|
523
|
+
console.log(`📁 Project : ${this.projectName}\n🔌 Port : ${this.port}`);
|
|
524
|
+
|
|
525
|
+
console.log('\n🧠 Intelligence Report');
|
|
526
|
+
console.log('────────────────────────────────────────────────');
|
|
527
|
+
console.log(`🔒 Privacy Firewall : \x1b[32m[ACTIVE]\x1b[0m`);
|
|
528
|
+
console.log(`🔀 Complexity Router : \x1b[32m[ACTIVE]\x1b[0m`);
|
|
529
|
+
console.log(`💾 Exact Cache : \x1b[32m[ACTIVE]\x1b[0m`);
|
|
530
|
+
|
|
531
|
+
const ollamaOk = await checkDependency('http://localhost:11434/api/tags');
|
|
532
|
+
const chromaOk = await checkDependency('http://localhost:8000/'); // Basic check for Chroma
|
|
533
|
+
|
|
534
|
+
if (pro) {
|
|
535
|
+
console.log(`🎯 Semantic Cache : ${ollamaOk && chromaOk ? '\x1b[32m[ACTIVE]\x1b[0m' : '\x1b[33m[OFFLINE - Check Ollama/Chroma]\x1b[0m'}`);
|
|
536
|
+
console.log(`🌐 Hive Mind (Cloud) : \x1b[32m[ACTIVE]\x1b[0m`);
|
|
537
|
+
} else {
|
|
538
|
+
console.log(`🎯 Semantic Cache : \x1b[90m[PRO ONLY]\x1b[0m -> https://lemma.nxus.studio/upgrade`);
|
|
539
|
+
console.log(`🌐 Hive Mind (Cloud) : \x1b[90m[PRO ONLY]\x1b[0m -> https://lemma.nxus.studio/upgrade`);
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
const hasStackDir = fs.existsSync(path.join(process.cwd(), '.lemma'));
|
|
543
|
+
console.log(`📡 Telepathic Sync : ${hasStackDir ? '\x1b[32m[READY]\x1b[0m' : '\x1b[90m[DISABLED - Run "lemma init"]\x1b[0m'}`);
|
|
544
|
+
console.log('────────────────────────────────────────────────\n');
|
|
545
|
+
|
|
546
|
+
if (!pro) {
|
|
547
|
+
console.log('\x1b[36m💡 Unlock Semantic Search & Team Caching at https://lemma.nxus.studio/upgrade\x1b[0m\n');
|
|
548
|
+
}
|
|
471
549
|
});
|
|
472
550
|
process.on('SIGTERM', () => server.close());
|
|
473
551
|
}
|
|
474
552
|
}
|
|
475
553
|
|
|
476
554
|
// ── CLI ────────────────────────────────────────────────────────────────────────
|
|
477
|
-
program.name('lemma').description('Lemma Proxy CLI — Intelligent AI Gateway').version(
|
|
555
|
+
program.name('lemma').description('Lemma Proxy CLI — Intelligent AI Gateway').version(VERSION);
|
|
478
556
|
|
|
479
557
|
program.command('start')
|
|
480
558
|
.description('Start the proxy server')
|
|
@@ -484,6 +562,16 @@ program.command('start')
|
|
|
484
562
|
.action(async (opts) => {
|
|
485
563
|
const port = parseInt(opts.port, 10);
|
|
486
564
|
|
|
565
|
+
// Check if already running
|
|
566
|
+
try {
|
|
567
|
+
const resp = await axios.get(`http://localhost:${port}/health`, { timeout: 500 });
|
|
568
|
+
if (resp.data && resp.data.status === 'ok') {
|
|
569
|
+
console.log(`\n⚠️ Lemma Proxy is already running on port ${port} (Project: ${resp.data.project})`);
|
|
570
|
+
console.log(`💡 Use 'lemma status' for details or 'lemma stop' to restart.\n`);
|
|
571
|
+
process.exit(0);
|
|
572
|
+
}
|
|
573
|
+
} catch {}
|
|
574
|
+
|
|
487
575
|
if (opts.stack) {
|
|
488
576
|
const { spawn } = require('child_process');
|
|
489
577
|
console.log('🚀 Launching Lemma Full Stack...');
|
|
@@ -534,15 +622,32 @@ program.command('start')
|
|
|
534
622
|
|
|
535
623
|
program.command('stop')
|
|
536
624
|
.description('Stop the proxy server')
|
|
537
|
-
.
|
|
625
|
+
.option('-p, --port <number>', 'Port to check', '8081')
|
|
626
|
+
.action((opts) => {
|
|
627
|
+
const port = parseInt(opts.port, 10);
|
|
628
|
+
let stopped = false;
|
|
538
629
|
try {
|
|
539
630
|
if (fs.existsSync(PID_FILE)) {
|
|
540
631
|
const pid = fs.readFileSync(PID_FILE, 'utf8');
|
|
541
|
-
|
|
632
|
+
try {
|
|
633
|
+
process.kill(parseInt(pid), 'SIGTERM');
|
|
634
|
+
stopped = true;
|
|
635
|
+
} catch {}
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
if (!stopped) {
|
|
639
|
+
const pidByPort = getPidByPort(port);
|
|
640
|
+
if (pidByPort) {
|
|
641
|
+
process.kill(parseInt(pidByPort), 'SIGTERM');
|
|
642
|
+
console.log(`✅ Stopped process ${pidByPort} on port ${port}`);
|
|
643
|
+
stopped = true;
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
if (stopped) {
|
|
542
648
|
console.log('✅ Stopped');
|
|
543
649
|
} else {
|
|
544
|
-
console.log('⚠️ No
|
|
545
|
-
// Fallback for windows/mac: kill by port or name
|
|
650
|
+
console.log('⚠️ No running process found.');
|
|
546
651
|
}
|
|
547
652
|
} catch { console.log('⚠️ Could not stop process.'); }
|
|
548
653
|
if (fs.existsSync(PID_FILE)) fs.unlinkSync(PID_FILE);
|
|
@@ -605,15 +710,28 @@ program.command('init')
|
|
|
605
710
|
.description('Initialize Lemma in the current project (auto-discovery)')
|
|
606
711
|
.action(() => {
|
|
607
712
|
const project = detectProject();
|
|
608
|
-
console.log(
|
|
713
|
+
console.log(`\n🛠️ Initializing Lemma for [${project}]...`);
|
|
609
714
|
|
|
715
|
+
// 1. Create .lemma directory
|
|
716
|
+
const lemmaDir = path.join(process.cwd(), '.lemma');
|
|
717
|
+
if (!fs.existsSync(lemmaDir)) {
|
|
718
|
+
fs.mkdirSync(lemmaDir, { recursive: true });
|
|
719
|
+
console.log('✅ Created .lemma directory (Telepathic Sync enabled)');
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
// 2. Update .gitignore
|
|
723
|
+
if (ensureGitIgnore()) {
|
|
724
|
+
console.log('✅ Added .lemma/ to .gitignore');
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
// 3. Update .env
|
|
610
728
|
const envFile = path.join(process.cwd(), '.env');
|
|
611
729
|
const lemmaConfig = `\n# Lemma AI Gateway Configuration\nOPENAI_BASE_URL=http://localhost:8081/v1\nLEMMA_PROJECT=${project}\n`;
|
|
612
730
|
|
|
613
731
|
if (fs.existsSync(envFile)) {
|
|
614
732
|
const content = fs.readFileSync(envFile, 'utf8');
|
|
615
733
|
if (content.includes('OPENAI_BASE_URL')) {
|
|
616
|
-
console.log('⚠️ OPENAI_BASE_URL already exists in .env.
|
|
734
|
+
console.log('⚠️ OPENAI_BASE_URL already exists in .env. Update it to: http://localhost:8081/v1');
|
|
617
735
|
} else {
|
|
618
736
|
fs.appendFileSync(envFile, lemmaConfig);
|
|
619
737
|
console.log('✅ Added Lemma configuration to .env');
|
|
@@ -623,7 +741,8 @@ program.command('init')
|
|
|
623
741
|
console.log('✅ Created .env with Lemma configuration');
|
|
624
742
|
}
|
|
625
743
|
|
|
626
|
-
console.log('\n
|
|
744
|
+
console.log('\n✨ Project initialized for the Agentic Era!');
|
|
745
|
+
console.log('🚀 Run "lemma start" to begin.\n');
|
|
627
746
|
});
|
|
628
747
|
|
|
629
748
|
program.parse(process.argv);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nxuss/lemma",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.5",
|
|
4
4
|
"description": "Intelligent AI Gateway — Semantic cache, Privacy Firewall, and Autonomous Cost-Optimization for AI Agents.",
|
|
5
5
|
"main": "./dist/cjs/index.js",
|
|
6
6
|
"module": "./dist/esm/index.js",
|
|
@@ -161,6 +161,7 @@
|
|
|
161
161
|
"homepage": "https://github.com/Nxusbets/lemma#readme",
|
|
162
162
|
"dependencies": {
|
|
163
163
|
"@chroma-core/default-embed": "^0.1.9",
|
|
164
|
+
"@nxuss/lemma": "^0.4.3",
|
|
164
165
|
"@types/cors": "^2.8.19",
|
|
165
166
|
"axios": "^1.6.0",
|
|
166
167
|
"commander": "^14.0.3",
|