@lanonasis/cli 3.6.5 → 3.6.7

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/dist/commands/api-keys.d.ts +2 -1
  2. package/dist/commands/api-keys.js +73 -78
  3. package/dist/commands/auth.js +160 -167
  4. package/dist/commands/completion.js +31 -39
  5. package/dist/commands/config.js +162 -201
  6. package/dist/commands/enhanced-memory.js +11 -17
  7. package/dist/commands/guide.js +79 -88
  8. package/dist/commands/init.js +14 -20
  9. package/dist/commands/mcp.d.ts +10 -0
  10. package/dist/commands/mcp.js +167 -156
  11. package/dist/commands/memory.js +77 -83
  12. package/dist/commands/organization.js +15 -21
  13. package/dist/commands/topics.js +52 -58
  14. package/dist/core/achievements.js +19 -26
  15. package/dist/core/architecture.js +42 -59
  16. package/dist/core/dashboard.js +71 -81
  17. package/dist/core/error-handler.js +30 -39
  18. package/dist/core/power-mode.js +46 -53
  19. package/dist/core/progress.js +35 -44
  20. package/dist/core/welcome.js +56 -64
  21. package/dist/enhanced-cli.js +49 -58
  22. package/dist/index-simple.js +75 -113
  23. package/dist/index.js +64 -69
  24. package/dist/mcp/access-control.js +13 -17
  25. package/dist/mcp/client/enhanced-client.js +16 -23
  26. package/dist/mcp/enhanced-server.js +10 -14
  27. package/dist/mcp/logger.js +3 -7
  28. package/dist/mcp/memory-state.js +13 -17
  29. package/dist/mcp/schemas/tool-schemas.d.ts +16 -16
  30. package/dist/mcp/schemas/tool-schemas.js +122 -126
  31. package/dist/mcp/server/lanonasis-server.js +66 -57
  32. package/dist/mcp/transports/transport-manager.js +18 -25
  33. package/dist/mcp/vector-store.js +6 -10
  34. package/dist/mcp-server.js +23 -27
  35. package/dist/utils/api.js +19 -26
  36. package/dist/utils/config.d.ts +2 -1
  37. package/dist/utils/config.js +65 -78
  38. package/dist/utils/formatting.js +6 -14
  39. package/dist/utils/mcp-client.js +76 -117
  40. package/package.json +36 -5
