@lanonasis/cli 1.5.0 → 1.5.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 (37) hide show
  1. package/README.md +284 -586
  2. package/dist/commands/api-keys.d.ts +3 -0
  3. package/dist/commands/api-keys.js +812 -0
  4. package/dist/commands/auth.d.ts +2 -0
  5. package/dist/commands/auth.js +127 -138
  6. package/dist/commands/completion.d.ts +33 -0
  7. package/dist/commands/completion.js +378 -0
  8. package/dist/commands/guide.d.ts +19 -0
  9. package/dist/commands/guide.js +446 -0
  10. package/dist/commands/mcp.js +30 -37
  11. package/dist/commands/memory.js +53 -78
  12. package/dist/completions/bash-completion.sh +88 -0
  13. package/dist/completions/fish-completion.fish +132 -0
  14. package/dist/completions/zsh-completion.zsh +196 -0
  15. package/dist/index-simple.js +633 -183
  16. package/dist/index.js +327 -221
  17. package/dist/mcp-server.d.ts +38 -0
  18. package/dist/mcp-server.js +154 -0
  19. package/dist/utils/api.d.ts +12 -2
  20. package/dist/utils/api.js +38 -4
  21. package/dist/utils/config.d.ts +5 -2
  22. package/dist/utils/config.js +39 -15
  23. package/dist/utils/formatting.d.ts +2 -0
  24. package/dist/utils/formatting.js +13 -0
  25. package/dist/utils/mcp-client.d.ts +49 -6
  26. package/dist/utils/mcp-client.js +159 -82
  27. package/package.json +22 -12
  28. package/dist/utils/completions.d.ts +0 -28
  29. package/dist/utils/completions.js +0 -276
  30. package/dist/utils/mcp-client.test.d.ts +0 -1
  31. package/dist/utils/mcp-client.test.js +0 -125
  32. package/dist/utils/output.d.ts +0 -23
  33. package/dist/utils/output.js +0 -97
  34. package/dist/utils/websocket-mcp-client.d.ts +0 -60
  35. package/dist/utils/websocket-mcp-client.js +0 -182
  36. package/dist/utils/websocket-mcp-client.test.d.ts +0 -1
  37. package/dist/utils/websocket-mcp-client.test.js +0 -126
