@lanonasis/cli 3.2.14 → 3.4.15

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 (36) hide show
  1. package/README.md +57 -13
  2. package/dist/commands/auth.js +7 -7
  3. package/dist/commands/completion.js +2 -0
  4. package/dist/commands/config.js +4 -4
  5. package/dist/commands/enhanced-memory.js +1 -1
  6. package/dist/commands/mcp.js +15 -9
  7. package/dist/core/achievements.js +1 -1
  8. package/dist/core/power-mode.js +5 -3
  9. package/dist/core/welcome.js +7 -6
  10. package/dist/enhanced-cli.js +6 -3
  11. package/dist/index-simple.js +5 -1
  12. package/dist/index.js +5 -1
  13. package/dist/mcp/access-control.d.ts +1 -1
  14. package/dist/mcp/access-control.js +4 -4
  15. package/dist/mcp/client/enhanced-client.js +4 -5
  16. package/dist/mcp/schemas/tool-schemas.d.ts +1 -1
  17. package/dist/mcp/schemas/tool-schemas.js +1 -1
  18. package/dist/mcp/server/lanonasis-server.d.ts +2 -1
  19. package/dist/mcp/server/lanonasis-server.js +7 -5
  20. package/dist/mcp/transports/transport-manager.js +3 -3
  21. package/dist/mcp-server.js +3 -3
  22. package/dist/utils/config.js +59 -10
  23. package/dist/utils/mcp-client.d.ts +4 -2
  24. package/dist/utils/mcp-client.js +86 -42
  25. package/package.json +3 -3
  26. package/dist/__tests__/auth-persistence.test.d.ts +0 -1
  27. package/dist/__tests__/auth-persistence.test.js +0 -243
  28. package/dist/__tests__/cross-device-integration.test.d.ts +0 -1
  29. package/dist/__tests__/cross-device-integration.test.js +0 -305
  30. package/dist/__tests__/mcp-connection-reliability.test.d.ts +0 -1
  31. package/dist/__tests__/mcp-connection-reliability.test.js +0 -489
  32. package/dist/__tests__/setup.d.ts +0 -1
  33. package/dist/__tests__/setup.js +0 -26
  34. package/dist/mcp/server/mcp/server/lanonasis-server.js +0 -911
  35. package/dist/mcp/server/utils/api.js +0 -431
  36. package/dist/mcp/server/utils/config.js +0 -855
