@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,6 +1,8 @@
1
1
  interface LoginOptions {
2
2
  email?: string;
3
3
  password?: string;
4
+ vendorKey?: string;
5
+ useWebAuth?: boolean;
4
6
  }
5
7
  export declare function loginCommand(options: LoginOptions): Promise<void>;
6
8
  export {};
@@ -1,41 +1,152 @@
1
1
  import chalk from 'chalk';
2
2
  import inquirer from 'inquirer';
3
3
  import ora from 'ora';
4
- import { createServer } from 'http';
5
- import { URL } from 'url';
6
4
  import open from 'open';
7
5
  import { apiClient } from '../utils/api.js';
8
6
  import { CLIConfig } from '../utils/config.js';
7
+ // Color scheme
8
+ const colors = {
9
+ primary: chalk.blue.bold,
10
+ success: chalk.green,
11
+ warning: chalk.yellow,
12
+ error: chalk.red,
13
+ info: chalk.cyan,
14
+ accent: chalk.magenta,
15
+ muted: chalk.gray,
16
+ highlight: chalk.white.bold
17
+ };
9
18
  export async function loginCommand(options) {
10
19
  const config = new CLIConfig();
11
20
  await config.init();
12
- console.log(chalk.blue.bold('🔐 Login to Lanonasis Core Gateway'));
21
+ console.log(chalk.blue.bold('🔐 Onasis-Core Golden Contract Authentication'));
22
+ console.log(colors.info('━'.repeat(50)));
13
23
  console.log();
14
- // Check if API key is provided via environment or option
15
- const apiKey = process.env.LANONASIS_API_KEY;
16
- if (apiKey) {
17
- console.log(chalk.green('✓ Using API key authentication'));
18
- await config.setApiKey(apiKey);
19
- console.log(chalk.green('✓ Authentication configured successfully'));
24
+ // Enhanced authentication flow - check for vendor key first
25
+ if (options.vendorKey) {
26
+ await handleVendorKeyAuth(options.vendorKey, config);
20
27
  return;
21
28
  }
22
- // Choose authentication method
23
- const authMethod = await inquirer.prompt([
29
+ // Show authentication options
30
+ const authChoice = await inquirer.prompt([
24
31
  {
25
32
  type: 'list',
26
33
  name: 'method',
27
34
  message: 'Choose authentication method:',
28
35
  choices: [
29
- { name: '🔑 Username/Password (direct login)', value: 'password' },
30
- { name: '🌐 Web Browser (OAuth providers)', value: 'oauth' }
36
+ {
37
+ name: '🔑 Vendor Key (Recommended for API access)',
38
+ value: 'vendor'
39
+ },
40
+ {
41
+ name: '🌐 Web OAuth (Browser-based)',
42
+ value: 'oauth'
43
+ },
44
+ {
45
+ name: '⚙️ Username/Password (Direct credentials)',
46
+ value: 'credentials'
47
+ }
31
48
  ]
32
49
  }
33
50
  ]);
34
- if (authMethod.method === 'oauth') {
35
- await oauthLoginFlow(config);
51
+ switch (authChoice.method) {
52
+ case 'vendor':
53
+ await handleVendorKeyFlow(config);
54
+ break;
55
+ case 'oauth':
56
+ await handleOAuthFlow(config);
57
+ break;
58
+ case 'credentials':
59
+ await handleCredentialsFlow(options, config);
60
+ break;
61
+ }
62
+ }
63
+ async function handleVendorKeyAuth(vendorKey, config) {
64
+ const spinner = ora('Validating vendor key...').start();
65
+ try {
66
+ await config.setVendorKey(vendorKey);
67
+ // Test the vendor key with a health check
68
+ const response = await apiClient.get('/health');
69
+ spinner.succeed('Vendor key authentication successful');
70
+ console.log();
71
+ console.log(chalk.green('✓ Authenticated with vendor key'));
72
+ console.log(colors.info('Ready to use Onasis-Core services'));
73
+ }
74
+ catch (error) {
75
+ spinner.fail('Vendor key validation failed');
76
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
77
+ console.error(chalk.red('✖ Invalid vendor key:'), errorMessage);
78
+ process.exit(1);
79
+ }
80
+ }
81
+ async function handleVendorKeyFlow(config) {
82
+ console.log();
83
+ console.log(chalk.yellow('🔑 Vendor Key Authentication'));
84
+ console.log(chalk.gray('Vendor keys provide secure API access with format: pk_xxx.sk_xxx'));
85
+ console.log();
86
+ const { vendorKey } = await inquirer.prompt([
87
+ {
88
+ type: 'password',
89
+ name: 'vendorKey',
90
+ message: 'Enter your vendor key (pk_xxx.sk_xxx):',
91
+ mask: '*',
92
+ validate: (input) => {
93
+ if (!input)
94
+ return 'Vendor key is required';
95
+ if (!input.match(/^pk_[a-zA-Z0-9]+\.sk_[a-zA-Z0-9]+$/)) {
96
+ return 'Invalid format. Expected: pk_xxx.sk_xxx';
97
+ }
98
+ return true;
99
+ }
100
+ }
101
+ ]);
102
+ await handleVendorKeyAuth(vendorKey, config);
103
+ }
104
+ async function handleOAuthFlow(config) {
105
+ console.log();
106
+ console.log(chalk.yellow('🌐 Web OAuth Authentication'));
107
+ console.log(chalk.gray('This will open your browser for secure authentication'));
108
+ console.log();
109
+ const { proceed } = await inquirer.prompt([
110
+ {
111
+ type: 'confirm',
112
+ name: 'proceed',
113
+ message: 'Open browser for authentication?',
114
+ default: true
115
+ }
116
+ ]);
117
+ if (!proceed) {
118
+ console.log(chalk.yellow('Authentication cancelled'));
36
119
  return;
37
120
  }
38
- // Password-based login flow
121
+ const authUrl = `${config.getDiscoveredApiUrl()}/auth/cli-login`;
122
+ try {
123
+ console.log(colors.info('Opening browser...'));
124
+ await open(authUrl);
125
+ console.log();
126
+ console.log(colors.info('Please complete authentication in your browser'));
127
+ console.log(colors.muted(`If browser doesn't open, visit: ${authUrl}`));
128
+ // TODO: Implement OAuth callback handling or polling mechanism
129
+ const { token } = await inquirer.prompt([
130
+ {
131
+ type: 'input',
132
+ name: 'token',
133
+ message: 'Paste the authentication token from browser:'
134
+ }
135
+ ]);
136
+ if (token) {
137
+ await config.setToken(token);
138
+ console.log(chalk.green('✓ OAuth authentication successful'));
139
+ }
140
+ }
141
+ catch (error) {
142
+ console.error(chalk.red('✖ Failed to open browser'));
143
+ console.log(colors.muted(`Please visit manually: ${authUrl}`));
144
+ }
145
+ }
146
+ async function handleCredentialsFlow(options, config) {
147
+ console.log();
148
+ console.log(chalk.yellow('⚙️ Username/Password Authentication'));
149
+ console.log();
39
150
  let { email, password } = options;
40
151
  // Get credentials if not provided
41
152
  if (!email || !password) {
@@ -159,125 +270,3 @@ async function registerFlow(defaultEmail) {
159
270
  process.exit(1);
160
271
  }
161
272
  }
162
- async function oauthLoginFlow(config) {
163
- console.log(chalk.blue('🌐 OAuth Authentication'));
164
- console.log(chalk.gray('This will open your browser for secure authentication'));
165
- console.log();
166
- const port = 3721; // CLI callback port
167
- const redirectUri = `http://localhost:${port}/callback`;
168
- const state = Math.random().toString(36).substring(2, 15);
169
- // Construct OAuth URL
170
- const authUrl = new URL('https://api.lanonasis.com/v1/auth/oauth');
171
- authUrl.searchParams.set('redirect_uri', redirectUri);
172
- authUrl.searchParams.set('state', state);
173
- authUrl.searchParams.set('project_scope', 'maas');
174
- authUrl.searchParams.set('response_type', 'code');
175
- const spinner = ora('Starting OAuth flow...').start();
176
- try {
177
- // Start local callback server
178
- const server = createServer();
179
- let authCode = null;
180
- let authError = null;
181
- server.on('request', (req, res) => {
182
- const url = new URL(req.url, `http://localhost:${port}`);
183
- if (url.pathname === '/callback') {
184
- const code = url.searchParams.get('code');
185
- const error = url.searchParams.get('error');
186
- const returnedState = url.searchParams.get('state');
187
- // Validate state parameter
188
- if (returnedState !== state) {
189
- authError = 'Invalid state parameter';
190
- res.writeHead(400, { 'Content-Type': 'text/html' });
191
- res.end('<h1>Authentication Failed</h1><p>Invalid state parameter</p>');
192
- return;
193
- }
194
- if (error) {
195
- authError = url.searchParams.get('error_description') || error;
196
- res.writeHead(400, { 'Content-Type': 'text/html' });
197
- res.end(`<h1>Authentication Failed</h1><p>${authError}</p>`);
198
- }
199
- else if (code) {
200
- authCode = code;
201
- res.writeHead(200, { 'Content-Type': 'text/html' });
202
- res.end('<h1>Authentication Successful</h1><p>You can close this window and return to the CLI.</p>');
203
- }
204
- else {
205
- authError = 'No authorization code received';
206
- res.writeHead(400, { 'Content-Type': 'text/html' });
207
- res.end('<h1>Authentication Failed</h1><p>No authorization code received</p>');
208
- }
209
- server.close();
210
- }
211
- });
212
- // Start server
213
- await new Promise((resolve, reject) => {
214
- server.listen(port, (err) => {
215
- if (err)
216
- reject(err);
217
- else
218
- resolve();
219
- });
220
- });
221
- spinner.text = 'Opening browser for authentication...';
222
- // Open browser
223
- await open(authUrl.toString());
224
- console.log();
225
- console.log(chalk.yellow('Browser opened for authentication'));
226
- console.log(chalk.gray(`If browser doesn't open, visit: ${authUrl.toString()}`));
227
- console.log();
228
- spinner.text = 'Waiting for authentication...';
229
- // Wait for callback
230
- await new Promise((resolve, reject) => {
231
- server.on('close', () => {
232
- if (authCode)
233
- resolve();
234
- else
235
- reject(new Error(authError || 'Authentication failed'));
236
- });
237
- // Timeout after 5 minutes
238
- setTimeout(() => {
239
- server.close();
240
- reject(new Error('Authentication timeout'));
241
- }, 300000);
242
- });
243
- if (!authCode) {
244
- throw new Error(authError || 'No authorization code received');
245
- }
246
- spinner.text = 'Exchanging authorization code for session...';
247
- // Exchange code for session
248
- const response = await fetch('https://api.lanonasis.com/v1/auth/callback', {
249
- method: 'POST',
250
- headers: {
251
- 'Content-Type': 'application/json',
252
- 'x-project-scope': 'maas'
253
- },
254
- body: JSON.stringify({
255
- code: authCode,
256
- state: state,
257
- project_scope: 'maas'
258
- }),
259
- credentials: 'include'
260
- });
261
- if (!response.ok) {
262
- const errorData = await response.json().catch(() => ({ error: 'Unknown error' }));
263
- throw new Error(errorData.error || `HTTP ${response.status}`);
264
- }
265
- const sessionData = await response.json();
266
- // Store session token
267
- await config.setToken(sessionData.access_token);
268
- spinner.succeed('OAuth authentication successful');
269
- console.log();
270
- console.log(chalk.green('✓ Authenticated successfully via OAuth'));
271
- console.log(`Welcome, ${sessionData.user.email}!`);
272
- if (sessionData.user.organization_id) {
273
- console.log(`Organization: ${sessionData.user.organization_id}`);
274
- }
275
- console.log(`Plan: ${sessionData.user.plan || 'free'}`);
276
- }
277
- catch (error) {
278
- spinner.fail('OAuth authentication failed');
279
- const errorMessage = error instanceof Error ? error.message : 'Unknown error';
280
- console.error(chalk.red('✖ OAuth failed:'), errorMessage);
281
- process.exit(1);
282
- }
283
- }
@@ -0,0 +1,33 @@
1
+ export interface CompletionData {
2
+ commands: Array<{
3
+ name: string;
4
+ description: string;
5
+ aliases?: string[];
6
+ subcommands?: Array<{
7
+ name: string;
8
+ description: string;
9
+ options?: Array<{
10
+ name: string;
11
+ description: string;
12
+ type: 'string' | 'boolean' | 'number' | 'choice';
13
+ choices?: string[];
14
+ required?: boolean;
15
+ }>;
16
+ }>;
17
+ }>;
18
+ globalOptions: Array<{
19
+ name: string;
20
+ description: string;
21
+ type: 'string' | 'boolean' | 'number' | 'choice';
22
+ choices?: string[];
23
+ }>;
24
+ contextualData: {
25
+ memoryTypes: string[];
26
+ outputFormats: string[];
27
+ sortOptions: string[];
28
+ authMethods: string[];
29
+ };
30
+ }
31
+ export declare function generateCompletionData(): Promise<CompletionData>;
32
+ export declare function completionCommand(): Promise<void>;
33
+ export declare function installCompletionsCommand(): Promise<void>;