@nxuss/lemma 0.4.2 → 0.4.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.
Files changed (2) hide show
  1. package/lemma-proxy.cjs +60 -8
  2. 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 v0.4.1 — Universal AI Cache CLI
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,21 @@ 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
+
79
96
  // ── License helpers ────────────────────────────────────────────────────────────
80
97
  function loadLicense() {
81
98
  return readJson(LICENSE_FILE, { isPro: false });
@@ -87,7 +104,7 @@ async function validateKeyRemote(key) {
87
104
  const body = JSON.stringify({ key });
88
105
  const u = new URL(VALIDATE_URL);
89
106
  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': 'lemma-proxy/0.3.2' }
107
+ headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(body), 'User-Agent': `lemma-proxy/${VERSION}` }
91
108
  }, res => {
92
109
  let d = '';
93
110
  res.on('data', c => d += c);
@@ -464,17 +481,25 @@ class LemmaServer {
464
481
 
465
482
  start() {
466
483
  const server = http.createServer(this.app);
484
+ server.on('error', (e) => {
485
+ if (e.code === 'EADDRINUSE') {
486
+ console.error(`\n❌ Error: Port ${this.port} is already in use.`);
487
+ console.error(`💡 Try stopping the existing process with 'lemma stop' or use a different port with '--port <number>'.\n`);
488
+ process.exit(1);
489
+ }
490
+ throw e;
491
+ });
467
492
  server.listen(this.port, () => {
468
493
  fs.writeFileSync(PID_FILE, String(process.pid));
469
494
  fs.writeFileSync(PORT_FILE, String(this.port));
470
- console.log(`\n🚀 Lemma Proxy v0.4.1\n📁 Project : ${this.projectName}\n🔌 Port : ${this.port}\n`);
495
+ console.log(`\n🚀 Lemma Proxy v${VERSION}\n📁 Project : ${this.projectName}\n🔌 Port : ${this.port}\n`);
471
496
  });
472
497
  process.on('SIGTERM', () => server.close());
473
498
  }
474
499
  }
475
500
 
476
501
  // ── CLI ────────────────────────────────────────────────────────────────────────
477
- program.name('lemma').description('Lemma Proxy CLI — Intelligent AI Gateway').version('0.4.1');
502
+ program.name('lemma').description('Lemma Proxy CLI — Intelligent AI Gateway').version(VERSION);
478
503
 
479
504
  program.command('start')
480
505
  .description('Start the proxy server')
@@ -484,6 +509,16 @@ program.command('start')
484
509
  .action(async (opts) => {
485
510
  const port = parseInt(opts.port, 10);
486
511
 
512
+ // Check if already running
513
+ try {
514
+ const resp = await axios.get(`http://localhost:${port}/health`, { timeout: 500 });
515
+ if (resp.data && resp.data.status === 'ok') {
516
+ console.log(`\n⚠️ Lemma Proxy is already running on port ${port} (Project: ${resp.data.project})`);
517
+ console.log(`💡 Use 'lemma status' for details or 'lemma stop' to restart.\n`);
518
+ process.exit(0);
519
+ }
520
+ } catch {}
521
+
487
522
  if (opts.stack) {
488
523
  const { spawn } = require('child_process');
489
524
  console.log('🚀 Launching Lemma Full Stack...');
@@ -534,15 +569,32 @@ program.command('start')
534
569
 
535
570
  program.command('stop')
536
571
  .description('Stop the proxy server')
537
- .action(() => {
572
+ .option('-p, --port <number>', 'Port to check', '8081')
573
+ .action((opts) => {
574
+ const port = parseInt(opts.port, 10);
575
+ let stopped = false;
538
576
  try {
539
577
  if (fs.existsSync(PID_FILE)) {
540
578
  const pid = fs.readFileSync(PID_FILE, 'utf8');
541
- process.kill(parseInt(pid), 'SIGTERM');
579
+ try {
580
+ process.kill(parseInt(pid), 'SIGTERM');
581
+ stopped = true;
582
+ } catch {}
583
+ }
584
+
585
+ if (!stopped) {
586
+ const pidByPort = getPidByPort(port);
587
+ if (pidByPort) {
588
+ process.kill(parseInt(pidByPort), 'SIGTERM');
589
+ console.log(`✅ Stopped process ${pidByPort} on port ${port}`);
590
+ stopped = true;
591
+ }
592
+ }
593
+
594
+ if (stopped) {
542
595
  console.log('✅ Stopped');
543
596
  } else {
544
- console.log('⚠️ No PID file found. Checking for processes...');
545
- // Fallback for windows/mac: kill by port or name
597
+ console.log('⚠️ No running process found.');
546
598
  }
547
599
  } catch { console.log('⚠️ Could not stop process.'); }
548
600
  if (fs.existsSync(PID_FILE)) fs.unlinkSync(PID_FILE);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nxuss/lemma",
3
- "version": "0.4.2",
3
+ "version": "0.4.4",
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",