package/dist/utils/api.js CHANGED
@@ -1,19 +1,13 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.apiClient = exports.APIClient = void 0;
7
- const axios_1 = __importDefault(require("axios"));
8
- const chalk_1 = __importDefault(require("chalk"));
9
- const crypto_1 = require("crypto");
10
- const config_js_1 = require("./config.js");
11
- class APIClient {
1
+ import axios from 'axios';
2
+ import chalk from 'chalk';
3
+ import { randomUUID } from 'crypto';
4
+ import { CLIConfig } from './config.js';
5
+ export class APIClient {
12
6
  client;
13
7
  config;
14
8
  constructor() {
15
- this.config = new config_js_1.CLIConfig();
16
- this.client = axios_1.default.create({
9
+ this.config = new CLIConfig();
10
+ this.client = axios.create({
17
11
  proxy: false // Bypass proxy to avoid redirect loops in containerized environments
18
12
  });
19
13
  // Setup request interceptor to add auth token and headers
@@ -45,44 +39,44 @@ class APIClient {
45
39
  config.headers['X-Auth-Method'] = 'jwt';
46
40
  }
47
41
  // Add request ID for correlation
48
- const requestId = (0, crypto_1.randomUUID)();
42
+ const requestId = randomUUID();
49
43
  config.headers['X-Request-ID'] = requestId;
50
44
  // Add project scope for Golden Contract compliance
51
45
  config.headers['X-Project-Scope'] = 'lanonasis-maas';
52
46
  if (process.env.CLI_VERBOSE === 'true') {
53
- console.log(chalk_1.default.dim(`→ ${config.method?.toUpperCase()} ${config.url} [${requestId}]`));
47
+ console.log(chalk.dim(`→ ${config.method?.toUpperCase()} ${config.url} [${requestId}]`));
54
48
  }
55
49
  return config;
56
50
  });
57
51
  // Setup response interceptor for error handling
58
52
  this.client.interceptors.response.use((response) => {
59
53
  if (process.env.CLI_VERBOSE === 'true') {
60
- console.log(chalk_1.default.dim(`← ${response.status} ${response.statusText}`));
54
+ console.log(chalk.dim(`← ${response.status} ${response.statusText}`));
61
55
  }
62
56
  return response;
63
57
  }, (error) => {
64
58
  if (error.response) {
65
59
  const { status, data } = error.response;
66
60
  if (status === 401) {
67
- console.error(chalk_1.default.red('✖ Authentication failed'));
68
- console.log(chalk_1.default.yellow('Please run:'), chalk_1.default.white('memory login'));
61
+ console.error(chalk.red('✖ Authentication failed'));
62
+ console.log(chalk.yellow('Please run:'), chalk.white('memory login'));
69
63
  process.exit(1);
70
64
  }
71
65
  if (status === 403) {
72
- console.error(chalk_1.default.red('✖ Permission denied'));
66
+ console.error(chalk.red('✖ Permission denied'));
73
67
  if (data.message) {
74
- console.error(chalk_1.default.gray(data.message));
68
+ console.error(chalk.gray(data.message));
75
69
  }
76
70
  process.exit(1);
77
71
  }
78
72
  if (status === 429) {
79
- console.error(chalk_1.default.red('✖ Rate limit exceeded'));
80
- console.error(chalk_1.default.gray('Please wait a moment before trying again'));
73
+ console.error(chalk.red('✖ Rate limit exceeded'));
74
+ console.error(chalk.gray('Please wait a moment before trying again'));
81
75
  process.exit(1);
82
76
  }
83
77
  if (process.env.CLI_VERBOSE === 'true') {
84
- console.error(chalk_1.default.dim(`← ${status} ${error.response.statusText}`));
85
- console.error(chalk_1.default.dim(JSON.stringify(data, null, 2)));
78
+ console.error(chalk.dim(`← ${status} ${error.response.statusText}`));
79
+ console.error(chalk.dim(JSON.stringify(data, null, 2)));
86
80
  }
87
81
  }
88
82
  return Promise.reject(error);
@@ -189,5 +183,4 @@ class APIClient {
189
183
  return response.data;
190
184
  }
191
185
  }
192
- exports.APIClient = APIClient;
193
- exports.apiClient = new APIClient();
186
+ export const apiClient = new APIClient();
@@ -13,7 +13,7 @@ interface CLIConfigData {
13
13
  mcpServerPath?: string;
14
14
  mcpServerUrl?: string;
15
15
  mcpUseRemote?: boolean;
16
- mcpPreference?: 'local' | 'remote' | 'auto';
16
+ mcpPreference?: 'local' | 'remote' | 'websocket' | 'auto';
17
17
  discoveredServices?: {
18
18
  auth_base: string;
19
19
  memory_base: string;
@@ -65,6 +65,7 @@ export declare class CLIConfig {
65
65
  private categorizeServiceDiscoveryError;
66
66
  private resolveFallbackEndpoints;
67
67
  private logFallbackUsage;
68
+ private pingAuthHealth;
68
69
  setManualEndpoints(endpoints: Partial<CLIConfigData['discoveredServices']>): Promise<void>;
69
70
  hasManualEndpointOverrides(): boolean;
70
71
  clearManualEndpointOverrides(): Promise<void>;
@@ -1,45 +1,9 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.CLIConfig = void 0;
37
- const fs = __importStar(require("fs/promises"));
38
- const path = __importStar(require("path"));
39
- const os = __importStar(require("os"));
40
- const jwt_decode_1 = require("jwt-decode");
41
- const crypto_1 = require("crypto");
42
- class CLIConfig {
1
+ import * as fs from 'fs/promises';
2
+ import * as path from 'path';
3
+ import * as os from 'os';
4
+ import { jwtDecode } from 'jwt-decode';
5
+ import { randomUUID } from 'crypto';
6
+ export class CLIConfig {
43
7
  configDir;
44
8
  configPath;
45
9
  config = {};
@@ -119,7 +83,7 @@ class CLIConfig {
119
83
  this.config.version = CLIConfig.CONFIG_VERSION;
120
84
  this.config.lastUpdated = new Date().toISOString();
121
85
  // Create temporary file with unique name
122
- const tempPath = `${this.configPath}.tmp.${(0, crypto_1.randomUUID)()}`;
86
+ const tempPath = `${this.configPath}.tmp.${randomUUID()}`;
123
87
  // Write to temporary file first
124
88
  await fs.writeFile(tempPath, JSON.stringify(this.config, null, 2), 'utf-8');
125
89
  // Atomic rename - this is the critical atomic operation
@@ -201,7 +165,7 @@ class CLIConfig {
201
165
  getApiUrl() {
202
166
  return process.env.MEMORY_API_URL ||
203
167
  this.config.apiUrl ||
204
- 'https://api.lanonasis.com/api/v1';
168
+ 'https://mcp.lanonasis.com/api/v1';
205
169
  }
206
170
  // Enhanced Service Discovery Integration
207
171
  async discoverServices(verbose = false) {
@@ -228,14 +192,16 @@ class CLIConfig {
228
192
  if (authBase.includes('localhost') || authBase.includes('127.0.0.1')) {
229
193
  authBase = 'https://auth.lanonasis.com';
230
194
  }
195
+ const memoryBase = discovered.endpoints?.http || 'https://mcp.lanonasis.com/api/v1';
231
196
  this.config.discoveredServices = {
232
197
  auth_base: authBase || 'https://auth.lanonasis.com',
233
- memory_base: 'https://api.lanonasis.com/api/v1',
234
- mcp_base: discovered.endpoints?.http || 'https://mcp.lanonasis.com/api/v1',
198
+ memory_base: memoryBase,
199
+ mcp_base: memoryBase,
235
200
  mcp_ws_base: discovered.endpoints?.websocket || 'wss://mcp.lanonasis.com/ws',
236
201
  mcp_sse_base: discovered.endpoints?.sse || 'https://mcp.lanonasis.com/api/v1/events',
237
202
  project_scope: 'lanonasis-maas'
238
203
  };
204
+ this.config.apiUrl = memoryBase;
239
205
  // Mark discovery as successful
240
206
  this.config.lastServiceDiscovery = new Date().toISOString();
241
207
  await this.save();
@@ -292,6 +258,7 @@ class CLIConfig {
292
258
  ...fallback.endpoints,
293
259
  project_scope: 'lanonasis-maas'
294
260
  };
261
+ this.config.apiUrl = fallback.endpoints.memory_base;
295
262
  // Mark as fallback (don't set lastServiceDiscovery)
296
263
  await this.save();
297
264
  this.logFallbackUsage(fallback.source, this.config.discoveredServices);
@@ -337,7 +304,7 @@ class CLIConfig {
337
304
  const nodeEnv = (process.env.NODE_ENV ?? '').toLowerCase();
338
305
  const isDevEnvironment = nodeEnv === 'development' || nodeEnv === 'test';
339
306
  const defaultAuthBase = isDevEnvironment ? 'http://localhost:4000' : 'https://auth.lanonasis.com';
340
- const defaultMemoryBase = isDevEnvironment ? 'http://localhost:4000/api/v1' : 'https://api.lanonasis.com/api/v1';
307
+ const defaultMemoryBase = isDevEnvironment ? 'http://localhost:4000/api/v1' : 'https://mcp.lanonasis.com/api/v1';
341
308
  const defaultMcpBase = isDevEnvironment ? 'http://localhost:4100/api/v1' : 'https://mcp.lanonasis.com/api/v1';
342
309
  const defaultMcpWsBase = isDevEnvironment ? 'ws://localhost:4100/ws' : 'wss://mcp.lanonasis.com/ws';
343
310
  const defaultMcpSseBase = isDevEnvironment ? 'http://localhost:4100/api/v1/events' : 'https://mcp.lanonasis.com/api/v1/events';
@@ -368,6 +335,34 @@ class CLIConfig {
368
335
  process.emitWarning(message, 'ServiceDiscoveryFallback');
369
336
  }
370
337
  }
338
+ async pingAuthHealth(axiosInstance, authBase, headers, options = {}) {
339
+ const normalizedBase = authBase.replace(/\/$/, '');
340
+ const endpoints = [
341
+ `${normalizedBase}/health`,
342
+ `${normalizedBase}/api/v1/health`
343
+ ];
344
+ let lastError;
345
+ for (const endpoint of endpoints) {
346
+ try {
347
+ const requestConfig = {
348
+ headers,
349
+ timeout: options.timeout ?? 10000
350
+ };
351
+ if (options.proxy === false) {
352
+ requestConfig.proxy = false;
353
+ }
354
+ await axiosInstance.get(endpoint, requestConfig);
355
+ return;
356
+ }
357
+ catch (error) {
358
+ lastError = error;
359
+ }
360
+ }
361
+ if (lastError instanceof Error) {
362
+ throw lastError;
363
+ }
364
+ throw new Error('Auth health endpoints unreachable');
365
+ }
371
366
  // Manual endpoint override functionality
372
367
  async setManualEndpoints(endpoints) {
373
368
  if (!this.config.discoveredServices) {
@@ -388,13 +383,15 @@ class CLIConfig {
388
383
  return !!this.config.manualEndpointOverrides;
389
384
  }
390
385
  async clearManualEndpointOverrides() {
391
- this.config.manualEndpointOverrides = undefined;
392
- this.config.lastManualEndpointUpdate = undefined;
386
+ delete this.config.manualEndpointOverrides;
387
+ delete this.config.lastManualEndpointUpdate;
393
388
  // Rediscover services
394
389
  await this.discoverServices();
395
390
  }
396
391
  getDiscoveredApiUrl() {
397
- return this.config.discoveredServices?.auth_base || this.getApiUrl();
392
+ return process.env.AUTH_BASE ||
393
+ this.config.discoveredServices?.auth_base ||
394
+ 'https://auth.lanonasis.com';
398
395
  }
399
396
  // Enhanced authentication support
400
397
  async setVendorKey(vendorKey) {
@@ -426,16 +423,11 @@ class CLIConfig {
426
423
  // Ensure service discovery is done
427
424
  await this.discoverServices();
428
425
  const authBase = this.config.discoveredServices?.auth_base || 'https://auth.lanonasis.com';
429
- // Test vendor key with health endpoint
430
- await axios.get(`${authBase}/health`, {
431
- headers: {
432
- 'X-API-Key': vendorKey,
433
- 'X-Auth-Method': 'vendor_key',
434
- 'X-Project-Scope': 'lanonasis-maas'
435
- },
436
- timeout: 10000,
437
- proxy: false // Bypass proxy to avoid redirect loops
438
- });
426
+ await this.pingAuthHealth(axios, authBase, {
427
+ 'X-API-Key': vendorKey,
428
+ 'X-Auth-Method': 'vendor_key',
429
+ 'X-Project-Scope': 'lanonasis-maas'
430
+ }, { timeout: 10000, proxy: false });
439
431
  }
440
432
  catch (error) {
441
433
  // Provide specific error messages based on response
@@ -497,7 +489,7 @@ class CLIConfig {
497
489
  await this.resetFailureCount(); // Reset failure count on successful auth
498
490
  // Decode token to get user info and expiry
499
491
  try {
500
- const decoded = (0, jwt_decode_1.jwtDecode)(token);
492
+ const decoded = jwtDecode(token);
501
493
  // Store token expiry
502
494
  if (typeof decoded.exp === 'number') {
503
495
  this.config.tokenExpiry = decoded.exp;
@@ -554,7 +546,7 @@ class CLIConfig {
554
546
  else {
555
547
  // Handle JWT tokens
556
548
  try {
557
- const decoded = (0, jwt_decode_1.jwtDecode)(token);
549
+ const decoded = jwtDecode(token);
558
550
  const now = Date.now() / 1000;
559
551
  locallyValid = typeof decoded.exp === 'number' && decoded.exp > now;
560
552
  }
@@ -568,8 +560,7 @@ class CLIConfig {
568
560
  const axios = (await import('axios')).default;
569
561
  const endpoints = [
570
562
  'http://localhost:4000/v1/auth/verify-token',
571
- 'https://auth.lanonasis.com/v1/auth/verify-token',
572
- 'https://api.lanonasis.com/auth/verify'
563
+ 'https://auth.lanonasis.com/v1/auth/verify-token'
573
564
  ];
574
565
  for (const endpoint of endpoints) {
575
566
  try {
@@ -607,8 +598,7 @@ class CLIConfig {
607
598
  // Try auth-gateway first (port 4000), then fall back to Netlify function
608
599
  const endpoints = [
609
600
  'http://localhost:4000/v1/auth/verify-token',
610
- 'https://auth.lanonasis.com/v1/auth/verify-token',
611
- 'https://api.lanonasis.com/auth/verify'
601
+ 'https://auth.lanonasis.com/v1/auth/verify-token'
612
602
  ];
613
603
  let response = null;
614
604
  for (const endpoint of endpoints) {
@@ -681,7 +671,7 @@ class CLIConfig {
681
671
  const axios = (await import('axios')).default;
682
672
  // Ensure service discovery is done
683
673
  await this.discoverServices();
684
- const authBase = this.config.discoveredServices?.auth_base || 'https://api.lanonasis.com';
674
+ const authBase = this.config.discoveredServices?.auth_base || 'https://auth.lanonasis.com';
685
675
  const headers = {
686
676
  'X-Project-Scope': 'lanonasis-maas'
687
677
  };
@@ -693,11 +683,7 @@ class CLIConfig {
693
683
  headers['Authorization'] = `Bearer ${token}`;
694
684
  headers['X-Auth-Method'] = 'jwt';
695
685
  }
696
- // Validate against server with health endpoint
697
- await axios.get(`${authBase}/api/v1/health`, {
698
- headers,
699
- timeout: 10000
700
- });
686
+ await this.pingAuthHealth(axios, authBase, headers);
701
687
  // Update last validated timestamp
702
688
  this.config.lastValidated = new Date().toISOString();
703
689
  await this.resetFailureCount();
@@ -721,7 +707,7 @@ class CLIConfig {
721
707
  // CLI tokens don't need refresh, they're long-lived
722
708
  return;
723
709
  }
724
- const decoded = (0, jwt_decode_1.jwtDecode)(token);
710
+ const decoded = jwtDecode(token);
725
711
  const now = Date.now() / 1000;
726
712
  const exp = typeof decoded.exp === 'number' ? decoded.exp : 0;
727
713
  // Refresh if token expires within 5 minutes
@@ -729,7 +715,7 @@ class CLIConfig {
729
715
  // Import axios dynamically
730
716
  const axios = (await import('axios')).default;
731
717
  await this.discoverServices();
732
- const authBase = this.config.discoveredServices?.auth_base || 'https://api.lanonasis.com';
718
+ const authBase = this.config.discoveredServices?.auth_base || 'https://auth.lanonasis.com';
733
719
  // Attempt token refresh
734
720
  const response = await axios.post(`${authBase}/v1/auth/refresh`, {}, {
735
721
  headers: {
@@ -795,7 +781,7 @@ class CLIConfig {
795
781
  async getDeviceId() {
796
782
  if (!this.config.deviceId) {
797
783
  // Generate a new device ID
798
- this.config.deviceId = (0, crypto_1.randomUUID)();
784
+ this.config.deviceId = randomUUID();
799
785
  await this.save();
800
786
  }
801
787
  return this.config.deviceId;
@@ -833,15 +819,16 @@ class CLIConfig {
833
819
  shouldUseRemoteMCP() {
834
820
  const preference = this.config.mcpPreference || 'auto';
835
821
  switch (preference) {
822
+ case 'websocket':
836
823
  case 'remote':
837
824
  return true;
838
825
  case 'local':
839
826
  return false;
840
827
  case 'auto':
841
828
  default:
842
- // Use remote if authenticated, otherwise local
843
- return !!this.config.token;
829
+ // Default to remote/websocket (production mode)
830
+ // Local mode should only be used when explicitly configured
831
+ return true;
844
832
  }
845
833
  }
846
834
  }
847
- exports.CLIConfig = CLIConfig;
@@ -1,12 +1,4 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.formatOutput = formatOutput;
4
- exports.formatBytes = formatBytes;
5
- exports.truncateText = truncateText;
6
- exports.formatDuration = formatDuration;
7
- exports.formatDate = formatDate;
8
- exports.formatTableData = formatTableData;
9
- function formatOutput(data, format = 'table') {
1
+ export function formatOutput(data, format = 'table') {
10
2
  switch (format) {
11
3
  case 'json':
12
4
  console.log(JSON.stringify(data, null, 2));
@@ -20,7 +12,7 @@ function formatOutput(data, format = 'table') {
20
12
  break;
21
13
  }
22
14
  }
23
- function formatBytes(bytes) {
15
+ export function formatBytes(bytes) {
24
16
  if (bytes === 0)
25
17
  return '0 Bytes';
26
18
  const k = 1024;
@@ -28,23 +20,23 @@ function formatBytes(bytes) {
28
20
  const i = Math.floor(Math.log(bytes) / Math.log(k));
29
21
  return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
30
22
  }
31
- function truncateText(text, maxLength) {
23
+ export function truncateText(text, maxLength) {
32
24
  if (text.length <= maxLength)
33
25
  return text;
34
26
  return text.substring(0, maxLength - 3) + '...';
35
27
  }
36
- function formatDuration(ms) {
28
+ export function formatDuration(ms) {
37
29
  if (ms < 1000)
38
30
  return `${ms}ms`;
39
31
  if (ms < 60000)
40
32
  return `${(ms / 1000).toFixed(1)}s`;
41
33
  return `${(ms / 60000).toFixed(1)}m`;
42
34
  }
43
- function formatDate(date) {
35
+ export function formatDate(date) {
44
36
  const d = new Date(date);
45
37
  return d.toLocaleString();
46
38
  }
47
- function formatTableData(data) {
39
+ export function formatTableData(data) {
48
40
  return data.map(item => {
49
41
  if (Array.isArray(item))
50
42
  return item.map(String);