@lanonasis/cli 1.4.2 → 1.5.0

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.
@@ -19,9 +19,10 @@ export function mcpCommands(program) {
19
19
  const config = new CLIConfig();
20
20
  const isAuthenticated = !!config.get('token');
21
21
  if (isAuthenticated) {
22
- console.log(chalk.green('✓ Authenticated - Using remote MCP mode'));
23
- console.log(' Your memory operations will use api.lanonasis.com');
24
- console.log(' with real-time SSE updates enabled');
22
+ console.log(chalk.green('✓ Authenticated - Using enterprise MCP modes'));
23
+ console.log(' SSE Mode: api.lanonasis.com (regular users)');
24
+ console.log(' WebSocket Mode: mcp.lanonasis.com (enterprise users)');
25
+ console.log(' with real-time updates enabled');
25
26
  }
26
27
  else {
27
28
  console.log(chalk.yellow('⚠️ Not authenticated - Using local MCP mode'));
@@ -30,7 +31,8 @@ export function mcpCommands(program) {
30
31
  console.log('');
31
32
  console.log(chalk.cyan('Available MCP Commands:'));
32
33
  console.log(' lanonasis mcp connect # Auto-connect to best mode');
33
- console.log(' lanonasis mcp connect -r # Force remote mode');
34
+ console.log(' lanonasis mcp connect -r # Force remote SSE mode');
35
+ console.log(' lanonasis mcp connect -w # Force WebSocket mode (enterprise)');
34
36
  console.log(' lanonasis mcp connect -l # Force local mode');
35
37
  console.log(' lanonasis mcp status # Check connection status');
36
38
  console.log(' lanonasis mcp tools # List available tools');
@@ -48,74 +50,79 @@ export function mcpCommands(program) {
48
50
  spinner.fail('Failed to auto-connect to MCP');
49
51
  }
50
52
  }
51
- catch {
53
+ catch (_error) {
52
54
  spinner.fail('MCP auto-connect failed');
53
55
  }
54
56
  });
55
57
  // Connect command
56
58
  mcp.command('connect')
57
- .description('Connect to MCP server (local, remote, or WebSocket)')
59
+ .description('Connect to MCP server (local, remote SSE, or WebSocket)')
58
60
  .option('-l, --local', 'Connect to local MCP server')
59
- .option('-r, --remote', 'Connect to remote MCP server (api.lanonasis.com)')
60
- .option('-w, --websocket', 'Connect using WebSocket mode for enterprise users')
61
+ .option('-r, --remote', 'Connect to remote SSE server (api.lanonasis.com)')
62
+ .option('-w, --websocket', 'Connect to WebSocket server (mcp.lanonasis.com) - Enterprise')
61
63
  .option('-s, --server <path>', 'Local MCP server path')
62
- .option('-u, --url <url>', 'Remote/WebSocket server URL')
64
+ .option('-u, --url <url>', 'Remote MCP server URL')
63
65
  .action(async (options) => {
64
66
  const spinner = ora('Connecting to MCP server...').start();
65
67
  const config = new CLIConfig();
66
68
  try {
67
- let connectionMode;
68
- // Determine connection mode - WebSocket takes precedence over remote and local
69
+ // Determine connection mode
70
+ let connectionMode = 'local';
69
71
  if (options.websocket) {
70
72
  connectionMode = 'websocket';
71
73
  }
72
74
  else if (options.remote) {
73
75
  connectionMode = 'remote';
74
76
  }
75
- else if (options.local) {
76
- connectionMode = 'local';
77
- }
78
- else {
79
- // Default to remote if authenticated, otherwise local
80
- connectionMode = !!config.get('token') ? 'remote' : 'local';
77
+ else if (!options.local && !options.remote && !options.websocket) {
78
+ // Auto-detect: WebSocket for enterprise, SSE for regular, local if not authenticated
79
+ const token = config.get('token');
80
+ if (token) {
81
+ // Check if enterprise user (simplified check)
82
+ connectionMode = 'remote'; // Default to SSE for now
83
+ }
81
84
  }
82
- // Save preferences
85
+ // Save preference
83
86
  config.set('mcpConnectionMode', connectionMode);
84
87
  if (options.server) {
85
88
  config.set('mcpServerPath', options.server);
86
89
  }
87
90
  if (options.url) {
88
- if (connectionMode === 'websocket') {
89
- config.set('mcpWebSocketUrl', options.url);
90
- }
91
- else {
92
- config.set('mcpServerUrl', options.url);
93
- }
91
+ config.set('mcpServerUrl', options.url);
94
92
  }
95
93
  const client = getMCPClient();
96
94
  const connected = await client.connect({
97
- connectionMode,
95
+ mode: connectionMode,
98
96
  serverPath: options.server,
99
97
  serverUrl: options.url
100
98
  });
101
99
  if (connected) {
102
- spinner.succeed(chalk.green(`Connected to MCP server in ${connectionMode} mode`));
100
+ const modeLabels = {
101
+ local: 'local',
102
+ remote: 'remote SSE',
103
+ websocket: 'WebSocket (Enterprise)'
104
+ };
105
+ spinner.succeed(chalk.green(`Connected to ${modeLabels[connectionMode]} MCP server`));
103
106
  if (connectionMode === 'remote') {
104
107
  console.log(chalk.cyan('ℹ️ Using remote MCP via api.lanonasis.com'));
105
108
  console.log(chalk.cyan('📡 SSE endpoint active for real-time updates'));
106
109
  }
107
110
  else if (connectionMode === 'websocket') {
108
- console.log(chalk.cyan('ℹ️ Using enterprise WebSocket MCP server'));
109
- console.log(chalk.cyan('📡 WebSocket connection active with auto-reconnect'));
111
+ console.log(chalk.cyan('🚀 Using enterprise WebSocket MCP via mcp.lanonasis.com'));
112
+ console.log(chalk.cyan(' Real-time WebSocket connection active'));
113
+ console.log(chalk.cyan('🏢 Enterprise features enabled'));
110
114
  }
111
115
  }
112
116
  else {
113
117
  spinner.fail('Failed to connect to MCP server');
118
+ if (connectionMode === 'websocket') {
119
+ console.log(chalk.yellow('💡 WebSocket mode requires enterprise access'));
120
+ console.log(chalk.yellow(' Try: lanonasis mcp connect -r (for SSE mode)'));
121
+ }
114
122
  }
115
123
  }
116
124
  catch (error) {
117
125
  spinner.fail(`Connection failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
118
- process.exit(1);
119
126
  }
120
127
  });
121
128
  // Disconnect command
@@ -215,7 +222,7 @@ export function mcpCommands(program) {
215
222
  try {
216
223
  args = JSON.parse(options.args);
217
224
  }
218
- catch {
225
+ catch (error) {
219
226
  spinner.fail('Invalid JSON arguments');
220
227
  process.exit(1);
221
228
  }
@@ -6,6 +6,8 @@ import wrap from 'word-wrap';
6
6
  import { format } from 'date-fns';
7
7
  import { apiClient } from '../utils/api.js';
8
8
  import { formatBytes, truncateText } from '../utils/formatting.js';
9
+ import { output } from '../utils/output.js';
10
+ // Using GetMemoriesParams from api.ts
9
11
  export function memoryCommands(program) {
10
12
  // Create memory
11
13
  program
@@ -21,7 +23,11 @@ export function memoryCommands(program) {
21
23
  .action(async (options) => {
22
24
  try {
23
25
  let { title, content, type, tags, topicId, interactive } = options;
24
- if (interactive || (!title || !content)) {
26
+ // Validate required fields in silent mode
27
+ if (output.isSilent() && (!title || !content)) {
28
+ throw new Error('Title and content are required when using --output json or --silent');
29
+ }
30
+ if ((interactive || (!title || !content)) && !output.isSilent()) {
25
31
  const answers = await inquirer.prompt([
26
32
  {
27
33
  type: 'input',
@@ -56,7 +62,7 @@ export function memoryCommands(program) {
56
62
  type = answers.type;
57
63
  tags = answers.tags;
58
64
  }
59
- const spinner = ora('Creating memory...').start();
65
+ const spinner = output.isSilent() ? null : ora('Creating memory...').start();
60
66
  const memoryData = {
61
67
  title,
62
68
  content,
@@ -69,19 +75,25 @@ export function memoryCommands(program) {
69
75
  memoryData.topic_id = topicId;
70
76
  }
71
77
  const memory = await apiClient.createMemory(memoryData);
72
- spinner.succeed('Memory created successfully');
73
- console.log();
74
- console.log(chalk.green('✓ Memory created:'));
75
- console.log(` ID: ${chalk.cyan(memory.id)}`);
76
- console.log(` Title: ${memory.title}`);
77
- console.log(` Type: ${memory.memory_type}`);
78
- if (memory.tags && memory.tags.length > 0) {
79
- console.log(` Tags: ${memory.tags.join(', ')}`);
78
+ if (spinner)
79
+ spinner.succeed('Memory created successfully');
80
+ if (output.isJsonOutput()) {
81
+ output.json(memory);
82
+ }
83
+ else {
84
+ console.log();
85
+ console.log(chalk.green(' Memory created:'));
86
+ console.log(` ID: ${chalk.cyan(memory.id)}`);
87
+ console.log(` Title: ${memory.title}`);
88
+ console.log(` Type: ${memory.memory_type}`);
89
+ if (memory.tags && memory.tags.length > 0) {
90
+ console.log(` Tags: ${memory.tags.join(', ')}`);
91
+ }
80
92
  }
81
93
  }
82
94
  catch (error) {
83
95
  const errorMessage = error instanceof Error ? error.message : 'Unknown error';
84
- console.error(chalk.red('✖ Failed to create memory:'), errorMessage);
96
+ output.error(chalk.red('✖ Failed to create memory:'), errorMessage);
85
97
  process.exit(1);
86
98
  }
87
99
  });
@@ -99,36 +111,41 @@ export function memoryCommands(program) {
99
111
  .option('--order <order>', 'sort order (asc, desc)', 'desc')
100
112
  .action(async (options) => {
101
113
  try {
102
- const spinner = ora('Fetching memories...').start();
114
+ const spinner = output.isSilent() ? null : ora('Fetching memories...').start();
103
115
  const params = {
104
- page: parseInt(options.page || '1'),
116
+ offset: (parseInt(options.page || '1') - 1) * parseInt(options.limit || '20'),
105
117
  limit: parseInt(options.limit || '20'),
106
- sort: options.sort || 'created_at',
107
- order: options.order || 'desc'
118
+ sort_by: (options.sort || 'created_at'),
119
+ sort_order: (options.order || 'desc')
108
120
  };
109
121
  if (options.type)
110
122
  params.memory_type = options.type;
111
123
  if (options.tags)
112
- params.tags = options.tags;
113
- if (options.userId)
114
- params.user_id = options.userId;
124
+ params.tags = options.tags.split(',').map(t => t.trim());
125
+ // Note: user_id filtering removed as it's handled by authentication
115
126
  const result = await apiClient.getMemories(params);
116
- spinner.stop();
117
- const memories = result.memories || result.data || [];
118
- if (memories.length === 0) {
119
- console.log(chalk.yellow('No memories found'));
127
+ if (spinner)
128
+ spinner.stop();
129
+ if (result.data.length === 0) {
130
+ if (output.isJsonOutput()) {
131
+ output.json({ data: [], pagination: result.pagination });
132
+ }
133
+ else {
134
+ console.log(chalk.yellow('No memories found'));
135
+ }
120
136
  return;
121
137
  }
122
- console.log(chalk.blue.bold(`\n📚 Memories (${result.pagination.total} total)`));
123
- console.log(chalk.gray(`Page ${result.pagination.page || 1} of ${result.pagination.pages || Math.ceil(result.pagination.total / result.pagination.limit)}`));
124
- console.log();
125
- const outputFormat = process.env.CLI_OUTPUT_FORMAT || 'table';
126
- if (outputFormat === 'json') {
127
- console.log(JSON.stringify(result, null, 2));
138
+ if (output.isJsonOutput()) {
139
+ output.json(result);
128
140
  }
129
141
  else {
142
+ console.log(chalk.blue.bold(`\n📚 Memories (${result.pagination.total} total)`));
143
+ const currentPage = Math.floor(result.pagination.offset / result.pagination.limit) + 1;
144
+ const totalPages = Math.ceil(result.pagination.total / result.pagination.limit);
145
+ console.log(chalk.gray(`Page ${currentPage} of ${totalPages}`));
146
+ console.log();
130
147
  // Table format
131
- const tableData = memories.map((memory) => [
148
+ const tableData = result.data.map((memory) => [
132
149
  truncateText(memory.title, 30),
133
150
  memory.memory_type,
134
151
  memory.tags.slice(0, 3).join(', '),
@@ -136,7 +153,6 @@ export function memoryCommands(program) {
136
153
  memory.access_count
137
154
  ]);
138
155
  const tableConfig = {
139
- header: ['Title', 'Type', 'Tags', 'Created', 'Access'],
140
156
  columnDefault: {
141
157
  width: 20,
142
158
  wrapWord: true
@@ -149,13 +165,12 @@ export function memoryCommands(program) {
149
165
  { width: 8 }
150
166
  ]
151
167
  };
152
- console.log(table([tableConfig.header, ...tableData], {
153
- columnDefault: tableConfig.columnDefault,
154
- columns: tableConfig.columns
155
- }));
168
+ const tableHeaders = ['Title', 'Type', 'Tags', 'Created', 'Access'];
169
+ console.log(table([tableHeaders, ...tableData], tableConfig));
156
170
  // Pagination info
157
- if (result.pagination.pages > 1) {
158
- console.log(chalk.gray(`\nUse --page ${result.pagination.page + 1} for next page`));
171
+ if (result.pagination.has_more) {
172
+ const nextPage = currentPage + 1;
173
+ console.log(chalk.gray(`\nUse --page ${nextPage} for next page`));
159
174
  }
160
175
  }
161
176
  }
@@ -176,7 +191,7 @@ export function memoryCommands(program) {
176
191
  .option('--tags <tags>', 'filter by tags (comma-separated)')
177
192
  .action(async (query, options) => {
178
193
  try {
179
- const spinner = ora(`Searching for "${query}"...`).start();
194
+ const spinner = output.isSilent() ? null : ora(`Searching for "${query}"...`).start();
180
195
  const searchOptions = {
181
196
  limit: parseInt(options.limit || '20'),
182
197
  threshold: parseFloat(options.threshold || '0.7')
@@ -188,25 +203,35 @@ export function memoryCommands(program) {
188
203
  searchOptions.tags = options.tags.split(',').map((t) => t.trim());
189
204
  }
190
205
  const result = await apiClient.searchMemories(query, searchOptions);
191
- spinner.stop();
192
- const results = result.results || result.data || [];
193
- if (results.length === 0) {
194
- console.log(chalk.yellow('No memories found matching your search'));
206
+ if (spinner)
207
+ spinner.stop();
208
+ if (result.data.length === 0) {
209
+ if (output.isJsonOutput()) {
210
+ output.json({ data: [], pagination: result.pagination, query });
211
+ }
212
+ else {
213
+ console.log(chalk.yellow('No memories found matching your search'));
214
+ }
195
215
  return;
196
216
  }
197
- console.log(chalk.blue.bold(`\n🔍 Search Results (${result.total_results || results.length} found)`));
198
- console.log(chalk.gray(`Query: "${query}" | Search time: ${result.search_time_ms || 0}ms`));
199
- console.log();
200
- results.forEach((memory, index) => {
201
- const score = (memory.relevance_score * 100).toFixed(1);
202
- console.log(chalk.green(`${index + 1}. ${memory.title}`) + chalk.gray(` (${score}% match)`));
203
- console.log(chalk.white(` ${truncateText(memory.content, 100)}`));
204
- console.log(chalk.cyan(` ID: ${memory.id}`) + chalk.gray(` | Type: ${memory.memory_type}`));
205
- if (memory.tags.length > 0) {
206
- console.log(chalk.yellow(` Tags: ${memory.tags.join(', ')}`));
207
- }
217
+ if (output.isJsonOutput()) {
218
+ output.json({ ...result, query });
219
+ }
220
+ else {
221
+ console.log(chalk.blue.bold(`\n🔍 Search Results (${result.pagination.total} found)`));
222
+ console.log(chalk.gray(`Query: "${query}"`));
208
223
  console.log();
209
- });
224
+ result.data.forEach((memory, index) => {
225
+ const score = (memory.relevance_score * 100).toFixed(1);
226
+ console.log(chalk.green(`${index + 1}. ${memory.title}`) + chalk.gray(` (${score}% match)`));
227
+ console.log(chalk.white(` ${truncateText(memory.content, 100)}`));
228
+ console.log(chalk.cyan(` ID: ${memory.id}`) + chalk.gray(` | Type: ${memory.memory_type}`));
229
+ if (memory.tags.length > 0) {
230
+ console.log(chalk.yellow(` Tags: ${memory.tags.join(', ')}`));
231
+ }
232
+ console.log();
233
+ });
234
+ }
210
235
  }
211
236
  catch (error) {
212
237
  const errorMessage = error instanceof Error ? error.message : 'Unknown error';