berget 2.2.7 → 2.2.9
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/.github/workflows/publish.yml +6 -6
- package/.github/workflows/test.yml +1 -1
- package/.prettierrc +5 -3
- package/dist/index.js +24 -25
- package/dist/package.json +7 -3
- package/dist/src/agents/app.js +8 -8
- package/dist/src/agents/backend.js +3 -3
- package/dist/src/agents/devops.js +8 -8
- package/dist/src/agents/frontend.js +3 -3
- package/dist/src/agents/fullstack.js +3 -3
- package/dist/src/agents/index.js +18 -18
- package/dist/src/agents/quality.js +8 -8
- package/dist/src/agents/security.js +8 -8
- package/dist/src/client.js +115 -127
- package/dist/src/commands/api-keys.js +181 -202
- package/dist/src/commands/auth.js +16 -25
- package/dist/src/commands/autocomplete.js +8 -8
- package/dist/src/commands/billing.js +10 -19
- package/dist/src/commands/chat.js +139 -170
- package/dist/src/commands/clusters.js +21 -30
- package/dist/src/commands/code/__tests__/auth-sync.test.js +189 -186
- package/dist/src/commands/code/__tests__/fake-api-key-service.js +3 -13
- package/dist/src/commands/code/__tests__/fake-auth-service.js +21 -29
- package/dist/src/commands/code/__tests__/fake-command-runner.js +22 -33
- package/dist/src/commands/code/__tests__/fake-file-store.js +19 -41
- package/dist/src/commands/code/__tests__/fake-prompter.js +81 -97
- package/dist/src/commands/code/__tests__/setup-flow.test.js +295 -295
- package/dist/src/commands/code/adapters/clack-prompter.js +15 -32
- package/dist/src/commands/code/adapters/fs-file-store.js +25 -44
- package/dist/src/commands/code/adapters/spawn-command-runner.js +27 -41
- package/dist/src/commands/code/auth-sync.js +215 -228
- package/dist/src/commands/code/errors.js +15 -12
- package/dist/src/commands/code/setup.js +390 -425
- package/dist/src/commands/code.js +279 -294
- package/dist/src/commands/index.js +5 -5
- package/dist/src/commands/models.js +16 -25
- package/dist/src/commands/users.js +9 -18
- package/dist/src/constants/command-structure.js +138 -138
- package/dist/src/services/api-key-service.js +132 -152
- package/dist/src/services/auth-service.js +81 -95
- package/dist/src/services/browser-auth.js +121 -131
- package/dist/src/services/chat-service.js +369 -386
- package/dist/src/services/cluster-service.js +47 -62
- package/dist/src/services/collaborator-service.js +9 -21
- package/dist/src/services/flux-service.js +13 -25
- package/dist/src/services/helm-service.js +9 -21
- package/dist/src/services/kubectl-service.js +15 -29
- package/dist/src/utils/config-checker.js +8 -8
- package/dist/src/utils/config-loader.js +109 -109
- package/dist/src/utils/default-api-key.js +129 -139
- package/dist/src/utils/env-manager.js +55 -66
- package/dist/src/utils/error-handler.js +62 -62
- package/dist/src/utils/logger.js +74 -67
- package/dist/src/utils/markdown-renderer.js +28 -28
- package/dist/src/utils/opencode-validator.js +67 -69
- package/dist/src/utils/token-manager.js +67 -65
- package/dist/tests/commands/chat.test.js +30 -39
- package/dist/tests/commands/code.test.js +186 -195
- package/dist/tests/utils/config-loader.test.js +107 -107
- package/dist/tests/utils/env-manager.test.js +81 -90
- package/dist/tests/utils/opencode-validator.test.js +42 -41
- package/dist/vitest.config.js +1 -1
- package/eslint.config.mjs +65 -30
- package/index.ts +30 -31
- package/package.json +7 -3
- package/src/agents/app.ts +9 -9
- package/src/agents/backend.ts +4 -4
- package/src/agents/devops.ts +9 -9
- package/src/agents/frontend.ts +4 -4
- package/src/agents/fullstack.ts +4 -4
- package/src/agents/index.ts +27 -25
- package/src/agents/quality.ts +9 -9
- package/src/agents/security.ts +9 -9
- package/src/agents/types.ts +10 -10
- package/src/client.ts +85 -77
- package/src/commands/api-keys.ts +180 -185
- package/src/commands/auth.ts +15 -14
- package/src/commands/autocomplete.ts +10 -10
- package/src/commands/billing.ts +13 -12
- package/src/commands/chat.ts +145 -142
- package/src/commands/clusters.ts +20 -19
- package/src/commands/code/__tests__/auth-sync.test.ts +176 -175
- package/src/commands/code/__tests__/fake-api-key-service.ts +2 -2
- package/src/commands/code/__tests__/fake-auth-service.ts +18 -18
- package/src/commands/code/__tests__/fake-command-runner.ts +28 -22
- package/src/commands/code/__tests__/fake-file-store.ts +15 -15
- package/src/commands/code/__tests__/fake-prompter.ts +86 -85
- package/src/commands/code/__tests__/setup-flow.test.ts +253 -251
- package/src/commands/code/adapters/clack-prompter.ts +32 -30
- package/src/commands/code/adapters/fs-file-store.ts +18 -17
- package/src/commands/code/adapters/spawn-command-runner.ts +20 -15
- package/src/commands/code/auth-sync.ts +210 -210
- package/src/commands/code/errors.ts +11 -11
- package/src/commands/code/ports/auth-services.ts +7 -7
- package/src/commands/code/ports/command-runner.ts +2 -2
- package/src/commands/code/ports/file-store.ts +3 -3
- package/src/commands/code/ports/prompter.ts +13 -13
- package/src/commands/code/setup.ts +408 -406
- package/src/commands/code.ts +288 -287
- package/src/commands/index.ts +11 -10
- package/src/commands/models.ts +19 -18
- package/src/commands/users.ts +11 -10
- package/src/constants/command-structure.ts +159 -159
- package/src/services/api-key-service.ts +85 -85
- package/src/services/auth-service.ts +55 -54
- package/src/services/browser-auth.ts +62 -62
- package/src/services/chat-service.ts +170 -171
- package/src/services/cluster-service.ts +28 -28
- package/src/services/collaborator-service.ts +6 -6
- package/src/services/flux-service.ts +17 -17
- package/src/services/helm-service.ts +11 -11
- package/src/services/kubectl-service.ts +12 -12
- package/src/types/api.d.ts +1933 -1933
- package/src/types/json.d.ts +1 -1
- package/src/utils/config-checker.ts +7 -7
- package/src/utils/config-loader.ts +130 -129
- package/src/utils/default-api-key.ts +81 -80
- package/src/utils/env-manager.ts +37 -37
- package/src/utils/error-handler.ts +64 -64
- package/src/utils/logger.ts +72 -66
- package/src/utils/markdown-renderer.ts +28 -28
- package/src/utils/opencode-validator.ts +72 -71
- package/src/utils/token-manager.ts +69 -68
- package/tests/commands/chat.test.ts +32 -31
- package/tests/commands/code.test.ts +182 -181
- package/tests/utils/config-loader.test.ts +111 -110
- package/tests/utils/env-manager.test.ts +83 -79
- package/tests/utils/opencode-validator.test.ts +43 -42
- package/tsconfig.json +2 -1
- package/vitest.config.ts +2 -2
|
@@ -1,29 +1,29 @@
|
|
|
1
|
-
import { createAuthenticatedClient } from
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { createAuthenticatedClient } from '../client';
|
|
2
|
+
import { COMMAND_GROUPS, SUBCOMMANDS } from '../constants/command-structure';
|
|
3
|
+
import { handleError } from '../utils/error-handler';
|
|
4
4
|
|
|
5
5
|
export interface ApiKey {
|
|
6
|
+
active: boolean;
|
|
7
|
+
created: string;
|
|
8
|
+
description: null | string;
|
|
6
9
|
id: number;
|
|
10
|
+
lastUsed: null | string;
|
|
11
|
+
modified: string;
|
|
7
12
|
name: string;
|
|
8
|
-
description: string | null;
|
|
9
|
-
created: string;
|
|
10
|
-
lastUsed: string | null;
|
|
11
13
|
prefix: string;
|
|
12
|
-
active: boolean;
|
|
13
|
-
modified: string;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
export interface
|
|
16
|
+
export interface ApiKeyResponse {
|
|
17
|
+
created: string;
|
|
18
|
+
description: null | string;
|
|
19
|
+
id: number;
|
|
20
|
+
key: string;
|
|
17
21
|
name: string;
|
|
18
|
-
description?: string;
|
|
19
22
|
}
|
|
20
23
|
|
|
21
|
-
export interface
|
|
22
|
-
|
|
24
|
+
export interface CreateApiKeyOptions {
|
|
25
|
+
description?: string;
|
|
23
26
|
name: string;
|
|
24
|
-
description: string | null;
|
|
25
|
-
key: string;
|
|
26
|
-
created: string;
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
/**
|
|
@@ -31,15 +31,15 @@ export interface ApiKeyResponse {
|
|
|
31
31
|
* Command group: api-keys
|
|
32
32
|
*/
|
|
33
33
|
export class ApiKeyService {
|
|
34
|
-
private static instance: ApiKeyService;
|
|
35
|
-
private client = createAuthenticatedClient();
|
|
36
|
-
|
|
37
34
|
// Command group name for this service
|
|
38
35
|
public static readonly COMMAND_GROUP = COMMAND_GROUPS.API_KEYS;
|
|
39
|
-
|
|
40
36
|
// Subcommands for this service
|
|
41
37
|
public static readonly COMMANDS = SUBCOMMANDS.API_KEYS;
|
|
42
38
|
|
|
39
|
+
private static instance: ApiKeyService;
|
|
40
|
+
|
|
41
|
+
private client = createAuthenticatedClient();
|
|
42
|
+
|
|
43
43
|
private constructor() {}
|
|
44
44
|
|
|
45
45
|
public static getInstance(): ApiKeyService {
|
|
@@ -49,21 +49,6 @@ export class ApiKeyService {
|
|
|
49
49
|
return ApiKeyService.instance;
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
/**
|
|
53
|
-
* List all API keys
|
|
54
|
-
* Command: berget api-keys list
|
|
55
|
-
*/
|
|
56
|
-
public async list(): Promise<ApiKey[]> {
|
|
57
|
-
try {
|
|
58
|
-
const { data, error } = await this.client.GET("/v1/api-keys");
|
|
59
|
-
if (error) throw error;
|
|
60
|
-
return data || [];
|
|
61
|
-
} catch (error) {
|
|
62
|
-
handleError("Failed to list API keys", error);
|
|
63
|
-
throw error;
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
52
|
/**
|
|
68
53
|
* Create a new API key
|
|
69
54
|
* Command: berget api-keys create
|
|
@@ -72,18 +57,18 @@ export class ApiKeyService {
|
|
|
72
57
|
try {
|
|
73
58
|
// Validate input before sending request
|
|
74
59
|
if (!options.name || options.name.trim().length === 0) {
|
|
75
|
-
throw new Error(
|
|
60
|
+
throw new Error('API key name is required and cannot be empty');
|
|
76
61
|
}
|
|
77
62
|
|
|
78
63
|
if (options.name.length > 100) {
|
|
79
|
-
throw new Error(
|
|
64
|
+
throw new Error('API key name must be 100 characters or less');
|
|
80
65
|
}
|
|
81
66
|
|
|
82
67
|
if (options.description && options.description.length > 500) {
|
|
83
|
-
throw new Error(
|
|
68
|
+
throw new Error('API key description must be 500 characters or less');
|
|
84
69
|
}
|
|
85
70
|
|
|
86
|
-
const { data, error } = await this.client.POST(
|
|
71
|
+
const { data, error } = await this.client.POST('/v1/api-keys', {
|
|
87
72
|
body: options,
|
|
88
73
|
});
|
|
89
74
|
|
|
@@ -91,46 +76,46 @@ export class ApiKeyService {
|
|
|
91
76
|
// Enhanced error handling with specific troubleshooting
|
|
92
77
|
|
|
93
78
|
// Handle specific error cases
|
|
94
|
-
if (typeof error ===
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
if (
|
|
98
|
-
let detailedMessage =
|
|
99
|
-
detailedMessage +=
|
|
100
|
-
detailedMessage +=
|
|
101
|
-
detailedMessage +=
|
|
102
|
-
detailedMessage +=
|
|
103
|
-
detailedMessage +=
|
|
104
|
-
detailedMessage +=
|
|
105
|
-
detailedMessage +=
|
|
106
|
-
detailedMessage +=
|
|
107
|
-
detailedMessage +=
|
|
108
|
-
detailedMessage +=
|
|
79
|
+
if (typeof error === 'object' && error !== null) {
|
|
80
|
+
const errorObject = error as any;
|
|
81
|
+
|
|
82
|
+
if (errorObject.error?.code === 'API_KEY_CREATION_FAILED') {
|
|
83
|
+
let detailedMessage = 'Failed to create API key. This could be due to:\n';
|
|
84
|
+
detailedMessage += '• Account limits or quota restrictions\n';
|
|
85
|
+
detailedMessage += '• Insufficient permissions for API key creation\n';
|
|
86
|
+
detailedMessage += '• Temporary server issues\n';
|
|
87
|
+
detailedMessage += '• Billing or subscription issues\n\n';
|
|
88
|
+
detailedMessage += 'Troubleshooting steps:\n';
|
|
89
|
+
detailedMessage += '1. Check if you have reached your API key limit\n';
|
|
90
|
+
detailedMessage += '2. Verify your account has API key creation permissions\n';
|
|
91
|
+
detailedMessage += '3. Check your billing status and subscription\n';
|
|
92
|
+
detailedMessage += '4. Try again in a few minutes if this is a temporary issue\n';
|
|
93
|
+
detailedMessage += '5. Contact support if the problem persists';
|
|
109
94
|
|
|
110
95
|
throw new Error(detailedMessage);
|
|
111
96
|
}
|
|
112
97
|
|
|
113
|
-
if (
|
|
98
|
+
if (errorObject.error?.code === 'USER_NOT_FOUND') {
|
|
114
99
|
throw new Error(
|
|
115
|
-
|
|
100
|
+
'Your account is still being set up. Please wait a moment and try again.\n\nIf this issue persists, please contact support at support@berget.ai',
|
|
116
101
|
);
|
|
117
102
|
}
|
|
118
103
|
|
|
119
|
-
if (
|
|
104
|
+
if (errorObject.error?.code === 'QUOTA_EXCEEDED') {
|
|
120
105
|
throw new Error(
|
|
121
|
-
|
|
106
|
+
'You have reached your API key limit. Please delete existing keys or contact support to increase your quota.',
|
|
122
107
|
);
|
|
123
108
|
}
|
|
124
109
|
|
|
125
|
-
if (
|
|
110
|
+
if (errorObject.error?.code === 'INSUFFICIENT_PERMISSIONS') {
|
|
126
111
|
throw new Error(
|
|
127
|
-
|
|
112
|
+
'Your account does not have permission to create API keys. Please contact your administrator.',
|
|
128
113
|
);
|
|
129
114
|
}
|
|
130
115
|
|
|
131
|
-
if (
|
|
116
|
+
if (errorObject.error?.code === 'BILLING_REQUIRED') {
|
|
132
117
|
throw new Error(
|
|
133
|
-
|
|
118
|
+
'A valid billing method is required to create API keys. Please add a payment method.',
|
|
134
119
|
);
|
|
135
120
|
}
|
|
136
121
|
}
|
|
@@ -139,30 +124,30 @@ export class ApiKeyService {
|
|
|
139
124
|
}
|
|
140
125
|
|
|
141
126
|
if (!data) {
|
|
142
|
-
throw new Error(
|
|
127
|
+
throw new Error('No data received from server');
|
|
143
128
|
}
|
|
144
129
|
|
|
145
130
|
return data;
|
|
146
131
|
} catch (error) {
|
|
147
|
-
console.error(
|
|
132
|
+
console.error('Failed to create API key:', error);
|
|
148
133
|
|
|
149
134
|
// Add additional context for common issues
|
|
150
135
|
if (error instanceof Error) {
|
|
151
|
-
if (error.message.includes(
|
|
152
|
-
throw new Error(
|
|
136
|
+
if (error.message.includes('ECONNREFUSED')) {
|
|
137
|
+
throw new Error('Cannot connect to Berget API. Please check your internet connection.');
|
|
153
138
|
}
|
|
154
139
|
|
|
155
|
-
if (error.message.includes(
|
|
156
|
-
throw new Error(
|
|
140
|
+
if (error.message.includes('ENOTFOUND')) {
|
|
141
|
+
throw new Error('Cannot resolve Berget API hostname. Please check your DNS settings.');
|
|
157
142
|
}
|
|
158
143
|
|
|
159
|
-
if (error.message.includes(
|
|
160
|
-
throw new Error(
|
|
144
|
+
if (error.message.includes('401') || error.message.includes('Unauthorized')) {
|
|
145
|
+
throw new Error('Authentication failed. Please run `berget auth login` to log in again.');
|
|
161
146
|
}
|
|
162
147
|
|
|
163
|
-
if (error.message.includes(
|
|
148
|
+
if (error.message.includes('403')) {
|
|
164
149
|
throw new Error(
|
|
165
|
-
|
|
150
|
+
'Access forbidden. Your account may not have permission to create API keys.',
|
|
166
151
|
);
|
|
167
152
|
}
|
|
168
153
|
}
|
|
@@ -177,47 +162,62 @@ export class ApiKeyService {
|
|
|
177
162
|
*/
|
|
178
163
|
public async delete(id: string): Promise<boolean> {
|
|
179
164
|
try {
|
|
180
|
-
const { error } = await this.client.DELETE(
|
|
165
|
+
const { error } = await this.client.DELETE('/v1/api-keys/{id}', {
|
|
181
166
|
params: { path: { id } },
|
|
182
167
|
});
|
|
183
168
|
if (error) throw new Error(JSON.stringify(error));
|
|
184
169
|
return true;
|
|
185
170
|
} catch (error) {
|
|
186
|
-
console.error(
|
|
171
|
+
console.error('Failed to delete API key:', error);
|
|
187
172
|
throw error;
|
|
188
173
|
}
|
|
189
174
|
}
|
|
190
175
|
|
|
191
176
|
/**
|
|
192
|
-
*
|
|
193
|
-
* Command: berget api-keys
|
|
177
|
+
* Get usage statistics for an API key
|
|
178
|
+
* Command: berget api-keys describe
|
|
194
179
|
*/
|
|
195
|
-
public async
|
|
180
|
+
public async describe(id: string): Promise<any> {
|
|
196
181
|
try {
|
|
197
|
-
const { data, error } = await this.client.
|
|
182
|
+
const { data, error } = await this.client.GET('/v1/api-keys/{id}/usage', {
|
|
198
183
|
params: { path: { id } },
|
|
199
184
|
});
|
|
200
185
|
if (error) throw new Error(JSON.stringify(error));
|
|
201
|
-
return data
|
|
186
|
+
return data;
|
|
202
187
|
} catch (error) {
|
|
203
|
-
console.error(
|
|
188
|
+
console.error('Failed to get API key usage:', error);
|
|
204
189
|
throw error;
|
|
205
190
|
}
|
|
206
191
|
}
|
|
207
192
|
|
|
208
193
|
/**
|
|
209
|
-
*
|
|
210
|
-
* Command: berget api-keys
|
|
194
|
+
* List all API keys
|
|
195
|
+
* Command: berget api-keys list
|
|
211
196
|
*/
|
|
212
|
-
public async
|
|
197
|
+
public async list(): Promise<ApiKey[]> {
|
|
213
198
|
try {
|
|
214
|
-
const { data, error } = await this.client.GET(
|
|
199
|
+
const { data, error } = await this.client.GET('/v1/api-keys');
|
|
200
|
+
if (error) throw error;
|
|
201
|
+
return data || [];
|
|
202
|
+
} catch (error) {
|
|
203
|
+
handleError('Failed to list API keys', error);
|
|
204
|
+
throw error;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Rotate an API key
|
|
210
|
+
* Command: berget api-keys rotate
|
|
211
|
+
*/
|
|
212
|
+
public async rotate(id: string): Promise<ApiKeyResponse> {
|
|
213
|
+
try {
|
|
214
|
+
const { data, error } = await this.client.PUT('/v1/api-keys/{id}/rotate', {
|
|
215
215
|
params: { path: { id } },
|
|
216
216
|
});
|
|
217
217
|
if (error) throw new Error(JSON.stringify(error));
|
|
218
|
-
return data
|
|
218
|
+
return data!;
|
|
219
219
|
} catch (error) {
|
|
220
|
-
console.error(
|
|
220
|
+
console.error('Failed to rotate API key:', error);
|
|
221
221
|
throw error;
|
|
222
222
|
}
|
|
223
223
|
}
|
|
@@ -1,41 +1,32 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
import { COMMAND_GROUPS, SUBCOMMANDS } from
|
|
5
|
-
import {
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
|
|
3
|
+
import { clearAuthToken, createAuthenticatedClient, saveAuthToken } from '../client';
|
|
4
|
+
import { COMMAND_GROUPS, SUBCOMMANDS } from '../constants/command-structure';
|
|
5
|
+
import { handleError } from '../utils/error-handler';
|
|
6
|
+
import { BrowserAuth } from './browser-auth';
|
|
6
7
|
|
|
7
8
|
// Keycloak configuration based on environment
|
|
8
|
-
const isStageMode = process.argv.includes(
|
|
9
|
-
const isLocalMode = process.argv.includes(
|
|
9
|
+
const isStageMode = process.argv.includes('--stage');
|
|
10
|
+
const isLocalMode = process.argv.includes('--local');
|
|
10
11
|
const KEYCLOAK_URL =
|
|
11
|
-
isStageMode || isLocalMode ?
|
|
12
|
-
const KEYCLOAK_REALM =
|
|
13
|
-
const KEYCLOAK_CLIENT_ID =
|
|
12
|
+
isStageMode || isLocalMode ? 'https://keycloak.stage.berget.ai' : 'https://keycloak.berget.ai';
|
|
13
|
+
const KEYCLOAK_REALM = 'berget';
|
|
14
|
+
const KEYCLOAK_CLIENT_ID = 'berget-code';
|
|
14
15
|
const CALLBACK_PORT = 8787;
|
|
15
16
|
|
|
16
|
-
function makeBrowserAuth(debug?: boolean): BrowserAuth {
|
|
17
|
-
return new BrowserAuth({
|
|
18
|
-
keycloakUrl: KEYCLOAK_URL,
|
|
19
|
-
realm: KEYCLOAK_REALM,
|
|
20
|
-
clientId: KEYCLOAK_CLIENT_ID,
|
|
21
|
-
callbackPort: CALLBACK_PORT,
|
|
22
|
-
debug,
|
|
23
|
-
});
|
|
24
|
-
}
|
|
25
|
-
|
|
26
17
|
/**
|
|
27
18
|
* Service for authentication operations
|
|
28
19
|
* Command group: auth
|
|
29
20
|
*/
|
|
30
21
|
export class AuthService {
|
|
31
|
-
private static instance: AuthService;
|
|
32
|
-
|
|
33
22
|
// Command group name for this service
|
|
34
23
|
public static readonly COMMAND_GROUP = COMMAND_GROUPS.AUTH;
|
|
35
24
|
|
|
36
25
|
// Subcommands for this service
|
|
37
26
|
public static readonly COMMANDS = SUBCOMMANDS.AUTH;
|
|
38
27
|
|
|
28
|
+
private static instance: AuthService;
|
|
29
|
+
|
|
39
30
|
private constructor() {}
|
|
40
31
|
|
|
41
32
|
public static getInstance(): AuthService {
|
|
@@ -45,20 +36,6 @@ export class AuthService {
|
|
|
45
36
|
return AuthService.instance;
|
|
46
37
|
}
|
|
47
38
|
|
|
48
|
-
public async whoami(): Promise<any> {
|
|
49
|
-
try {
|
|
50
|
-
// Create fresh client to ensure we have the latest token
|
|
51
|
-
const client = createAuthenticatedClient();
|
|
52
|
-
const { data: profile, error } = await client.GET("/v1/users/me");
|
|
53
|
-
if (error) {
|
|
54
|
-
return null;
|
|
55
|
-
}
|
|
56
|
-
return profile;
|
|
57
|
-
} catch {
|
|
58
|
-
return null;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
39
|
/**
|
|
63
40
|
* Browser-based PKCE login for interactive CLI use.
|
|
64
41
|
* Prints status to stdout/stderr. Use loginInteractive() when you need
|
|
@@ -68,20 +45,20 @@ export class AuthService {
|
|
|
68
45
|
try {
|
|
69
46
|
clearAuthToken();
|
|
70
47
|
|
|
71
|
-
console.log(chalk.blue(
|
|
48
|
+
console.log(chalk.blue('Initiating login process...'));
|
|
72
49
|
|
|
73
|
-
const auth = makeBrowserAuth(process.argv.includes(
|
|
50
|
+
const auth = makeBrowserAuth(process.argv.includes('--debug'));
|
|
74
51
|
const result = await auth.start();
|
|
75
52
|
|
|
76
53
|
if (!result.success) {
|
|
77
|
-
console.log(chalk.red(`\nAuthentication failed: ${result.error ||
|
|
54
|
+
console.log(chalk.red(`\nAuthentication failed: ${result.error || 'Unknown error'}`));
|
|
78
55
|
return false;
|
|
79
56
|
}
|
|
80
57
|
|
|
81
58
|
saveAuthToken(result.accessToken!, result.refreshToken!, result.expiresIn!);
|
|
82
59
|
|
|
83
|
-
if (process.argv.includes(
|
|
84
|
-
console.log(chalk.yellow(
|
|
60
|
+
if (process.argv.includes('--debug')) {
|
|
61
|
+
console.log(chalk.yellow('DEBUG: Token data received:'));
|
|
85
62
|
console.log(
|
|
86
63
|
chalk.yellow(
|
|
87
64
|
JSON.stringify(
|
|
@@ -89,13 +66,13 @@ export class AuthService {
|
|
|
89
66
|
expires_in: result.expiresIn,
|
|
90
67
|
},
|
|
91
68
|
null,
|
|
92
|
-
2
|
|
93
|
-
)
|
|
94
|
-
)
|
|
69
|
+
2,
|
|
70
|
+
),
|
|
71
|
+
),
|
|
95
72
|
);
|
|
96
73
|
}
|
|
97
74
|
|
|
98
|
-
console.log(chalk.green(
|
|
75
|
+
console.log(chalk.green('\n✓ Successfully logged in to Berget'));
|
|
99
76
|
|
|
100
77
|
try {
|
|
101
78
|
const profile = await this.whoami();
|
|
@@ -106,13 +83,13 @@ export class AuthService {
|
|
|
106
83
|
// Ignore errors fetching profile
|
|
107
84
|
}
|
|
108
85
|
|
|
109
|
-
console.log(chalk.cyan(
|
|
110
|
-
console.log(chalk.cyan(
|
|
111
|
-
console.log(chalk.cyan(
|
|
86
|
+
console.log(chalk.cyan('\nNext steps:'));
|
|
87
|
+
console.log(chalk.cyan(' • Create an API key: berget api-keys create'));
|
|
88
|
+
console.log(chalk.cyan(' • Setup OpenCode: berget code init'));
|
|
112
89
|
|
|
113
90
|
return true;
|
|
114
91
|
} catch (error) {
|
|
115
|
-
handleError(
|
|
92
|
+
handleError('Login failed', error);
|
|
116
93
|
return false;
|
|
117
94
|
}
|
|
118
95
|
}
|
|
@@ -123,16 +100,16 @@ export class AuthService {
|
|
|
123
100
|
* their own UI (e.g. via clack/prompts).
|
|
124
101
|
*/
|
|
125
102
|
public async loginInteractive(): Promise<{
|
|
126
|
-
success: boolean;
|
|
127
103
|
accessToken?: string;
|
|
128
|
-
refreshToken?: string;
|
|
129
|
-
expiresIn?: number;
|
|
130
104
|
error?: string;
|
|
105
|
+
expiresIn?: number;
|
|
106
|
+
refreshToken?: string;
|
|
107
|
+
success: boolean;
|
|
131
108
|
}> {
|
|
132
109
|
try {
|
|
133
110
|
clearAuthToken();
|
|
134
111
|
|
|
135
|
-
const auth = makeBrowserAuth(process.argv.includes(
|
|
112
|
+
const auth = makeBrowserAuth(process.argv.includes('--debug'));
|
|
136
113
|
const result = await auth.start();
|
|
137
114
|
|
|
138
115
|
if (result.success) {
|
|
@@ -142,9 +119,33 @@ export class AuthService {
|
|
|
142
119
|
return result;
|
|
143
120
|
} catch (error) {
|
|
144
121
|
return {
|
|
145
|
-
success: false,
|
|
146
122
|
error: error instanceof Error ? error.message : String(error),
|
|
123
|
+
success: false,
|
|
147
124
|
};
|
|
148
125
|
}
|
|
149
126
|
}
|
|
127
|
+
|
|
128
|
+
public async whoami(): Promise<any> {
|
|
129
|
+
try {
|
|
130
|
+
// Create fresh client to ensure we have the latest token
|
|
131
|
+
const client = createAuthenticatedClient();
|
|
132
|
+
const { data: profile, error } = await client.GET('/v1/users/me');
|
|
133
|
+
if (error) {
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
return profile;
|
|
137
|
+
} catch {
|
|
138
|
+
return null;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function makeBrowserAuth(debug?: boolean): BrowserAuth {
|
|
144
|
+
return new BrowserAuth({
|
|
145
|
+
callbackPort: CALLBACK_PORT,
|
|
146
|
+
clientId: KEYCLOAK_CLIENT_ID,
|
|
147
|
+
debug,
|
|
148
|
+
keycloakUrl: KEYCLOAK_URL,
|
|
149
|
+
realm: KEYCLOAK_REALM,
|
|
150
|
+
});
|
|
150
151
|
}
|