@@ -1,182 +0,0 @@
1
- /**
2
- * WebSocket MCP Client for Enterprise Connections
3
- * Connects to mcp.lanonasis.com WebSocket server for real-time MCP operations
4
- */
5
- import WebSocket from 'ws';
6
- import { EventEmitter } from 'events';
7
- import chalk from 'chalk';
8
- export class WebSocketMCPClient extends EventEmitter {
9
- ws = null;
10
- url;
11
- apiKey;
12
- reconnectInterval;
13
- maxReconnectAttempts;
14
- timeout;
15
- reconnectAttempts = 0;
16
- isConnected = false;
17
- messageId = 0;
18
- pendingRequests = new Map();
19
- constructor(options) {
20
- super();
21
- this.url = options.url || 'wss://mcp.lanonasis.com/mcp';
22
- this.apiKey = options.apiKey;
23
- this.reconnectInterval = options.reconnectInterval || 5000;
24
- this.maxReconnectAttempts = options.maxReconnectAttempts || 10;
25
- this.timeout = options.timeout || 30000;
26
- }
27
- async connect() {
28
- return new Promise((resolve, reject) => {
29
- try {
30
- this.ws = new WebSocket(this.url, {
31
- headers: {
32
- 'Authorization': `Bearer ${this.apiKey}`,
33
- 'X-API-Key': this.apiKey
34
- }
35
- });
36
- this.ws.on('open', () => {
37
- this.isConnected = true;
38
- this.reconnectAttempts = 0;
39
- this.emit('connected');
40
- // Send initialize message
41
- this.sendRequest('initialize', {
42
- protocolVersion: '2024-11-05',
43
- capabilities: {
44
- roots: { listChanged: true },
45
- sampling: {}
46
- },
47
- clientInfo: {
48
- name: '@lanonasis/cli',
49
- version: '1.2.0'
50
- }
51
- }).then(() => {
52
- resolve();
53
- }).catch(reject);
54
- });
55
- this.ws.on('message', (data) => {
56
- try {
57
- const message = JSON.parse(data.toString());
58
- this.handleMessage(message);
59
- }
60
- catch (error) {
61
- console.error(chalk.red('Failed to parse WebSocket message:'), error);
62
- }
63
- });
64
- this.ws.on('close', (code, reason) => {
65
- this.isConnected = false;
66
- this.emit('disconnected', { code, reason: reason.toString() });
67
- if (this.reconnectAttempts < this.maxReconnectAttempts) {
68
- this.reconnectAttempts++;
69
- console.log(chalk.yellow(`WebSocket disconnected. Reconnecting... (${this.reconnectAttempts}/${this.maxReconnectAttempts})`));
70
- setTimeout(() => this.connect(), this.reconnectInterval);
71
- }
72
- else {
73
- console.error(chalk.red('Max reconnection attempts reached. Connection failed.'));
74
- this.emit('error', new Error('Max reconnection attempts reached'));
75
- }
76
- });
77
- this.ws.on('error', (error) => {
78
- console.error('Failed to parse message:', error instanceof Error ? error.message : 'Unknown error');
79
- this.emit('error', error);
80
- reject(error);
81
- });
82
- // Connection timeout
83
- setTimeout(() => {
84
- if (!this.isConnected) {
85
- reject(new Error('WebSocket connection timeout'));
86
- }
87
- }, this.timeout);
88
- }
89
- catch (error) {
90
- reject(error);
91
- }
92
- });
93
- }
94
- handleMessage(message) {
95
- if (message.id && this.pendingRequests.has(message.id)) {
96
- const pending = this.pendingRequests.get(message.id);
97
- if (pending) {
98
- clearTimeout(pending.timeout);
99
- this.pendingRequests.delete(message.id);
100
- if (message.type === 'error' || message.error) {
101
- pending.reject(new Error(message.error?.message || 'Unknown error'));
102
- }
103
- else {
104
- pending.resolve(message.result);
105
- }
106
- }
107
- }
108
- else if (message.type === 'notification') {
109
- this.emit('notification', message);
110
- }
111
- }
112
- async sendRequest(method, params) {
113
- if (!this.isConnected) {
114
- throw new Error('WebSocket not connected');
115
- }
116
- return new Promise((resolve, reject) => {
117
- const id = `req_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
118
- const request = {
119
- id,
120
- type: 'request',
121
- method,
122
- params: params || {}
123
- };
124
- const timeout = setTimeout(() => {
125
- this.pendingRequests.delete(id);
126
- reject(new Error(`Request timeout: ${method}`));
127
- }, this.timeout);
128
- this.pendingRequests.set(id, { resolve, reject, timeout });
129
- if (this.ws?.readyState === WebSocket.OPEN) {
130
- this.ws.send(JSON.stringify(request));
131
- }
132
- else {
133
- this.pendingRequests.delete(id);
134
- clearTimeout(timeout);
135
- reject(new Error('WebSocket not connected'));
136
- }
137
- });
138
- }
139
- async listTools() {
140
- const result = await this.sendRequest('tools/list');
141
- return result;
142
- }
143
- async callTool(name, arguments_ = {}) {
144
- const result = await this.sendRequest('tools/call', { name, arguments: arguments_ });
145
- return result;
146
- }
147
- async deleteMemory(id) {
148
- return this.callTool('delete_memory', { id });
149
- }
150
- async searchMemories(args) {
151
- return this.callTool('search_memories', args);
152
- }
153
- async listResources() {
154
- const result = await this.sendRequest('resources/list');
155
- return result;
156
- }
157
- async getMemories(query) {
158
- const result = await this.sendRequest('resources/read', { uri: query });
159
- return result;
160
- }
161
- disconnect() {
162
- if (this.ws) {
163
- this.isConnected = false;
164
- this.ws.close();
165
- this.ws = null;
166
- }
167
- // Clear all pending requests
168
- for (const [, pending] of this.pendingRequests) {
169
- clearTimeout(pending.timeout);
170
- pending.reject(new Error('Connection closed'));
171
- }
172
- this.pendingRequests.clear();
173
- }
174
- getConnectionStatus() {
175
- return {
176
- connected: this.isConnected,
177
- url: this.url,
178
- reconnectAttempts: this.reconnectAttempts,
179
- pendingRequests: this.pendingRequests.size
180
- };
181
- }
182
- }
@@ -1 +0,0 @@
1
- export {};
@@ -1,126 +0,0 @@
1
- import { describe, it, expect, beforeEach, afterEach } from 'bun:test';
2
- import { WebSocketMCPClient } from './websocket-mcp-client';
3
- import WebSocket from 'ws';
4
- // Mock WebSocket for testing
5
- class MockWebSocket extends WebSocket {
6
- constructor(url) {
7
- super(url);
8
- // Override for testing
9
- }
10
- send(data) {
11
- // Mock send implementation
12
- this.emit('message', JSON.stringify({
13
- id: '1',
14
- type: 'response',
15
- result: { success: true }
16
- }));
17
- }
18
- }
19
- describe('WebSocketMCPClient', () => {
20
- let client;
21
- const mockOptions = {
22
- url: 'ws://localhost:8081',
23
- apiKey: 'test-api-key'
24
- };
25
- beforeEach(() => {
26
- client = new WebSocketMCPClient(mockOptions);
27
- });
28
- afterEach(() => {
29
- if (client) {
30
- client.disconnect();
31
- }
32
- });
33
- describe('constructor', () => {
34
- it('should create client with correct options', () => {
35
- expect(client).toBeDefined();
36
- expect(client.isConnected()).toBe(false);
37
- });
38
- it('should use default URL when not provided', () => {
39
- const clientWithDefaults = new WebSocketMCPClient({ apiKey: 'test' });
40
- expect(clientWithDefaults).toBeDefined();
41
- });
42
- });
43
- describe('connection management', () => {
44
- it('should report disconnected state initially', () => {
45
- expect(client.isConnected()).toBe(false);
46
- });
47
- it('should handle connection attempts', async () => {
48
- // Mock successful connection
49
- const connectPromise = client.connect();
50
- // Simulate connection success
51
- setTimeout(() => {
52
- client.emit('connected');
53
- }, 10);
54
- await expect(connectPromise).resolves.toBe(true);
55
- });
56
- it('should handle disconnection', () => {
57
- client.disconnect();
58
- expect(client.isConnected()).toBe(false);
59
- });
60
- });
61
- describe('message handling', () => {
62
- it('should handle MCP request/response cycle', async () => {
63
- // This would require more sophisticated mocking
64
- // For now, test basic message structure
65
- const message = {
66
- id: '1',
67
- type: 'request',
68
- method: 'test_method',
69
- params: { test: 'data' }
70
- };
71
- expect(message.type).toBe('request');
72
- expect(message.method).toBe('test_method');
73
- });
74
- it('should generate unique message IDs', () => {
75
- // Test ID generation logic
76
- const client1 = new WebSocketMCPClient(mockOptions);
77
- const client2 = new WebSocketMCPClient(mockOptions);
78
- // Both should start with different internal state
79
- expect(client1).not.toBe(client2);
80
- });
81
- });
82
- describe('error handling', () => {
83
- it('should handle connection errors gracefully', () => {
84
- const errorHandler = jest.fn();
85
- client.on('error', errorHandler);
86
- // Simulate error
87
- client.emit('error', new Error('Test error'));
88
- expect(errorHandler).toHaveBeenCalledWith(new Error('Test error'));
89
- });
90
- it('should handle malformed messages', () => {
91
- // Test error handling for invalid JSON
92
- expect(() => {
93
- JSON.parse('invalid json');
94
- }).toThrow();
95
- });
96
- });
97
- describe('MCP protocol compliance', () => {
98
- it('should create valid MCP message structure', () => {
99
- const message = {
100
- id: '123',
101
- type: 'request',
102
- method: 'memory/create',
103
- params: {
104
- title: 'Test Memory',
105
- content: 'Test content'
106
- }
107
- };
108
- expect(message).toHaveProperty('id');
109
- expect(message).toHaveProperty('type');
110
- expect(message).toHaveProperty('method');
111
- expect(message).toHaveProperty('params');
112
- });
113
- it('should handle MCP response format', () => {
114
- const response = {
115
- id: '123',
116
- type: 'response',
117
- result: {
118
- memory_id: 'mem_123',
119
- success: true
120
- }
121
- };
122
- expect(response.type).toBe('response');
123
- expect(response.result).toHaveProperty('success');
124
- });
125
- });
126
- });