@lanonasis/cli 3.8.0 → 3.8.1
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/dist/commands/auth.js +1 -1
- package/dist/commands/config.js +3 -2
- package/dist/commands/mcp.js +23 -3
- package/dist/commands/memory.js +2 -2
- package/dist/mcp/access-control.js +2 -2
- package/dist/mcp/server/lanonasis-server.js +26 -3
- package/dist/utils/api.js +10 -10
- package/dist/utils/config.js +40 -6
- package/package.json +1 -1
package/dist/commands/auth.js
CHANGED
|
@@ -707,7 +707,7 @@ async function handleOAuthFlow(config) {
|
|
|
707
707
|
await config.setToken(tokens.access_token);
|
|
708
708
|
await config.set('refresh_token', tokens.refresh_token);
|
|
709
709
|
await config.set('token_expires_at', Date.now() + (tokens.expires_in * 1000));
|
|
710
|
-
await config.set('authMethod', '
|
|
710
|
+
await config.set('authMethod', 'oauth');
|
|
711
711
|
// The OAuth access token from auth-gateway works as the API token for all services
|
|
712
712
|
// Store it as the vendor key equivalent for MCP and API access
|
|
713
713
|
spinner.text = 'Configuring unified access...';
|
package/dist/commands/config.js
CHANGED
|
@@ -391,8 +391,9 @@ export function configCommands(program) {
|
|
|
391
391
|
else {
|
|
392
392
|
console.log(chalk.green(' ✓ Authentication credentials found'));
|
|
393
393
|
// Validate auth method consistency
|
|
394
|
-
|
|
395
|
-
|
|
394
|
+
// Note: OAuth users can have vendorKey stored (for MCP access) while authMethod is 'oauth'
|
|
395
|
+
if (vendorKey && authMethod !== 'vendor_key' && authMethod !== 'oauth') {
|
|
396
|
+
console.log(chalk.yellow(' ⚠ Auth method mismatch (has vendor key but method is not vendor_key or oauth)'));
|
|
396
397
|
validation.issues.push('Auth method mismatch');
|
|
397
398
|
if (options.repair) {
|
|
398
399
|
config.set('authMethod', 'vendor_key');
|
package/dist/commands/mcp.js
CHANGED
|
@@ -169,6 +169,7 @@ export function mcpCommands(program) {
|
|
|
169
169
|
const client = getMCPClient();
|
|
170
170
|
await client.disconnect();
|
|
171
171
|
console.log(chalk.green('✓ Disconnected from MCP server'));
|
|
172
|
+
process.exit(0);
|
|
172
173
|
});
|
|
173
174
|
// Status command
|
|
174
175
|
mcp.command('status')
|
|
@@ -183,6 +184,7 @@ export function mcpCommands(program) {
|
|
|
183
184
|
await config.init();
|
|
184
185
|
let healthLabel = chalk.gray('Unknown');
|
|
185
186
|
let healthDetails;
|
|
187
|
+
let isServiceReachable = false;
|
|
186
188
|
try {
|
|
187
189
|
const axios = (await import('axios')).default;
|
|
188
190
|
// Derive MCP health URL from discovered REST base (e.g. https://mcp.lanonasis.com/api/v1 -> https://mcp.lanonasis.com/health)
|
|
@@ -207,14 +209,17 @@ export function mcpCommands(program) {
|
|
|
207
209
|
const overallStatus = String(response.data?.status ?? '').toLowerCase();
|
|
208
210
|
const ok = response.status === 200 && (!overallStatus || overallStatus === 'healthy');
|
|
209
211
|
if (ok) {
|
|
210
|
-
healthLabel = chalk.green('
|
|
212
|
+
healthLabel = chalk.green('Healthy');
|
|
213
|
+
isServiceReachable = true;
|
|
211
214
|
}
|
|
212
215
|
else {
|
|
213
216
|
healthLabel = chalk.yellow('Degraded');
|
|
217
|
+
isServiceReachable = true; // Service is reachable but degraded
|
|
214
218
|
}
|
|
215
219
|
}
|
|
216
220
|
catch (error) {
|
|
217
221
|
healthLabel = chalk.red('Unreachable');
|
|
222
|
+
isServiceReachable = false;
|
|
218
223
|
if (error instanceof Error) {
|
|
219
224
|
healthDetails = error.message;
|
|
220
225
|
}
|
|
@@ -224,7 +229,14 @@ export function mcpCommands(program) {
|
|
|
224
229
|
}
|
|
225
230
|
console.log(chalk.cyan('\n📊 MCP Connection Status'));
|
|
226
231
|
console.log(chalk.cyan('========================'));
|
|
227
|
-
|
|
232
|
+
// Show status based on service reachability, not in-memory connection state
|
|
233
|
+
// The CLI isn't a persistent daemon - "connected" means the service is available
|
|
234
|
+
if (isServiceReachable) {
|
|
235
|
+
console.log(`Status: ${chalk.green('Ready')} (service reachable)`);
|
|
236
|
+
}
|
|
237
|
+
else {
|
|
238
|
+
console.log(`Status: ${chalk.red('Unavailable')} (service unreachable)`);
|
|
239
|
+
}
|
|
228
240
|
// Display mode with proper labels
|
|
229
241
|
let modeDisplay;
|
|
230
242
|
switch (status.mode) {
|
|
@@ -246,7 +258,8 @@ export function mcpCommands(program) {
|
|
|
246
258
|
if (healthDetails && process.env.CLI_VERBOSE === 'true') {
|
|
247
259
|
console.log(chalk.gray(`Health details: ${healthDetails}`));
|
|
248
260
|
}
|
|
249
|
-
|
|
261
|
+
// Show features when service is reachable
|
|
262
|
+
if (isServiceReachable) {
|
|
250
263
|
if (status.mode === 'remote') {
|
|
251
264
|
console.log(`\n${chalk.cyan('Features:')}`);
|
|
252
265
|
console.log('• Real-time updates via SSE');
|
|
@@ -259,7 +272,12 @@ export function mcpCommands(program) {
|
|
|
259
272
|
console.log('• Authenticated WebSocket connection');
|
|
260
273
|
console.log('• Production-ready MCP server');
|
|
261
274
|
}
|
|
275
|
+
console.log(chalk.green('\n✓ MCP tools are available. Run "lanonasis mcp tools" to see them.'));
|
|
276
|
+
}
|
|
277
|
+
else {
|
|
278
|
+
console.log(chalk.yellow('\n⚠ MCP service is not reachable. Run "lanonasis mcp diagnose" for troubleshooting.'));
|
|
262
279
|
}
|
|
280
|
+
process.exit(0);
|
|
263
281
|
});
|
|
264
282
|
// List tools command
|
|
265
283
|
mcp.command('tools')
|
|
@@ -456,6 +474,7 @@ export function mcpCommands(program) {
|
|
|
456
474
|
console.log(' --prefer-local : Use local stdio mode (development only)');
|
|
457
475
|
console.log(' --auto : Auto-detect based on configuration (default)');
|
|
458
476
|
}
|
|
477
|
+
process.exit(0);
|
|
459
478
|
});
|
|
460
479
|
// Start MCP server for external clients
|
|
461
480
|
mcp.command('start')
|
|
@@ -790,5 +809,6 @@ export function mcpCommands(program) {
|
|
|
790
809
|
console.log(chalk.gray(' • Verify your network allows outbound HTTPS connections'));
|
|
791
810
|
console.log(chalk.gray(' • Contact support if issues persist'));
|
|
792
811
|
}
|
|
812
|
+
process.exit(0);
|
|
793
813
|
});
|
|
794
814
|
}
|
package/dist/commands/memory.js
CHANGED
|
@@ -31,9 +31,9 @@ export function memoryCommands(program) {
|
|
|
31
31
|
validate: (input) => input.length > 0 || 'Title is required'
|
|
32
32
|
},
|
|
33
33
|
{
|
|
34
|
-
type: '
|
|
34
|
+
type: 'input',
|
|
35
35
|
name: 'content',
|
|
36
|
-
message: 'Memory content:',
|
|
36
|
+
message: 'Memory content (or use -c flag for multi-line):',
|
|
37
37
|
default: content,
|
|
38
38
|
validate: (input) => input.length > 0 || 'Content is required'
|
|
39
39
|
},
|
|
@@ -192,7 +192,7 @@ export class MemoryAccessControl {
|
|
|
192
192
|
const apiUrl = this.config.get('apiUrl') || 'https://api.lanonasis.com';
|
|
193
193
|
const token = this.config.get('token');
|
|
194
194
|
const axios = (await import('axios')).default;
|
|
195
|
-
const response = await axios.get(`${apiUrl}/api/v1/
|
|
195
|
+
const response = await axios.get(`${apiUrl}/api/v1/memories/${memoryId}`, {
|
|
196
196
|
headers: {
|
|
197
197
|
'Authorization': `Bearer ${token}`,
|
|
198
198
|
'Content-Type': 'application/json'
|
|
@@ -210,7 +210,7 @@ export class MemoryAccessControl {
|
|
|
210
210
|
const apiUrl = this.config.get('apiUrl') || 'https://api.lanonasis.com';
|
|
211
211
|
const token = this.config.get('token');
|
|
212
212
|
const axios = (await import('axios')).default;
|
|
213
|
-
const response = await axios.get(`${apiUrl}/api/v1/
|
|
213
|
+
const response = await axios.get(`${apiUrl}/api/v1/memories?user_id=${userId}`, {
|
|
214
214
|
headers: {
|
|
215
215
|
'Authorization': `Bearer ${token}`,
|
|
216
216
|
'Content-Type': 'application/json'
|
|
@@ -407,7 +407,15 @@ export class LanonasisMCPServer {
|
|
|
407
407
|
text: `Authentication Error: ${error instanceof Error ? error.message : 'Authentication failed'}`
|
|
408
408
|
}
|
|
409
409
|
],
|
|
410
|
-
isError: true
|
|
410
|
+
isError: true,
|
|
411
|
+
task: {
|
|
412
|
+
taskId: `${clientId}-${Date.now()}`,
|
|
413
|
+
status: 'failed',
|
|
414
|
+
ttl: null,
|
|
415
|
+
createdAt: new Date().toISOString(),
|
|
416
|
+
lastUpdatedAt: new Date().toISOString(),
|
|
417
|
+
statusMessage: 'Authentication failed'
|
|
418
|
+
}
|
|
411
419
|
};
|
|
412
420
|
}
|
|
413
421
|
this.updateConnectionActivity(clientId);
|
|
@@ -419,7 +427,14 @@ export class LanonasisMCPServer {
|
|
|
419
427
|
type: 'text',
|
|
420
428
|
text: JSON.stringify(result, null, 2)
|
|
421
429
|
}
|
|
422
|
-
]
|
|
430
|
+
],
|
|
431
|
+
task: {
|
|
432
|
+
taskId: `${clientId}-${Date.now()}`,
|
|
433
|
+
status: 'completed',
|
|
434
|
+
ttl: null,
|
|
435
|
+
createdAt: new Date().toISOString(),
|
|
436
|
+
lastUpdatedAt: new Date().toISOString()
|
|
437
|
+
}
|
|
423
438
|
};
|
|
424
439
|
}
|
|
425
440
|
catch (error) {
|
|
@@ -430,7 +445,15 @@ export class LanonasisMCPServer {
|
|
|
430
445
|
text: `Error: ${error instanceof Error ? error.message : 'Unknown error'}`
|
|
431
446
|
}
|
|
432
447
|
],
|
|
433
|
-
isError: true
|
|
448
|
+
isError: true,
|
|
449
|
+
task: {
|
|
450
|
+
taskId: `${clientId}-${Date.now()}`,
|
|
451
|
+
status: 'failed',
|
|
452
|
+
ttl: null,
|
|
453
|
+
createdAt: new Date().toISOString(),
|
|
454
|
+
lastUpdatedAt: new Date().toISOString(),
|
|
455
|
+
statusMessage: error instanceof Error ? error.message : 'Unknown error'
|
|
456
|
+
}
|
|
434
457
|
};
|
|
435
458
|
}
|
|
436
459
|
});
|
package/dist/utils/api.js
CHANGED
|
@@ -99,40 +99,40 @@ export class APIClient {
|
|
|
99
99
|
});
|
|
100
100
|
return response.data;
|
|
101
101
|
}
|
|
102
|
-
// Memory operations - aligned with
|
|
103
|
-
// All memory endpoints use /api/v1/
|
|
102
|
+
// Memory operations - aligned with REST API canonical endpoints
|
|
103
|
+
// All memory endpoints use /api/v1/memories path (plural, per REST conventions)
|
|
104
104
|
async createMemory(data) {
|
|
105
|
-
const response = await this.client.post('/api/v1/
|
|
105
|
+
const response = await this.client.post('/api/v1/memories', data);
|
|
106
106
|
return response.data;
|
|
107
107
|
}
|
|
108
108
|
async getMemories(params = {}) {
|
|
109
|
-
const response = await this.client.get('/api/v1/
|
|
109
|
+
const response = await this.client.get('/api/v1/memories', { params });
|
|
110
110
|
return response.data;
|
|
111
111
|
}
|
|
112
112
|
async getMemory(id) {
|
|
113
|
-
const response = await this.client.get(`/api/v1/
|
|
113
|
+
const response = await this.client.get(`/api/v1/memories/${id}`);
|
|
114
114
|
return response.data;
|
|
115
115
|
}
|
|
116
116
|
async updateMemory(id, data) {
|
|
117
|
-
const response = await this.client.put(`/api/v1/
|
|
117
|
+
const response = await this.client.put(`/api/v1/memories/${id}`, data);
|
|
118
118
|
return response.data;
|
|
119
119
|
}
|
|
120
120
|
async deleteMemory(id) {
|
|
121
|
-
await this.client.delete(`/api/v1/
|
|
121
|
+
await this.client.delete(`/api/v1/memories/${id}`);
|
|
122
122
|
}
|
|
123
123
|
async searchMemories(query, options = {}) {
|
|
124
|
-
const response = await this.client.post('/api/v1/
|
|
124
|
+
const response = await this.client.post('/api/v1/memories/search', {
|
|
125
125
|
query,
|
|
126
126
|
...options
|
|
127
127
|
});
|
|
128
128
|
return response.data;
|
|
129
129
|
}
|
|
130
130
|
async getMemoryStats() {
|
|
131
|
-
const response = await this.client.get('/api/v1/
|
|
131
|
+
const response = await this.client.get('/api/v1/memories/stats');
|
|
132
132
|
return response.data;
|
|
133
133
|
}
|
|
134
134
|
async bulkDeleteMemories(memoryIds) {
|
|
135
|
-
const response = await this.client.post('/api/v1/
|
|
135
|
+
const response = await this.client.post('/api/v1/memories/bulk/delete', {
|
|
136
136
|
memory_ids: memoryIds
|
|
137
137
|
});
|
|
138
138
|
return response.data;
|
package/dist/utils/config.js
CHANGED
|
@@ -499,7 +499,11 @@ export class CLIConfig {
|
|
|
499
499
|
}
|
|
500
500
|
// Store a reference marker in config (not the actual key)
|
|
501
501
|
this.config.vendorKey = 'stored_in_api_key_storage';
|
|
502
|
-
|
|
502
|
+
// Only set authMethod to 'vendor_key' if not already set to OAuth
|
|
503
|
+
// This prevents overwriting OAuth auth method when storing the token for MCP access
|
|
504
|
+
if (!this.config.authMethod || !['oauth', 'oauth2', 'jwt'].includes(this.config.authMethod)) {
|
|
505
|
+
this.config.authMethod = 'vendor_key';
|
|
506
|
+
}
|
|
503
507
|
this.config.lastValidated = new Date().toISOString();
|
|
504
508
|
await this.resetFailureCount(); // Reset failure count on successful auth
|
|
505
509
|
await this.save();
|
|
@@ -692,11 +696,41 @@ export class CLIConfig {
|
|
|
692
696
|
this.authCheckCache = { isValid: true, timestamp: Date.now() };
|
|
693
697
|
return true;
|
|
694
698
|
}
|
|
695
|
-
//
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
699
|
+
// Vendor key not recently validated - verify with server
|
|
700
|
+
try {
|
|
701
|
+
await this.discoverServices();
|
|
702
|
+
const authBase = this.config.discoveredServices?.auth_base || 'https://auth.lanonasis.com';
|
|
703
|
+
// Ping auth health with vendor key to verify it's still valid
|
|
704
|
+
await this.pingAuthHealth(axios, authBase, {
|
|
705
|
+
'X-API-Key': vendorKey,
|
|
706
|
+
'X-Auth-Method': 'vendor_key',
|
|
707
|
+
'X-Project-Scope': 'lanonasis-maas'
|
|
708
|
+
}, { timeout: 5000, proxy: false });
|
|
709
|
+
// Update last validated timestamp on success
|
|
710
|
+
this.config.lastValidated = new Date().toISOString();
|
|
711
|
+
await this.save().catch(() => { }); // Don't fail auth check if save fails
|
|
712
|
+
this.authCheckCache = { isValid: true, timestamp: Date.now() };
|
|
713
|
+
return true;
|
|
714
|
+
}
|
|
715
|
+
catch (error) {
|
|
716
|
+
// Server validation failed - check for grace period (7 days offline)
|
|
717
|
+
const gracePeriod = 7 * 24 * 60 * 60 * 1000;
|
|
718
|
+
const withinGracePeriod = lastValidated &&
|
|
719
|
+
(Date.now() - new Date(lastValidated).getTime()) < gracePeriod;
|
|
720
|
+
if (withinGracePeriod) {
|
|
721
|
+
if (process.env.CLI_VERBOSE === 'true') {
|
|
722
|
+
console.warn('⚠️ Unable to validate vendor key with server, using cached validation');
|
|
723
|
+
}
|
|
724
|
+
this.authCheckCache = { isValid: true, timestamp: Date.now() };
|
|
725
|
+
return true;
|
|
726
|
+
}
|
|
727
|
+
// Grace period expired - require server validation
|
|
728
|
+
if (process.env.CLI_VERBOSE === 'true') {
|
|
729
|
+
console.warn('⚠️ Vendor key validation failed and grace period expired');
|
|
730
|
+
}
|
|
731
|
+
this.authCheckCache = { isValid: false, timestamp: Date.now() };
|
|
732
|
+
return false;
|
|
733
|
+
}
|
|
700
734
|
}
|
|
701
735
|
// Handle token-based authentication
|
|
702
736
|
const token = this.getToken();
|