@lanonasis/cli 3.9.2 → 3.9.4

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/CHANGELOG.md CHANGED
@@ -1,5 +1,34 @@
1
1
  # Changelog - @lanonasis/cli
2
2
 
3
+ ## [3.9.3] - 2026-02-02
4
+
5
+ ### ✨ Features
6
+
7
+ - **Non-Interactive Vendor Key Auth**: Added `-k, --vendor-key <key>` option to `auth login` command
8
+ - Enables non-interactive authentication in CI/CD pipelines and automation scripts
9
+ - Example: `onasis auth login --vendor-key <your-key>`
10
+
11
+ ### 🐛 Bug Fixes
12
+
13
+ - **JWT Authentication Routing**: Fixed API routing for JWT/OAuth authenticated sessions
14
+ - JWT tokens from username/password or OAuth login now correctly route to MCP server
15
+ - Memory operations (list, create, search, update, delete) work with JWT authentication
16
+ - Path translation handles endpoint differences between API and MCP servers
17
+ - Vendor key authentication continues to route to main API server
18
+
19
+ - **Frozen Terminal During Text Input**: Fixed SSE/WebSocket event handlers interfering with inline text editor
20
+ - Real-time update messages (📡) now only display in verbose mode
21
+ - Prevents terminal freeze during interactive prompts (memory create, update)
22
+ - Raw terminal mode no longer conflicts with background MCP events
23
+
24
+ - **Missing CLI Option**: The `--vendor-key` option was defined in code but not exposed in CLI
25
+ - Now properly registered in command-line interface
26
+
27
+ ### ⚠️ Known Limitations
28
+
29
+ - `memory stats` command not available with JWT authentication (MCP server limitation)
30
+ - For full API access including stats, use vendor key authentication
31
+
3
32
  ## [3.9.2] - 2026-02-02
4
33
 
5
34
  ### 🐛 Bug Fixes
package/README.md CHANGED
@@ -1,11 +1,11 @@
1
- # @lanonasis/cli v3.9.0 - Enterprise Security & Professional UX
1
+ # @lanonasis/cli v3.9.3 - Enterprise Security & Professional UX
2
2
 
