@lanonasis/cli 3.9.6 → 3.9.7
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 +34 -0
- package/README.md +20 -4
- package/dist/core/welcome.js +4 -4
- package/dist/index.js +117 -12
- package/dist/mcp/schemas/tool-schemas.d.ts +186 -538
- package/dist/mcp/schemas/tool-schemas.js +7 -7
- package/dist/utils/api.d.ts +24 -0
- package/dist/utils/api.js +21 -0
- package/dist/utils/config.d.ts +10 -1
- package/dist/utils/config.js +53 -16
- package/package.json +22 -22
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,39 @@
|
|
|
1
1
|
# Changelog - @lanonasis/cli
|
|
2
2
|
|
|
3
|
+
## [3.9.7] - 2026-02-21
|
|
4
|
+
|
|
5
|
+
### ✨ New Features
|
|
6
|
+
|
|
7
|
+
- **`onasis whoami` command**: Display full authenticated user profile including email, name, role, OAuth provider, project scope, and last login time. Fetches live data from `GET /v1/auth/me`.
|
|
8
|
+
- **Live profile on `auth status`**: `onasis auth status` now fetches the real user profile from the auth gateway and displays email, role, and plan — no longer relies solely on cached local state.
|
|
9
|
+
- **Live memory API probe on `auth status`**: After local auth check passes, `auth status` issues a real memory list request to confirm end-to-end API access, reporting `✓ accessible` or `✖ rejected (401)` with actionable guidance.
|
|
10
|
+
- **Manual endpoint override warning**: `auth status` now warns when `manualEndpointOverrides` is active and shows the configured endpoint URLs.
|
|
11
|
+
|
|
12
|
+
### 🐛 Bug Fixes
|
|
13
|
+
|
|
14
|
+
- **OAuth sessions no longer show "Not Authenticated"**: Fixed `auth status` incorrectly reporting unauthenticated for valid OAuth PKCE sessions — was checking `if (isAuth && user)` when `user` may be undefined for OAuth sessions.
|
|
15
|
+
- **`process.exit(1)` no longer kills status probe**: Added `noExit` flag to `APIClient` so callers like `auth status` can catch 401/403 from the memory probe without the interceptor terminating the process.
|
|
16
|
+
- **Stale auth cache cleared on 401**: When the memory API returns 401, the CLI now calls `invalidateAuthCache()` to clear the 5-minute in-memory cache and the persisted `lastValidated` timestamp, preventing the 24-hour grace bypass.
|
|
17
|
+
- **24-hour `lastValidated` skip removed**: Eliminated a security hole that bypassed server re-validation for 24 hours after any successful auth check.
|
|
18
|
+
- **7-day offline grace restricted to network errors**: The offline grace period no longer applies to explicit 401/403 auth rejections — only genuine network failures.
|
|
19
|
+
- **Bogus vendor key always passed auth check**: `pingAuthHealth()` was hitting the unauthenticated `/health` endpoint. Replaced with `probeVendorKeyAuth()` which calls `POST /api/v1/memories/search` — a real protected endpoint. Interprets 401/403 as auth rejection, any other response (400, 405, 5xx) as auth accepted with a backend concern.
|
|
20
|
+
- **`discoverServices()` overwrote manual overrides**: Fixed auto-discovery ignoring `manualEndpointOverrides`; discovery now short-circuits when manual overrides are active.
|
|
21
|
+
- **Stale JWT cleared on vendor key switch**: When `setVendorKey()` sets `authMethod: 'vendor_key'`, any existing JWT tokens are now removed from config to prevent auth-method confusion in the API client.
|
|
22
|
+
- **Zod v4 compatibility**: Fixed `z.record(z.any())` → `z.record(z.string(), z.any())` (5 instances in `tool-schemas.ts`) and `error.errors` → `error.issues` (2 instances in schema validator).
|
|
23
|
+
- **Inquirer v9 compatibility**: Fixed deprecated `type: 'list'` → `type: 'select'` prompt type in `welcome.ts`.
|
|
24
|
+
|
|
25
|
+
### 📡 Auth Gateway Integration (coordinated release)
|
|
26
|
+
|
|
27
|
+
These CLI changes are paired with server-side fixes in the same release:
|
|
28
|
+
- **Auth Gateway `requireAuth`**: Added opaque OAuth PKCE token introspection path — OAuth CLI sessions can now access `GET /v1/auth/me` and other protected endpoints.
|
|
29
|
+
- **Central API Gateway (`onasis-gateway`)**: `validateJWTToken()` now falls back to `POST /verify-token` when the session endpoint returns 401, enabling OAuth token passthrough for all proxied services. Added `get-me` tool to the auth-gateway MCP adapter.
|
|
30
|
+
|
|
31
|
+
### 📚 Documentation
|
|
32
|
+
|
|
33
|
+
- Updated README with `onasis whoami` command reference.
|
|
34
|
+
- Added `auth status` live probe behavior to authentication section.
|
|
35
|
+
- Added `--no-mcp` flag to memory command examples.
|
|
36
|
+
|
|
3
37
|
## [3.9.6] - 2026-02-21
|
|
4
38
|
|
|
5
39
|
### 🐛 Bug Fixes
|
package/README.md
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
# @lanonasis/cli v3.9.
|
|
1
|
+
# @lanonasis/cli v3.9.7 - OAuth PKCE Auth & whoami
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/@lanonasis/cli)
|
|
4
4
|
[](https://www.npmjs.com/package/@lanonasis/cli)
|
|
5
5
|
[](https://opensource.org/licenses/MIT)
|
|
6
6
|
[](https://api.lanonasis.com/.well-known/onasis.json)
|
|
7
7
|
|
|
8
|
-
🎉 **NEW IN v3.9.
|
|
8
|
+
🎉 **NEW IN v3.9.7**: Full OAuth PKCE session support across CLI and API gateway. New `onasis whoami` command. `auth status` now shows live user profile and probes real memory API access. Seven auth verification fixes eliminate false-positive "Authenticated: Yes" reports.
|
|
9
9
|
|
|
10
10
|
## 🚀 Quick Start
|
|
11
11
|
|
|
@@ -172,13 +172,28 @@ Traditional username/password authentication:
|
|
|
172
172
|
onasis login # Will prompt for email and password
|
|
173
173
|
```
|
|
174
174
|
|
|
175
|
-
### Authentication Status
|
|
175
|
+
### Authentication Status & Profile
|
|
176
176
|
|
|
177
177
|
```bash
|
|
178
|
-
onasis auth status # Check current authentication
|
|
178
|
+
onasis auth status # Check current authentication (probes live memory API access)
|
|
179
179
|
onasis auth logout # Logout from current session
|
|
180
|
+
onasis whoami # Display full authenticated user profile
|
|
180
181
|
```
|
|
181
182
|
|
|
183
|
+
`auth status` now performs a live end-to-end check:
|
|
184
|
+
1. Validates the local credential (vendor key probe hits a real protected endpoint, not `/health`)
|
|
185
|
+
2. Fetches and displays your user profile from `GET /v1/auth/me`
|
|
186
|
+
3. Issues a real memory list request to confirm API access is working
|
|
187
|
+
4. Warns if manual endpoint overrides are active
|
|
188
|
+
|
|
189
|
+
`onasis whoami` displays:
|
|
190
|
+
- Email address and display name
|
|
191
|
+
- Role (admin, user, authenticated)
|
|
192
|
+
- Plan tier (free, pro, enterprise)
|
|
193
|
+
- OAuth provider (if applicable)
|
|
194
|
+
- Project scope
|
|
195
|
+
- Last login time
|
|
196
|
+
|
|
182
197
|
**Auth Login Options:**
|
|
183
198
|
| Short | Long | Description |
|
|
184
199
|
|-------|------|-------------|
|
|
@@ -222,6 +237,7 @@ echo 'onasis --completion fish | source' >> ~/.config/fish/config.fish
|
|
|
222
237
|
```bash
|
|
223
238
|
onasis health # Comprehensive system health check
|
|
224
239
|
onasis status # Quick status overview
|
|
240
|
+
onasis whoami # Display authenticated user profile (email, role, plan, provider)
|
|
225
241
|
onasis init # Initialize CLI configuration
|
|
226
242
|
onasis guide # Interactive setup guide
|
|
227
243
|
onasis quickstart # Essential commands reference
|
package/dist/core/welcome.js
CHANGED
|
@@ -73,7 +73,7 @@ export class WelcomeExperience {
|
|
|
73
73
|
const choices = isAuthenticated ? existingUserOptions : newUserOptions;
|
|
74
74
|
const { choice } = await inquirer.prompt([
|
|
75
75
|
{
|
|
76
|
-
type: '
|
|
76
|
+
type: 'select',
|
|
77
77
|
name: 'choice',
|
|
78
78
|
message: isAuthenticated ?
|
|
79
79
|
'Welcome back! What would you like to do?' :
|
|
@@ -229,7 +229,7 @@ export class InteractiveSetup {
|
|
|
229
229
|
console.log("Let's connect to your Onasis service\n");
|
|
230
230
|
const { connectionType } = await inquirer.prompt([
|
|
231
231
|
{
|
|
232
|
-
type: '
|
|
232
|
+
type: 'select',
|
|
233
233
|
name: 'connectionType',
|
|
234
234
|
message: 'Where is your Onasis service hosted?',
|
|
235
235
|
choices: [
|
|
@@ -291,7 +291,7 @@ export class InteractiveSetup {
|
|
|
291
291
|
};
|
|
292
292
|
const { authMethod } = await inquirer.prompt([
|
|
293
293
|
{
|
|
294
|
-
type: '
|
|
294
|
+
type: 'select',
|
|
295
295
|
name: 'authMethod',
|
|
296
296
|
message: 'Select authentication method:',
|
|
297
297
|
choices: [
|
|
@@ -395,7 +395,7 @@ export class InteractiveSetup {
|
|
|
395
395
|
console.log("Let's personalize your experience\n");
|
|
396
396
|
const answers = await inquirer.prompt([
|
|
397
397
|
{
|
|
398
|
-
type: '
|
|
398
|
+
type: 'select',
|
|
399
399
|
name: 'outputFormat',
|
|
400
400
|
message: 'Preferred output format:',
|
|
401
401
|
choices: [
|
package/dist/index.js
CHANGED
|
@@ -11,6 +11,7 @@ import { orgCommands } from './commands/organization.js';
|
|
|
11
11
|
import { mcpCommands } from './commands/mcp.js';
|
|
12
12
|
import apiKeysCommand from './commands/api-keys.js';
|
|
13
13
|
import { CLIConfig } from './utils/config.js';
|
|
14
|
+
import { APIClient } from './utils/api.js';
|
|
14
15
|
import { getMCPClient } from './utils/mcp-client.js';
|
|
15
16
|
import { dirname, join } from 'path';
|
|
16
17
|
import { createOnboardingFlow } from './ux/index.js';
|
|
@@ -253,29 +254,77 @@ authCmd
|
|
|
253
254
|
.description('Show authentication status')
|
|
254
255
|
.action(async () => {
|
|
255
256
|
const isAuth = await cliConfig.isAuthenticated();
|
|
256
|
-
const user = await cliConfig.getCurrentUser();
|
|
257
257
|
const failureCount = cliConfig.getFailureCount();
|
|
258
258
|
const lastFailure = cliConfig.getLastAuthFailure();
|
|
259
259
|
const authMethod = cliConfig.get('authMethod');
|
|
260
260
|
const lastValidated = cliConfig.get('lastValidated');
|
|
261
261
|
console.log(chalk.blue.bold('🔐 Authentication Status'));
|
|
262
262
|
console.log('━'.repeat(40));
|
|
263
|
-
if (isAuth
|
|
263
|
+
if (isAuth) {
|
|
264
264
|
console.log(chalk.green('✓ Authenticated'));
|
|
265
|
-
console.log(`Email: ${user.email}`);
|
|
266
|
-
console.log(`Organization: ${user.organization_id}`);
|
|
267
|
-
console.log(`Plan: ${user.plan}`);
|
|
268
265
|
if (authMethod) {
|
|
269
266
|
console.log(`Method: ${authMethod}`);
|
|
270
267
|
}
|
|
271
268
|
if (lastValidated) {
|
|
272
|
-
|
|
273
|
-
|
|
269
|
+
console.log(`Last validated: ${new Date(lastValidated).toLocaleString()}`);
|
|
270
|
+
}
|
|
271
|
+
// Fetch live profile from auth gateway
|
|
272
|
+
try {
|
|
273
|
+
const profileClient = new APIClient();
|
|
274
|
+
profileClient.noExit = true;
|
|
275
|
+
const profile = await profileClient.getUserProfile();
|
|
276
|
+
console.log(`Email: ${profile.email}`);
|
|
277
|
+
if (profile.name)
|
|
278
|
+
console.log(`Name: ${profile.name}`);
|
|
279
|
+
console.log(`Role: ${profile.role}`);
|
|
280
|
+
if (profile.provider)
|
|
281
|
+
console.log(`Provider: ${profile.provider}`);
|
|
282
|
+
if (profile.last_sign_in_at) {
|
|
283
|
+
console.log(`Last sign-in: ${new Date(profile.last_sign_in_at).toLocaleString()}`);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
catch {
|
|
287
|
+
// Profile fetch failed (e.g. auth gateway offline) — show cached info if available
|
|
288
|
+
const cached = await cliConfig.getCurrentUser();
|
|
289
|
+
if (cached?.email)
|
|
290
|
+
console.log(`Email: ${cached.email} (cached)`);
|
|
274
291
|
}
|
|
275
292
|
}
|
|
276
293
|
else {
|
|
277
294
|
console.log(chalk.red('✖ Not authenticated'));
|
|
278
|
-
console.log(chalk.yellow('Run:'), chalk.white('
|
|
295
|
+
console.log(chalk.yellow('Run:'), chalk.white('lanonasis auth login'));
|
|
296
|
+
}
|
|
297
|
+
// Warn when manual endpoint overrides are active
|
|
298
|
+
if (cliConfig.hasManualEndpointOverrides()) {
|
|
299
|
+
console.log();
|
|
300
|
+
console.log(chalk.yellow('⚠️ Manual endpoint overrides are active (manualEndpointOverrides=true)'));
|
|
301
|
+
const services = cliConfig.get('discoveredServices');
|
|
302
|
+
if (services) {
|
|
303
|
+
console.log(chalk.gray(` auth: ${services['auth_base']}`));
|
|
304
|
+
console.log(chalk.gray(` memory: ${services['memory_base']}`));
|
|
305
|
+
}
|
|
306
|
+
console.log(chalk.gray(' Run: lanonasis config clear-overrides to restore auto-discovery'));
|
|
307
|
+
}
|
|
308
|
+
// Live memory API probe — shows whether credentials actually work end-to-end
|
|
309
|
+
if (isAuth) {
|
|
310
|
+
console.log();
|
|
311
|
+
process.stdout.write('Memory API access: ');
|
|
312
|
+
try {
|
|
313
|
+
const apiClient = new APIClient();
|
|
314
|
+
apiClient.noExit = true; // catch 401 in our try/catch below instead of process.exit
|
|
315
|
+
await apiClient.getMemories({ limit: 1 });
|
|
316
|
+
console.log(chalk.green('✓ accessible'));
|
|
317
|
+
}
|
|
318
|
+
catch (err) {
|
|
319
|
+
const status = err?.response?.status;
|
|
320
|
+
if (status === 401 || status === 403) {
|
|
321
|
+
console.log(chalk.red(`✖ rejected (${status}) — credentials are stale or revoked`));
|
|
322
|
+
console.log(chalk.yellow(' Run: lanonasis auth login'));
|
|
323
|
+
}
|
|
324
|
+
else {
|
|
325
|
+
console.log(chalk.yellow(`⚠ reachable (status: ${status ?? 'network error'})`));
|
|
326
|
+
}
|
|
327
|
+
}
|
|
279
328
|
}
|
|
280
329
|
// Show failure tracking information
|
|
281
330
|
if (failureCount > 0) {
|
|
@@ -645,16 +694,72 @@ program
|
|
|
645
694
|
console.log(`Verified via: ${verification.endpoint}`);
|
|
646
695
|
}
|
|
647
696
|
if (isAuth) {
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
697
|
+
try {
|
|
698
|
+
const profileClient = new APIClient();
|
|
699
|
+
profileClient.noExit = true;
|
|
700
|
+
const profile = await profileClient.getUserProfile();
|
|
701
|
+
console.log(`User: ${profile.email}`);
|
|
702
|
+
if (profile.name)
|
|
703
|
+
console.log(`Name: ${profile.name}`);
|
|
704
|
+
console.log(`Role: ${profile.role}`);
|
|
705
|
+
}
|
|
706
|
+
catch {
|
|
707
|
+
const cached = await cliConfig.getCurrentUser();
|
|
708
|
+
if (cached?.email)
|
|
709
|
+
console.log(`User: ${cached.email} (cached)`);
|
|
652
710
|
}
|
|
653
711
|
return;
|
|
654
712
|
}
|
|
655
713
|
console.log(chalk.yellow(`Auth check: ${verification.reason || 'Credential validation failed'}`));
|
|
656
714
|
console.log(chalk.yellow('Please run:'), chalk.white('lanonasis auth login'));
|
|
657
715
|
});
|
|
716
|
+
// Whoami command — live profile from auth gateway
|
|
717
|
+
program
|
|
718
|
+
.command('whoami')
|
|
719
|
+
.description('Show the currently authenticated user profile')
|
|
720
|
+
.action(async () => {
|
|
721
|
+
await cliConfig.init();
|
|
722
|
+
const isAuth = await cliConfig.isAuthenticated();
|
|
723
|
+
if (!isAuth) {
|
|
724
|
+
console.log(chalk.red('✖ Not authenticated'));
|
|
725
|
+
console.log(chalk.yellow('Run:'), chalk.white('lanonasis auth login'));
|
|
726
|
+
process.exit(1);
|
|
727
|
+
}
|
|
728
|
+
try {
|
|
729
|
+
const profileClient = new APIClient();
|
|
730
|
+
profileClient.noExit = true;
|
|
731
|
+
const profile = await profileClient.getUserProfile();
|
|
732
|
+
console.log(chalk.blue.bold('👤 Current User'));
|
|
733
|
+
console.log('━'.repeat(40));
|
|
734
|
+
console.log(`Email: ${chalk.white(profile.email)}`);
|
|
735
|
+
if (profile.name) {
|
|
736
|
+
console.log(`Name: ${chalk.white(profile.name)}`);
|
|
737
|
+
}
|
|
738
|
+
console.log(`Role: ${chalk.white(profile.role)}`);
|
|
739
|
+
if (profile.provider) {
|
|
740
|
+
console.log(`Provider: ${chalk.white(profile.provider)}`);
|
|
741
|
+
}
|
|
742
|
+
if (profile.project_scope) {
|
|
743
|
+
console.log(`Scope: ${chalk.white(profile.project_scope)}`);
|
|
744
|
+
}
|
|
745
|
+
if (profile.last_sign_in_at) {
|
|
746
|
+
console.log(`Last login: ${chalk.white(new Date(profile.last_sign_in_at).toLocaleString())}`);
|
|
747
|
+
}
|
|
748
|
+
if (profile.created_at) {
|
|
749
|
+
console.log(`Member since: ${chalk.white(new Date(profile.created_at).toLocaleString())}`);
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
catch (err) {
|
|
753
|
+
const status = err?.response?.status;
|
|
754
|
+
if (status === 401 || status === 403) {
|
|
755
|
+
console.log(chalk.red('✖ Session expired — please log in again'));
|
|
756
|
+
console.log(chalk.yellow('Run:'), chalk.white('lanonasis auth login'));
|
|
757
|
+
process.exit(1);
|
|
758
|
+
}
|
|
759
|
+
console.error(chalk.red('✖ Failed to fetch profile:'), err instanceof Error ? err.message : String(err));
|
|
760
|
+
process.exit(1);
|
|
761
|
+
}
|
|
762
|
+
});
|
|
658
763
|
// Health command using the healthCheck function
|
|
659
764
|
program
|
|
660
765
|
.command('health')
|