@@ -1,305 +0,0 @@
1
- import { describe, it, expect, beforeEach, afterEach, jest } from '@jest/globals';
2
- import { CLIConfig } from '../utils/config.js';
3
- import * as fs from 'fs/promises';
4
- import * as path from 'path';
5
- import * as os from 'os';
6
- // Mock dependencies
7
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
8
- const mockAxios = {
9
- get: jest.fn(),
10
- post: jest.fn()
11
- };
12
- jest.mock('axios', () => ({
13
- default: mockAxios,
14
- get: mockAxios.get,
15
- post: mockAxios.post
16
- }));
17
- jest.mock('eventsource');
18
- jest.mock('ws');
19
- jest.mock('@modelcontextprotocol/sdk/client/index.js', () => ({
20
- Client: jest.fn().mockImplementation(() => ({
21
- connect: jest.fn(),
22
- close: jest.fn(),
23
- callTool: jest.fn(),
24
- listTools: jest.fn()
25
- }))
26
- }));
27
- jest.mock('@modelcontextprotocol/sdk/client/stdio.js', () => ({
28
- StdioClientTransport: jest.fn()
29
- }));
30
- describe('Cross-Device Integration Tests', () => {
31
- let device1Config;
32
- let device2Config;
33
- let device3Config;
34
- let device1Dir;
35
- let device2Dir;
36
- let device3Dir;
37
- beforeEach(async () => {
38
- // Create separate test directories for each "device"
39
- device1Dir = path.join(os.tmpdir(), `test-device1-${Date.now()}-${Math.random()}`);
40
- device2Dir = path.join(os.tmpdir(), `test-device2-${Date.now()}-${Math.random()}`);
41
- device3Dir = path.join(os.tmpdir(), `test-device3-${Date.now()}-${Math.random()}`);
42
- await fs.mkdir(device1Dir, { recursive: true });
43
- await fs.mkdir(device2Dir, { recursive: true });
44
- await fs.mkdir(device3Dir, { recursive: true });
45
- // Create config instances for each "device"
46
- device1Config = new CLIConfig();
47
- device1Config.configDir = device1Dir;
48
- device1Config.configPath = path.join(device1Dir, 'config.json');
49
- device1Config.lockFile = path.join(device1Dir, 'config.lock');
50
- device2Config = new CLIConfig();
51
- device2Config.configDir = device2Dir;
52
- device2Config.configPath = path.join(device2Dir, 'config.json');
53
- device2Config.lockFile = path.join(device2Dir, 'config.lock');
54
- device3Config = new CLIConfig();
55
- device3Config.configDir = device3Dir;
56
- device3Config.configPath = path.join(device3Dir, 'config.json');
57
- device3Config.lockFile = path.join(device3Dir, 'config.lock');
58
- // Initialize all configs
59
- await device1Config.init();
60
- await device2Config.init();
61
- await device3Config.init();
62
- // Clear axios mocks
63
- mockAxios.get.mockClear();
64
- mockAxios.post.mockClear();
65
- });
66
- afterEach(async () => {
67
- // Clean up all test directories
68
- try {
69
- await fs.rm(device1Dir, { recursive: true, force: true });
70
- await fs.rm(device2Dir, { recursive: true, force: true });
71
- await fs.rm(device3Dir, { recursive: true, force: true });
72
- }
73
- catch {
74
- // Ignore cleanup errors
75
- }
76
- });
77
- describe('Same Credentials Working on Multiple Simulated Devices', () => {
78
- it('should allow same vendor key to work on multiple devices', async () => {
79
- const sharedVendorKey = 'pk_shared123456789.sk_shared123456789012345';
80
- // Mock successful server validation for all devices
81
- mockAxios.get.mockResolvedValue({ status: 200, data: { status: 'ok' } });
82
- // Set same vendor key on all devices
83
- await device1Config.setVendorKey(sharedVendorKey);
84
- await device2Config.setVendorKey(sharedVendorKey);
85
- await device3Config.setVendorKey(sharedVendorKey);
86
- // Verify all devices have the same vendor key
87
- expect(device1Config.getVendorKey()).toBe(sharedVendorKey);
88
- expect(device2Config.getVendorKey()).toBe(sharedVendorKey);
89
- expect(device3Config.getVendorKey()).toBe(sharedVendorKey);
90
- // Verify all devices have same auth method
91
- expect(device1Config.get('authMethod')).toBe('vendor_key');
92
- expect(device2Config.get('authMethod')).toBe('vendor_key');
93
- expect(device3Config.get('authMethod')).toBe('vendor_key');
94
- // Verify server validation was called for each device
95
- expect(mockAxios.get).toHaveBeenCalledTimes(3);
96
- });
97
- it('should maintain separate device IDs while sharing credentials', async () => {
98
- const sharedVendorKey = 'pk_shared123456789.sk_shared123456789012345';
99
- // Mock successful server validation
100
- mockAxios.get.mockResolvedValue({ status: 200, data: { status: 'ok' } });
101
- // Set same vendor key on all devices
102
- await device1Config.setVendorKey(sharedVendorKey);
103
- await device2Config.setVendorKey(sharedVendorKey);
104
- await device3Config.setVendorKey(sharedVendorKey);
105
- // Get device IDs
106
- const deviceId1 = await device1Config.getDeviceId();
107
- const deviceId2 = await device2Config.getDeviceId();
108
- const deviceId3 = await device3Config.getDeviceId();
109
- // Device IDs should be different
110
- expect(deviceId1).not.toBe(deviceId2);
111
- expect(deviceId1).not.toBe(deviceId3);
112
- expect(deviceId2).not.toBe(deviceId3);
113
- // But credentials should be the same
114
- expect(device1Config.getVendorKey()).toBe(sharedVendorKey);
115
- expect(device2Config.getVendorKey()).toBe(sharedVendorKey);
116
- expect(device3Config.getVendorKey()).toBe(sharedVendorKey);
117
- });
118
- });
119
- describe('Service Discovery Consistency Across Environments', () => {
120
- it('should discover same service endpoints from all devices', async () => {
121
- // Mock service discovery response
122
- const mockDiscoveryResponse = {
123
- auth: { login: 'https://api.lanonasis.com/auth/login' },
124
- endpoints: {
125
- http: 'https://mcp.lanonasis.com/api/v1',
126
- websocket: 'wss://mcp.lanonasis.com/ws',
127
- sse: 'https://mcp.lanonasis.com/api/v1/events'
128
- }
129
- };
130
- mockAxios.get.mockResolvedValue({ data: mockDiscoveryResponse });
131
- // Perform service discovery on all devices
132
- await device1Config.discoverServices();
133
- await device2Config.discoverServices();
134
- await device3Config.discoverServices();
135
- // All devices should have discovered the same endpoints
136
- const services1 = device1Config.get('discoveredServices');
137
- const services2 = device2Config.get('discoveredServices');
138
- const services3 = device3Config.get('discoveredServices');
139
- expect(services1).toEqual(services2);
140
- expect(services1).toEqual(services3);
141
- expect(services2).toEqual(services3);
142
- // Verify specific endpoints
143
- expect(services1.mcp_base).toBe('https://mcp.lanonasis.com/api/v1');
144
- expect(services1.mcp_ws_base).toBe('wss://mcp.lanonasis.com/ws');
145
- expect(services1.mcp_sse_base).toBe('https://mcp.lanonasis.com/api/v1/events');
146
- });
147
- it('should handle service discovery failures consistently', async () => {
148
- // Mock service discovery failure
149
- mockAxios.get.mockRejectedValue(new Error('Service discovery failed'));
150
- const consoleSpy = jest.spyOn(console, 'log').mockImplementation(() => { });
151
- // Attempt service discovery on all devices
152
- await device1Config.discoverServices(true);
153
- await device2Config.discoverServices(true);
154
- await device3Config.discoverServices(true);
155
- // All devices should fall back to same default endpoints
156
- const services1 = device1Config.get('discoveredServices');
157
- const services2 = device2Config.get('discoveredServices');
158
- const services3 = device3Config.get('discoveredServices');
159
- expect(services1).toEqual(services2);
160
- expect(services1).toEqual(services3);
161
- // Should use fallback endpoints
162
- expect(services1.auth_base).toBe('https://api.lanonasis.com');
163
- expect(services1.mcp_base).toBe('https://mcp.lanonasis.com/api/v1');
164
- expect(services1.mcp_ws_base).toBe('wss://mcp.lanonasis.com/ws');
165
- consoleSpy.mockRestore();
166
- });
167
- });
168
- describe('Configuration Synchronization and Compatibility', () => {
169
- it('should maintain configuration version compatibility across devices', async () => {
170
- // All devices should have the same config version
171
- expect(device1Config.get('version')).toBe('1.0.0');
172
- expect(device2Config.get('version')).toBe('1.0.0');
173
- expect(device3Config.get('version')).toBe('1.0.0');
174
- // Set some data on device 1
175
- await device1Config.setAndSave('testData', 'test-value');
176
- // Read config file directly and apply to device 2
177
- const configPath1 = device1Config.configPath;
178
- const configData = JSON.parse(await fs.readFile(configPath1, 'utf-8'));
179
- const configPath2 = device2Config.configPath;
180
- await fs.writeFile(configPath2, JSON.stringify(configData, null, 2));
181
- // Reload device 2 config
182
- await device2Config.load();
183
- // Device 2 should have the same data and version
184
- expect(device2Config.get('testData')).toBe('test-value');
185
- expect(device2Config.get('version')).toBe('1.0.0');
186
- });
187
- it('should create consistent backup files across devices', async () => {
188
- const testData = { test: 'backup-data', timestamp: Date.now() };
189
- // Set data on all devices
190
- await device1Config.setAndSave('backupTest', testData);
191
- await device2Config.setAndSave('backupTest', testData);
192
- await device3Config.setAndSave('backupTest', testData);
193
- // Create backups on all devices
194
- const backup1 = await device1Config.backupConfig();
195
- const backup2 = await device2Config.backupConfig();
196
- const backup3 = await device3Config.backupConfig();
197
- // All backups should exist
198
- expect(await fs.access(backup1).then(() => true).catch(() => false)).toBe(true);
199
- expect(await fs.access(backup2).then(() => true).catch(() => false)).toBe(true);
200
- expect(await fs.access(backup3).then(() => true).catch(() => false)).toBe(true);
201
- // All backups should contain the same data
202
- const backupData1 = JSON.parse(await fs.readFile(backup1, 'utf-8'));
203
- const backupData2 = JSON.parse(await fs.readFile(backup2, 'utf-8'));
204
- const backupData3 = JSON.parse(await fs.readFile(backup3, 'utf-8'));
205
- expect(backupData1.backupTest).toEqual(testData);
206
- expect(backupData2.backupTest).toEqual(testData);
207
- expect(backupData3.backupTest).toEqual(testData);
208
- // All should have same version
209
- expect(backupData1.version).toBe('1.0.0');
210
- expect(backupData2.version).toBe('1.0.0');
211
- expect(backupData3.version).toBe('1.0.0');
212
- });
213
- });
214
- describe('Error Message Consistency Across Different Failure Scenarios', () => {
215
- it('should provide consistent error messages for authentication failures', async () => {
216
- const invalidVendorKey = 'pk_invalid.sk_invalid';
217
- // Mock authentication failure
218
- mockAxios.get.mockRejectedValue({
219
- response: { status: 401, data: { error: 'invalid vendor key' } }
220
- });
221
- // Attempt to set invalid vendor key on all devices
222
- const errors = [];
223
- try {
224
- await device1Config.setVendorKey(invalidVendorKey);
225
- }
226
- catch (error) {
227
- errors.push(error.message);
228
- }
229
- try {
230
- await device2Config.setVendorKey(invalidVendorKey);
231
- }
232
- catch (error) {
233
- errors.push(error.message);
234
- }
235
- try {
236
- await device3Config.setVendorKey(invalidVendorKey);
237
- }
238
- catch (error) {
239
- errors.push(error.message);
240
- }
241
- // All devices should get the same error message
242
- expect(errors).toHaveLength(3);
243
- expect(errors[0]).toBe(errors[1]);
244
- expect(errors[0]).toBe(errors[2]);
245
- expect(errors[0]).toContain('Vendor key authentication failed');
246
- });
247
- it('should provide consistent validation error messages', async () => {
248
- const invalidFormats = [
249
- 'invalid-key',
250
- 'pk_short.sk_short',
251
- 'pk_.sk_test123456789012345',
252
- 'pk_test123456789.sk_'
253
- ];
254
- for (const invalidKey of invalidFormats) {
255
- const validationResults = [];
256
- // Test validation on all devices
257
- validationResults.push(device1Config.validateVendorKeyFormat(invalidKey));
258
- validationResults.push(device2Config.validateVendorKeyFormat(invalidKey));
259
- validationResults.push(device3Config.validateVendorKeyFormat(invalidKey));
260
- // All devices should return the same validation error
261
- expect(validationResults[0]).toBe(validationResults[1]);
262
- expect(validationResults[0]).toBe(validationResults[2]);
263
- expect(typeof validationResults[0]).toBe('string'); // Should be error message
264
- }
265
- });
266
- it('should maintain consistent failure tracking across devices', async () => {
267
- const sharedVendorKey = 'pk_shared123456789.sk_shared123456789012345';
268
- // Mock successful initial setup
269
- mockAxios.get.mockResolvedValue({ status: 200, data: { status: 'ok' } });
270
- // Set vendor key on all devices
271
- await device1Config.setVendorKey(sharedVendorKey);
272
- await device2Config.setVendorKey(sharedVendorKey);
273
- await device3Config.setVendorKey(sharedVendorKey);
274
- // Mock validation failure
275
- mockAxios.get.mockRejectedValue({
276
- response: { status: 401, data: { error: 'invalid credentials' } }
277
- });
278
- // Validate credentials on all devices (should fail)
279
- await device1Config.validateStoredCredentials();
280
- await device2Config.validateStoredCredentials();
281
- await device3Config.validateStoredCredentials();
282
- // All devices should have incremented failure count
283
- expect(device1Config.getFailureCount()).toBe(1);
284
- expect(device2Config.getFailureCount()).toBe(1);
285
- expect(device3Config.getFailureCount()).toBe(1);
286
- // Add more failures to test delay calculation consistency
287
- await device1Config.incrementFailureCount();
288
- await device1Config.incrementFailureCount();
289
- await device2Config.incrementFailureCount();
290
- await device2Config.incrementFailureCount();
291
- await device3Config.incrementFailureCount();
292
- await device3Config.incrementFailureCount();
293
- // All devices should have same failure count and delay
294
- expect(device1Config.getFailureCount()).toBe(3);
295
- expect(device2Config.getFailureCount()).toBe(3);
296
- expect(device3Config.getFailureCount()).toBe(3);
297
- expect(device1Config.shouldDelayAuth()).toBe(true);
298
- expect(device2Config.shouldDelayAuth()).toBe(true);
299
- expect(device3Config.shouldDelayAuth()).toBe(true);
300
- expect(device1Config.getAuthDelayMs()).toBe(2000);
301
- expect(device2Config.getAuthDelayMs()).toBe(2000);
302
- expect(device3Config.getAuthDelayMs()).toBe(2000);
303
- });
304
- });
305
- });
@@ -1 +0,0 @@
1
- export {};