3
3
  [![NPM Version](https://img.shields.io/npm/v/@lanonasis/cli)](https://www.npmjs.com/package/@lanonasis/cli)
4
4
  [![Downloads](https://img.shields.io/npm/dt/@lanonasis/cli)](https://www.npmjs.com/package/@lanonasis/cli)
5
5
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6
6
  [![Golden Contract](https://img.shields.io/badge/Onasis--Core-v0.1%20Compliant-gold)](https://api.lanonasis.com/.well-known/onasis.json)
7
7
 
8
- 🎉 **NEW IN v3.9**: Professional CLI UX with seamless inline text editing, intelligent MCP connection management, and first-run onboarding. Advanced Model Context Protocol (MCP) support with multi-server connections, enhanced error handling, and enterprise-grade transport protocols. Revolutionary interactive CLI experience with guided workflows and **Golden Contract compliance**.
8
+ 🎉 **NEW IN v3.9.3**: Fixed JWT authentication routing for username/password login, resolved frozen terminal during interactive input, and added non-interactive vendor key authentication (`-k` flag). Professional CLI UX with seamless inline text editing, intelligent MCP connection management, and first-run onboarding.
9
9
 
10
10
  ## 🚀 Quick Start
11
11
 
@@ -151,7 +151,11 @@ onasis login --vendor-key pk_xxxxx.sk_xxxxx // ✅ Automatically hashed
151
151
  Best for API integrations and automation. Copy the vendor key value exactly as shown in your LanOnasis dashboard (keys may vary in format):
152
152
 
153
153
  ```bash
154
- onasis login --vendor-key <your-vendor-key>
154
+ # Full option
155
+ onasis auth login --vendor-key <your-vendor-key>
156
+
157
+ # Short form (for scripts and CI/CD)
158
+ onasis auth login -k <your-vendor-key>
155
159
  ```
156
160
 
157
161
  ### 2. OAuth Browser Authentication
@@ -179,6 +183,13 @@ onasis auth status # Check current authentication
179
183
  onasis auth logout # Logout from current session
180
184
  ```
181
185
 
186
+ **Auth Login Options:**
187
+ | Short | Long | Description |
188
+ |-------|------|-------------|
189
+ | `-k` | `--vendor-key <key>` | Authenticate with vendor key (non-interactive) |
190
+ | `-e` | `--email <email>` | Email for credentials login |
191
+ | `-p` | `--password <pass>` | Password for credentials login |
192
+
182
193
  ## 💻 Shell Completions
183
194
 
184
195
  ### Installation Guide
@@ -224,24 +235,38 @@ onasis quickstart # Essential commands reference
224
235
 
225
236
  ```bash
226
237
  # List memories
227
- onasis memory list
228
- onasis memory list --memory-type context --limit 20 --sort-by created_at
238
+ onasis memory list # or: onasis memory ls
239
+ onasis memory list --type context --limit 20
240
+
241
+ # Create memories (non-interactive)
242
+ onasis memory create -t "Project Notes" -c "Important information"
243
+ onasis memory create -t "Reference" --type reference --tags "docs,api"
229
244
 
230
- # Create memories
231
- onasis memory create --title "Project Notes" --content "Important information"
232
- onasis memory create --title "Reference" --memory-type reference --tags "docs,api"
245
+ # Create memories (interactive)
246
+ onasis memory create -i # Interactive mode with inline editor
247
+ onasis memory create # Prompts for missing fields
233
248
 
234
249
  # Search memories
235
250
  onasis memory search "api integration"
236
- onasis memory search "meeting notes" --memory-types context,reference
251
+ onasis memory search "meeting notes" --type context
237
252
 
238
253
  # Memory operations
239
254
  onasis memory get <id> # Get specific memory
240
- onasis memory update <id> --title "New Title"
255
+ onasis memory update <id> -t "New Title" # Update title
256
+ onasis memory update <id> -i # Interactive update
241
257
  onasis memory delete <id> # Delete memory
242
258
  onasis memory stats # Memory statistics
243
259
  ```
244
260
 
261
+ **Create/Update Options:**
262
+ | Short | Long | Description |
263
+ |-------|------|-------------|
264
+ | `-t` | `--title` | Memory title |
265
+ | `-c` | `--content` | Memory content |
266
+ | `-i` | `--interactive` | Interactive mode |
267
+ | | `--type` | Memory type (context, project, knowledge, etc.) |
268
+ | | `--tags` | Comma-separated tags |
269
+
245
270
  ### Topic Management
246
271
 
247
272
  ```bash
package/dist/index.js CHANGED
@@ -221,6 +221,7 @@ authCmd
221
221
  .description('Login to your MaaS account')
222
222
  .option('-e, --email <email>', 'email address')
223
223
  .option('-p, --password <password>', 'password')
224
+ .option('-k, --vendor-key <key>', 'vendor key for API access')
224
225
  .action(loginCommand);
225
226
  authCmd
226
227
  .command('logout')
package/dist/utils/api.js CHANGED
@@ -15,19 +15,43 @@ export class APIClient {
15
15
  await this.config.init();
16
16
  // Service Discovery
17
17
  await this.config.discoverServices();
18
- // Use appropriate base URL based on endpoint
18
+ // Use appropriate base URL based on endpoint and auth method
19
19
  const isAuthEndpoint = config.url?.includes('/auth/') || config.url?.includes('/login') || config.url?.includes('/register') || config.url?.includes('/oauth/');
20
20
  const discoveredServices = this.config.get('discoveredServices');
21
- config.baseURL = isAuthEndpoint ?
22
- (discoveredServices?.auth_base || 'https://auth.lanonasis.com') :
23
- this.config.getApiUrl();
21
+ const authMethod = this.config.get('authMethod');
22
+ const vendorKey = await this.config.getVendorKeyAsync();
23
+ // Determine the correct API base URL:
24
+ // - Auth endpoints -> auth.lanonasis.com
25
+ // - JWT auth (no vendor key) -> mcp.lanonasis.com (supports JWT tokens)
26
+ // - Vendor key auth -> api.lanonasis.com (requires vendor key)
27
+ let apiBaseUrl;
28
+ const useMcpServer = !vendorKey && (authMethod === 'jwt' || authMethod === 'oauth' || authMethod === 'oauth2');
29
+ if (isAuthEndpoint) {
30
+ apiBaseUrl = discoveredServices?.auth_base || 'https://auth.lanonasis.com';
31
+ }
32
+ else if (vendorKey) {
33
+ // Vendor key works with api.lanonasis.com
34
+ apiBaseUrl = this.config.getApiUrl();
35
+ }
36
+ else if (useMcpServer) {
37
+ // JWT/OAuth tokens work with mcp.lanonasis.com
38
+ apiBaseUrl = 'https://mcp.lanonasis.com/api/v1';
39
+ }
40
+ else {
41
+ apiBaseUrl = this.config.getApiUrl();
42
+ }
43
+ config.baseURL = apiBaseUrl;
44
+ // Path translation for MCP server:
45
+ // MCP uses /memory (singular) while main API uses /memories (plural)
46
+ if (useMcpServer && config.url) {
47
+ config.url = config.url.replace(/\/api\/v1\/memories/g, '/memory');
48
+ }
24
49
  // Add project scope header for auth endpoints
25
50
  if (isAuthEndpoint) {
26
51
  config.headers['X-Project-Scope'] = 'lanonasis-maas';
27
52
  }
28
53
  // Enhanced Authentication Support
29
54
  const token = this.config.getToken();
30
- const vendorKey = await this.config.getVendorKeyAsync();
31
55
  if (vendorKey) {
32
56
  // Vendor key authentication (validated server-side)
33
57
  // Send raw key - server handles hashing for comparison
@@ -469,7 +469,10 @@ export class MCPClient {
469
469
  this.sseConnection.onmessage = (event) => {
470
470
  try {
471
471
  const data = JSON.parse(event.data);
472
- console.log(chalk.blue('📡 Real-time update:'), data.type);
472
+ // Only show SSE updates in verbose mode to avoid interfering with interactive prompts
473
+ if (process.env.CLI_VERBOSE === 'true') {
474
+ console.log(chalk.blue('📡 Real-time update:'), data.type);
475
+ }
473
476
  }
474
477
  catch {
475
478
  // Ignore parse errors
@@ -526,15 +529,20 @@ export class MCPClient {
526
529
  this.wsConnection.on('message', (data) => {
527
530
  try {
528
531
  const message = JSON.parse(data.toString());
529
- const messageId = message.id ?? 'event';
530
- const messageType = message.method
531
- || (message.error ? 'error' : undefined)
532
- || (message.result ? 'result' : undefined)
533
- || 'response';
534
- console.log(chalk.blue('📡 MCP message:'), messageId, messageType);
532
+ // Only show WebSocket messages in verbose mode to avoid interfering with interactive prompts
533
+ if (process.env.CLI_VERBOSE === 'true') {
534
+ const messageId = message.id ?? 'event';
535
+ const messageType = message.method
536
+ || (message.error ? 'error' : undefined)
537
+ || (message.result ? 'result' : undefined)
538
+ || 'response';
539
+ console.log(chalk.blue('📡 MCP message:'), messageId, messageType);
540
+ }
535
541
  }
536
542
  catch (error) {
537
- console.error('Failed to parse WebSocket message:', error);
543
+ if (process.env.CLI_VERBOSE === 'true') {
544
+ console.error('Failed to parse WebSocket message:', error);
545
+ }
538
546
  }
539
547
  });
540
548
  this.wsConnection.on('error', (error) => {
@@ -46,46 +46,113 @@ export class TextInputHandlerImpl {
46
46
  options: mergedOptions,
47
47
  status: 'active',
48
48
  };
49
- return new Promise((resolve, reject) => {
49
+ return new Promise(async (resolve, reject) => {
50
50
  let handleKeypress = null;
51
+ let sigintHandler = null;
51
52
  const cleanup = () => {
52
53
  if (handleKeypress) {
53
54
  process.stdin.removeListener('data', handleKeypress);
55
+ handleKeypress = null;
56
+ }
57
+ if (sigintHandler) {
58
+ process.removeListener('SIGINT', sigintHandler);
59
+ sigintHandler = null;
54
60
  }
55
61
  this.disableRawMode();
62
+ // Restore terminal state
63
+ process.stdout.write('\x1b[?25h'); // Show cursor
56
64
  };
65
+ // Set up completion handlers first
66
+ const complete = (result) => {
67
+ cleanup();
68
+ if (this.currentSession) {
69
+ this.currentSession.status = 'completed';
70
+ }
71
+ resolve(result);
72
+ };
73
+ const cancel = () => {
74
+ cleanup();
75
+ if (this.currentSession) {
76
+ this.currentSession.status = 'cancelled';
77
+ }
78
+ reject(new Error('Input cancelled by user'));
79
+ };
80
+ // Store handlers for special key processing
81
+ this._completeHandler = complete;
82
+ this._cancelHandler = cancel;
57
83
  try {
84
+ // Check if we can use raw mode
85
+ if (!process.stdin.isTTY) {
86
+ // Fall back to simple readline for non-TTY environments
87
+ console.log('\nNote: Interactive text input not available. Using simple input mode.');
88
+ console.log('Enter your text (empty line to finish):');
89
+ const readline = require('readline');
90
+ const rl = readline.createInterface({
91
+ input: process.stdin,
92
+ output: process.stdout
93
+ });
94
+ const lines = [];
95
+ rl.on('line', (line) => {
96
+ if (line === '') {
97
+ rl.close();
98
+ complete(lines.join('\n'));
99
+ }
100
+ else {
101
+ lines.push(line);
102
+ }
103
+ });
104
+ rl.on('close', () => {
105
+ complete(lines.join('\n'));
106
+ });
107
+ return;
108
+ }
109
+ // Add SIGINT handler as fallback for Ctrl+C
110
+ sigintHandler = () => {
111
+ cancel();
112
+ };
113
+ process.on('SIGINT', sigintHandler);
114
+ // Safety: Add a way to escape via triple-ESC (sends 3 escape chars quickly)
115
+ let escapeCount = 0;
116
+ let escapeTimer = null;
117
+ // Try to claim stdin from any previous handlers
118
+ process.stdin.removeAllListeners('data');
119
+ process.stdin.removeAllListeners('readable');
120
+ process.stdin.removeAllListeners('end');
58
121
  this.enableRawMode();
122
+ // Verify raw mode is working
123
+ if (!this.isRawModeEnabled) {
124
+ console.log('\nWarning: Could not enable raw mode. Falling back to editor mode.');
125
+ cleanup();
126
+ const { content } = await (await import('inquirer')).default.prompt([
127
+ { type: 'editor', name: 'content', message: prompt, default: mergedOptions.defaultContent }
128
+ ]);
129
+ resolve(content);
130
+ return;
131
+ }
59
132
  this.displayInputPrompt(this.getCurrentContent());
60
133
  handleKeypress = (chunk) => {
61
- const key = this.parseKeyEvent(chunk);
62
- if (this.handleSpecialKeys(key)) {
63
- return;
64
- }
65
- // Handle regular character input
66
- if (key.sequence && this.currentSession) {
67
- this.addCharacterToInput(key.sequence);
68
- this.displayInputPrompt(this.getCurrentContent());
134
+ try {
135
+ const key = this.parseKeyEvent(chunk);
136
+ if (this.handleSpecialKeys(key)) {
137
+ return;
138
+ }
139
+ // Handle regular character input
140
+ if (key.sequence && this.currentSession) {
141
+ // Filter out control characters that shouldn't be added as text
142
+ if (key.sequence.charCodeAt(0) >= 32 || key.sequence === '\t') {
143
+ this.addCharacterToInput(key.sequence);
144
+ this.displayInputPrompt(this.getCurrentContent());
145
+ }
146
+ }
69
147
  }
70
- };
71
- // Set up completion handlers
72
- const complete = (result) => {
73
- cleanup();
74
- if (this.currentSession) {
75
- this.currentSession.status = 'completed';
148
+ catch (err) {
149
+ // Don't let errors in key handling crash the input
150
+ console.error('Key handling error:', err);
76
151
  }
77
- resolve(result);
78
152
  };
79
- const cancel = () => {
80
- cleanup();
81
- if (this.currentSession) {
82
- this.currentSession.status = 'cancelled';
83
- }
84
- reject(new Error('Input cancelled by user'));
85
- };
86
- // Store handlers for special key processing
87
- this._completeHandler = complete;
88
- this._cancelHandler = cancel;
153
+ // Ensure stdin is flowing before adding listener
154
+ // This is critical after inquirer prompts which may pause stdin
155
+ process.stdin.resume();
89
156
  process.stdin.on('data', handleKeypress);
90
157
  }
91
158
  catch (error) {
@@ -101,8 +168,14 @@ export class TextInputHandlerImpl {
101
168
  if (!this.isRawModeEnabled && process.stdin.isTTY) {
102
169
  this.originalStdinMode = process.stdin.isRaw;
103
170
  process.stdin.setRawMode(true);
171
+ process.stdin.resume(); // Ensure stdin is flowing to receive data events
104
172
  this.isRawModeEnabled = true;
105
173
  }
174
+ else if (!process.stdin.isTTY) {
175
+ // Non-TTY mode - can't use raw mode, fall back to line mode
176
+ console.error('Warning: Not a TTY, inline text input may not work correctly');
177
+ process.stdin.resume();
178
+ }
106
179
  }
107
180
  /**
108
181
  * Disable raw mode and return to normal terminal behavior
@@ -112,6 +185,7 @@ export class TextInputHandlerImpl {
112
185
  process.stdin.setRawMode(this.originalStdinMode || false);
113
186
  this.isRawModeEnabled = false;
114
187
  }
188
+ // Don't pause stdin here as other handlers may need it
115
189
  }
116
190
  /**
117
191
  * Handle special keyboard events
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lanonasis/cli",
3
- "version": "3.9.2",
3
+ "version": "3.9.4",
4
4
  "description": "Professional CLI for LanOnasis Memory as a Service (MaaS) with MCP support, seamless inline editing, and enterprise-grade security",
5
5
  "keywords": [
6
6
  "lanonasis",