berget 2.2.6 → 2.2.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/.github/workflows/publish.yml +6 -6
- package/.github/workflows/test.yml +11 -5
- package/.husky/pre-commit +1 -0
- package/.prettierignore +15 -0
- package/.prettierrc +5 -3
- package/CONTRIBUTING.md +38 -0
- package/README.md +2 -148
- package/dist/index.js +21 -21
- package/dist/package.json +28 -2
- package/dist/src/agents/app.js +28 -0
- package/dist/src/agents/backend.js +25 -0
- package/dist/src/agents/devops.js +34 -0
- package/dist/src/agents/frontend.js +25 -0
- package/dist/src/agents/fullstack.js +25 -0
- package/dist/src/agents/index.js +61 -0
- package/dist/src/agents/quality.js +70 -0
- package/dist/src/agents/security.js +26 -0
- package/dist/src/agents/types.js +2 -0
- package/dist/src/client.js +54 -62
- package/dist/src/commands/api-keys.js +132 -140
- package/dist/src/commands/auth.js +9 -9
- package/dist/src/commands/autocomplete.js +9 -9
- package/dist/src/commands/billing.js +7 -9
- package/dist/src/commands/chat.js +90 -92
- package/dist/src/commands/clusters.js +12 -12
- package/dist/src/commands/code/__tests__/auth-sync.test.js +348 -0
- package/dist/src/commands/code/__tests__/fake-api-key-service.js +23 -0
- package/dist/src/commands/code/__tests__/fake-auth-service.js +55 -0
- package/dist/src/commands/code/__tests__/fake-command-runner.js +5 -7
- package/dist/src/commands/code/__tests__/fake-file-store.js +9 -0
- package/dist/src/commands/code/__tests__/fake-prompter.js +60 -18
- package/dist/src/commands/code/__tests__/setup-flow.test.js +374 -107
- package/dist/src/commands/code/adapters/clack-prompter.js +10 -0
- package/dist/src/commands/code/adapters/fs-file-store.js +8 -3
- package/dist/src/commands/code/adapters/spawn-command-runner.js +15 -11
- package/dist/src/commands/code/auth-sync.js +283 -0
- package/dist/src/commands/code/errors.js +4 -4
- package/dist/src/commands/code/ports/auth-services.js +2 -0
- package/dist/src/commands/code/setup.js +234 -93
- package/dist/src/commands/code.js +139 -251
- package/dist/src/commands/models.js +13 -15
- package/dist/src/commands/users.js +6 -8
- package/dist/src/constants/command-structure.js +116 -116
- package/dist/src/services/api-key-service.js +43 -48
- package/dist/src/services/auth-service.js +60 -299
- package/dist/src/services/browser-auth.js +278 -0
- package/dist/src/services/chat-service.js +78 -91
- package/dist/src/services/cluster-service.js +6 -6
- package/dist/src/services/collaborator-service.js +5 -8
- package/dist/src/services/flux-service.js +5 -8
- package/dist/src/services/helm-service.js +5 -8
- package/dist/src/services/kubectl-service.js +7 -10
- package/dist/src/utils/config-checker.js +5 -5
- package/dist/src/utils/config-loader.js +25 -25
- package/dist/src/utils/default-api-key.js +23 -23
- package/dist/src/utils/env-manager.js +7 -7
- package/dist/src/utils/error-handler.js +60 -61
- package/dist/src/utils/logger.js +7 -7
- package/dist/src/utils/markdown-renderer.js +2 -2
- package/dist/src/utils/opencode-validator.js +17 -20
- package/dist/src/utils/token-manager.js +38 -11
- package/dist/tests/commands/chat.test.js +24 -24
- package/dist/tests/commands/code.test.js +147 -147
- package/dist/tests/utils/config-loader.test.js +114 -114
- package/dist/tests/utils/env-manager.test.js +57 -57
- package/dist/tests/utils/opencode-validator.test.js +33 -33
- package/dist/vitest.config.js +1 -1
- package/eslint.config.mjs +47 -0
- package/index.ts +42 -48
- package/package.json +28 -2
- package/src/agents/app.ts +27 -0
- package/src/agents/backend.ts +24 -0
- package/src/agents/devops.ts +33 -0
- package/src/agents/frontend.ts +24 -0
- package/src/agents/fullstack.ts +24 -0
- package/src/agents/index.ts +71 -0
- package/src/agents/quality.ts +69 -0
- package/src/agents/security.ts +26 -0
- package/src/agents/types.ts +17 -0
- package/src/client.ts +125 -167
- package/src/commands/api-keys.ts +261 -358
- package/src/commands/auth.ts +24 -30
- package/src/commands/autocomplete.ts +12 -12
- package/src/commands/billing.ts +22 -27
- package/src/commands/chat.ts +230 -323
- package/src/commands/clusters.ts +33 -33
- package/src/commands/code/__tests__/auth-sync.test.ts +481 -0
- package/src/commands/code/__tests__/fake-api-key-service.ts +13 -0
- package/src/commands/code/__tests__/fake-auth-service.ts +50 -0
- package/src/commands/code/__tests__/fake-command-runner.ts +39 -42
- package/src/commands/code/__tests__/fake-file-store.ts +32 -23
- package/src/commands/code/__tests__/fake-prompter.ts +107 -69
- package/src/commands/code/__tests__/setup-flow.test.ts +624 -270
- package/src/commands/code/adapters/clack-prompter.ts +50 -38
- package/src/commands/code/adapters/fs-file-store.ts +31 -27
- package/src/commands/code/adapters/spawn-command-runner.ts +33 -29
- package/src/commands/code/auth-sync.ts +329 -0
- package/src/commands/code/errors.ts +15 -15
- package/src/commands/code/ports/auth-services.ts +14 -0
- package/src/commands/code/ports/command-runner.ts +8 -4
- package/src/commands/code/ports/file-store.ts +5 -4
- package/src/commands/code/ports/prompter.ts +24 -18
- package/src/commands/code/setup.ts +545 -317
- package/src/commands/code.ts +271 -473
- package/src/commands/index.ts +19 -19
- package/src/commands/models.ts +32 -37
- package/src/commands/users.ts +15 -22
- package/src/constants/command-structure.ts +119 -142
- package/src/services/api-key-service.ts +96 -113
- package/src/services/auth-service.ts +92 -339
- package/src/services/browser-auth.ts +296 -0
- package/src/services/chat-service.ts +246 -279
- package/src/services/cluster-service.ts +29 -32
- package/src/services/collaborator-service.ts +13 -18
- package/src/services/flux-service.ts +16 -18
- package/src/services/helm-service.ts +16 -18
- package/src/services/kubectl-service.ts +12 -14
- package/src/types/api.d.ts +924 -926
- package/src/types/json.d.ts +3 -3
- package/src/utils/config-checker.ts +10 -10
- package/src/utils/config-loader.ts +110 -127
- package/src/utils/default-api-key.ts +81 -93
- package/src/utils/env-manager.ts +36 -40
- package/src/utils/error-handler.ts +83 -78
- package/src/utils/logger.ts +41 -41
- package/src/utils/markdown-renderer.ts +11 -11
- package/src/utils/opencode-validator.ts +51 -56
- package/src/utils/token-manager.ts +84 -64
- package/templates/agents/app.md +1 -0
- package/templates/agents/backend.md +1 -0
- package/templates/agents/devops.md +2 -0
- package/templates/agents/frontend.md +1 -0
- package/templates/agents/fullstack.md +1 -0
- package/templates/agents/quality.md +45 -40
- package/templates/agents/security.md +1 -0
- package/tests/commands/chat.test.ts +60 -70
- package/tests/commands/code.test.ts +330 -376
- package/tests/utils/config-loader.test.ts +260 -260
- package/tests/utils/env-manager.test.ts +127 -134
- package/tests/utils/opencode-validator.test.ts +58 -63
- package/tsconfig.json +2 -2
- package/vitest.config.ts +3 -3
- package/AGENTS.md +0 -374
- package/TODO.md +0 -19
|
@@ -1,27 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
-
if (mod && mod.__esModule) return mod;
|
|
20
|
-
var result = {};
|
|
21
|
-
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
-
__setModuleDefault(result, mod);
|
|
23
|
-
return result;
|
|
24
|
-
};
|
|
25
2
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
26
3
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
27
4
|
return new (P || (P = Promise))(function (resolve, reject) {
|
|
@@ -37,42 +14,32 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
37
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
38
15
|
exports.AuthService = void 0;
|
|
39
16
|
const client_1 = require("../client");
|
|
40
|
-
// We'll use dynamic import for 'open' to support ESM modules in CommonJS
|
|
41
17
|
const chalk_1 = __importDefault(require("chalk"));
|
|
42
18
|
const error_handler_1 = require("../utils/error-handler");
|
|
43
19
|
const command_structure_1 = require("../constants/command-structure");
|
|
44
|
-
const
|
|
45
|
-
const crypto = __importStar(require("crypto"));
|
|
46
|
-
const url = __importStar(require("url"));
|
|
20
|
+
const browser_auth_1 = require("./browser-auth");
|
|
47
21
|
// Keycloak configuration based on environment
|
|
48
|
-
const isStageMode = process.argv.includes(
|
|
49
|
-
const isLocalMode = process.argv.includes(
|
|
50
|
-
const KEYCLOAK_URL =
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
const KEYCLOAK_REALM = 'berget';
|
|
54
|
-
const KEYCLOAK_CLIENT_ID = 'berget-code';
|
|
22
|
+
const isStageMode = process.argv.includes("--stage");
|
|
23
|
+
const isLocalMode = process.argv.includes("--local");
|
|
24
|
+
const KEYCLOAK_URL = isStageMode || isLocalMode ? "https://keycloak.stage.berget.ai" : "https://keycloak.berget.ai";
|
|
25
|
+
const KEYCLOAK_REALM = "berget";
|
|
26
|
+
const KEYCLOAK_CLIENT_ID = "berget-code";
|
|
55
27
|
const CALLBACK_PORT = 8787;
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
*/
|
|
65
|
-
function generateCodeChallenge(verifier) {
|
|
66
|
-
return crypto.createHash('sha256').update(verifier).digest('base64url');
|
|
28
|
+
function makeBrowserAuth(debug) {
|
|
29
|
+
return new browser_auth_1.BrowserAuth({
|
|
30
|
+
keycloakUrl: KEYCLOAK_URL,
|
|
31
|
+
realm: KEYCLOAK_REALM,
|
|
32
|
+
clientId: KEYCLOAK_CLIENT_ID,
|
|
33
|
+
callbackPort: CALLBACK_PORT,
|
|
34
|
+
debug,
|
|
35
|
+
});
|
|
67
36
|
}
|
|
68
37
|
/**
|
|
69
38
|
* Service for authentication operations
|
|
70
39
|
* Command group: auth
|
|
71
40
|
*/
|
|
72
41
|
class AuthService {
|
|
73
|
-
constructor() {
|
|
74
|
-
this.client = (0, client_1.createAuthenticatedClient)();
|
|
75
|
-
}
|
|
42
|
+
constructor() { }
|
|
76
43
|
static getInstance() {
|
|
77
44
|
if (!AuthService.instance) {
|
|
78
45
|
AuthService.instance = new AuthService();
|
|
@@ -84,271 +51,41 @@ class AuthService {
|
|
|
84
51
|
try {
|
|
85
52
|
// Create fresh client to ensure we have the latest token
|
|
86
53
|
const client = (0, client_1.createAuthenticatedClient)();
|
|
87
|
-
const { data: profile, error } = yield client.GET(
|
|
54
|
+
const { data: profile, error } = yield client.GET("/v1/users/me");
|
|
88
55
|
if (error) {
|
|
89
56
|
return null;
|
|
90
57
|
}
|
|
91
58
|
return profile;
|
|
92
59
|
}
|
|
93
|
-
catch (
|
|
60
|
+
catch (_a) {
|
|
94
61
|
return null;
|
|
95
62
|
}
|
|
96
63
|
});
|
|
97
64
|
}
|
|
65
|
+
/**
|
|
66
|
+
* Browser-based PKCE login for interactive CLI use.
|
|
67
|
+
* Prints status to stdout/stderr. Use loginInteractive() when you need
|
|
68
|
+
* a silent, UI-agnostic result (e.g. inside the setup wizard).
|
|
69
|
+
*/
|
|
98
70
|
login() {
|
|
99
71
|
return __awaiter(this, void 0, void 0, function* () {
|
|
100
72
|
try {
|
|
101
|
-
// Clear any existing token to ensure a fresh login
|
|
102
73
|
(0, client_1.clearAuthToken)();
|
|
103
|
-
console.log(chalk_1.default.blue(
|
|
104
|
-
|
|
105
|
-
const
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
const redirectUri = `http://localhost:${CALLBACK_PORT}/callback`;
|
|
109
|
-
// Build authorization URL
|
|
110
|
-
const authUrl = new URL(`${KEYCLOAK_URL}/realms/${KEYCLOAK_REALM}/protocol/openid-connect/auth`);
|
|
111
|
-
authUrl.searchParams.set('client_id', KEYCLOAK_CLIENT_ID);
|
|
112
|
-
authUrl.searchParams.set('response_type', 'code');
|
|
113
|
-
authUrl.searchParams.set('redirect_uri', redirectUri);
|
|
114
|
-
authUrl.searchParams.set('scope', 'openid email profile');
|
|
115
|
-
authUrl.searchParams.set('state', state);
|
|
116
|
-
authUrl.searchParams.set('code_challenge', codeChallenge);
|
|
117
|
-
authUrl.searchParams.set('code_challenge_method', 'S256');
|
|
118
|
-
// Create a promise that resolves when we receive the callback
|
|
119
|
-
const authResult = yield new Promise((resolve) => {
|
|
120
|
-
const server = http.createServer((req, res) => __awaiter(this, void 0, void 0, function* () {
|
|
121
|
-
const parsedUrl = url.parse(req.url || '', true);
|
|
122
|
-
if (parsedUrl.pathname === '/callback') {
|
|
123
|
-
const receivedState = parsedUrl.query.state;
|
|
124
|
-
const code = parsedUrl.query.code;
|
|
125
|
-
const error = parsedUrl.query.error;
|
|
126
|
-
const errorPage = (title, message) => `
|
|
127
|
-
<!DOCTYPE html>
|
|
128
|
-
<html lang="en">
|
|
129
|
-
<head>
|
|
130
|
-
<meta charset="UTF-8">
|
|
131
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
132
|
-
<title>Berget - Authentication Failed</title>
|
|
133
|
-
<style>
|
|
134
|
-
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
135
|
-
body {
|
|
136
|
-
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
|
|
137
|
-
display: flex;
|
|
138
|
-
justify-content: center;
|
|
139
|
-
align-items: center;
|
|
140
|
-
min-height: 100vh;
|
|
141
|
-
background: linear-gradient(135deg, #0f0f1a 0%, #1a1a2e 50%, #16213e 100%);
|
|
142
|
-
color: #fff;
|
|
143
|
-
}
|
|
144
|
-
.container {
|
|
145
|
-
text-align: center;
|
|
146
|
-
padding: 3rem;
|
|
147
|
-
max-width: 400px;
|
|
148
|
-
}
|
|
149
|
-
.icon {
|
|
150
|
-
width: 80px;
|
|
151
|
-
height: 80px;
|
|
152
|
-
background: linear-gradient(135deg, #f87171 0%, #ef4444 100%);
|
|
153
|
-
border-radius: 50%;
|
|
154
|
-
display: flex;
|
|
155
|
-
align-items: center;
|
|
156
|
-
justify-content: center;
|
|
157
|
-
margin: 0 auto 1.5rem;
|
|
158
|
-
box-shadow: 0 4px 20px rgba(248, 113, 113, 0.3);
|
|
159
|
-
}
|
|
160
|
-
.icon svg {
|
|
161
|
-
width: 40px;
|
|
162
|
-
height: 40px;
|
|
163
|
-
stroke: #fff;
|
|
164
|
-
stroke-width: 3;
|
|
165
|
-
}
|
|
166
|
-
h1 {
|
|
167
|
-
font-size: 1.5rem;
|
|
168
|
-
font-weight: 600;
|
|
169
|
-
margin-bottom: 0.75rem;
|
|
170
|
-
color: #fff;
|
|
171
|
-
}
|
|
172
|
-
p {
|
|
173
|
-
color: #94a3b8;
|
|
174
|
-
font-size: 0.95rem;
|
|
175
|
-
line-height: 1.5;
|
|
176
|
-
}
|
|
177
|
-
.brand {
|
|
178
|
-
margin-top: 2rem;
|
|
179
|
-
opacity: 0.5;
|
|
180
|
-
font-size: 0.8rem;
|
|
181
|
-
letter-spacing: 0.05em;
|
|
182
|
-
}
|
|
183
|
-
</style>
|
|
184
|
-
</head>
|
|
185
|
-
<body>
|
|
186
|
-
<div class="container">
|
|
187
|
-
<div class="icon">
|
|
188
|
-
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor">
|
|
189
|
-
<line x1="18" y1="6" x2="6" y2="18"></line>
|
|
190
|
-
<line x1="6" y1="6" x2="18" y2="18"></line>
|
|
191
|
-
</svg>
|
|
192
|
-
</div>
|
|
193
|
-
<h1>${title}</h1>
|
|
194
|
-
<p>${message}</p>
|
|
195
|
-
<div class="brand">BERGET</div>
|
|
196
|
-
</div>
|
|
197
|
-
</body>
|
|
198
|
-
</html>
|
|
199
|
-
`;
|
|
200
|
-
if (error) {
|
|
201
|
-
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
202
|
-
res.end(errorPage('Authentication Failed', String(parsedUrl.query.error_description || error)));
|
|
203
|
-
server.close();
|
|
204
|
-
resolve({ success: false, error });
|
|
205
|
-
return;
|
|
206
|
-
}
|
|
207
|
-
if (receivedState !== state) {
|
|
208
|
-
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
209
|
-
res.end(errorPage('Authentication Failed', 'Invalid state parameter. Please try again.'));
|
|
210
|
-
server.close();
|
|
211
|
-
resolve({ success: false, error: 'Invalid state parameter' });
|
|
212
|
-
return;
|
|
213
|
-
}
|
|
214
|
-
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
215
|
-
res.end(`
|
|
216
|
-
<!DOCTYPE html>
|
|
217
|
-
<html lang="en">
|
|
218
|
-
<head>
|
|
219
|
-
<meta charset="UTF-8">
|
|
220
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
221
|
-
<title>Berget - Authentication Successful</title>
|
|
222
|
-
<style>
|
|
223
|
-
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
224
|
-
body {
|
|
225
|
-
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
|
|
226
|
-
display: flex;
|
|
227
|
-
justify-content: center;
|
|
228
|
-
align-items: center;
|
|
229
|
-
min-height: 100vh;
|
|
230
|
-
background: linear-gradient(135deg, #0f0f1a 0%, #1a1a2e 50%, #16213e 100%);
|
|
231
|
-
color: #fff;
|
|
232
|
-
}
|
|
233
|
-
.container {
|
|
234
|
-
text-align: center;
|
|
235
|
-
padding: 3rem;
|
|
236
|
-
max-width: 400px;
|
|
237
|
-
}
|
|
238
|
-
.icon {
|
|
239
|
-
width: 80px;
|
|
240
|
-
height: 80px;
|
|
241
|
-
background: linear-gradient(135deg, #4ade80 0%, #22c55e 100%);
|
|
242
|
-
border-radius: 50%;
|
|
243
|
-
display: flex;
|
|
244
|
-
align-items: center;
|
|
245
|
-
justify-content: center;
|
|
246
|
-
margin: 0 auto 1.5rem;
|
|
247
|
-
box-shadow: 0 4px 20px rgba(74, 222, 128, 0.3);
|
|
248
|
-
}
|
|
249
|
-
.icon svg {
|
|
250
|
-
width: 40px;
|
|
251
|
-
height: 40px;
|
|
252
|
-
stroke: #fff;
|
|
253
|
-
stroke-width: 3;
|
|
254
|
-
}
|
|
255
|
-
h1 {
|
|
256
|
-
font-size: 1.5rem;
|
|
257
|
-
font-weight: 600;
|
|
258
|
-
margin-bottom: 0.75rem;
|
|
259
|
-
color: #fff;
|
|
260
|
-
}
|
|
261
|
-
p {
|
|
262
|
-
color: #94a3b8;
|
|
263
|
-
font-size: 0.95rem;
|
|
264
|
-
line-height: 1.5;
|
|
265
|
-
}
|
|
266
|
-
.brand {
|
|
267
|
-
margin-top: 2rem;
|
|
268
|
-
opacity: 0.5;
|
|
269
|
-
font-size: 0.8rem;
|
|
270
|
-
letter-spacing: 0.05em;
|
|
271
|
-
}
|
|
272
|
-
</style>
|
|
273
|
-
</head>
|
|
274
|
-
<body>
|
|
275
|
-
<div class="container">
|
|
276
|
-
<div class="icon">
|
|
277
|
-
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor">
|
|
278
|
-
<polyline points="20 6 9 17 4 12"></polyline>
|
|
279
|
-
</svg>
|
|
280
|
-
</div>
|
|
281
|
-
<h1>Authentication Successful</h1>
|
|
282
|
-
<p>You can close this window and return to your terminal.</p>
|
|
283
|
-
<div class="brand">BERGET</div>
|
|
284
|
-
</div>
|
|
285
|
-
</body>
|
|
286
|
-
</html>
|
|
287
|
-
`);
|
|
288
|
-
server.close();
|
|
289
|
-
resolve({ success: true, code });
|
|
290
|
-
}
|
|
291
|
-
}));
|
|
292
|
-
server.listen(CALLBACK_PORT, () => {
|
|
293
|
-
if (process.argv.includes('--debug')) {
|
|
294
|
-
console.log(chalk_1.default.dim(`Callback server listening on port ${CALLBACK_PORT}`));
|
|
295
|
-
}
|
|
296
|
-
});
|
|
297
|
-
// Set timeout for the server
|
|
298
|
-
setTimeout(() => {
|
|
299
|
-
server.close();
|
|
300
|
-
resolve({ success: false, error: 'Authentication timed out' });
|
|
301
|
-
}, 5 * 60 * 1000) // 5 minute timeout
|
|
302
|
-
;
|
|
303
|
-
(() => __awaiter(this, void 0, void 0, function* () {
|
|
304
|
-
try {
|
|
305
|
-
const open = yield Promise.resolve().then(() => __importStar(require('open'))).then((m) => m.default);
|
|
306
|
-
yield open(authUrl.toString());
|
|
307
|
-
console.log(chalk_1.default.dim('Browser opened for authentication...'));
|
|
308
|
-
}
|
|
309
|
-
catch (_a) {
|
|
310
|
-
console.log(chalk_1.default.cyan('\nPlease open this URL in your browser:'));
|
|
311
|
-
console.log(chalk_1.default.bold(authUrl.toString()));
|
|
312
|
-
}
|
|
313
|
-
}))();
|
|
314
|
-
});
|
|
315
|
-
if (!authResult.success || !authResult.code) {
|
|
316
|
-
console.log(chalk_1.default.red(`\nAuthentication failed: ${authResult.error || 'Unknown error'}`));
|
|
317
|
-
return false;
|
|
318
|
-
}
|
|
319
|
-
// Exchange authorization code for tokens
|
|
320
|
-
console.log(chalk_1.default.dim('Exchanging authorization code for tokens...'));
|
|
321
|
-
const tokenUrl = `${KEYCLOAK_URL}/realms/${KEYCLOAK_REALM}/protocol/openid-connect/token`;
|
|
322
|
-
const tokenResponse = yield fetch(tokenUrl, {
|
|
323
|
-
method: 'POST',
|
|
324
|
-
headers: {
|
|
325
|
-
'Content-Type': 'application/x-www-form-urlencoded',
|
|
326
|
-
},
|
|
327
|
-
body: new URLSearchParams({
|
|
328
|
-
grant_type: 'authorization_code',
|
|
329
|
-
client_id: KEYCLOAK_CLIENT_ID,
|
|
330
|
-
code: authResult.code,
|
|
331
|
-
redirect_uri: redirectUri,
|
|
332
|
-
code_verifier: codeVerifier,
|
|
333
|
-
}).toString(),
|
|
334
|
-
});
|
|
335
|
-
if (!tokenResponse.ok) {
|
|
336
|
-
const errorText = yield tokenResponse.text();
|
|
337
|
-
console.log(chalk_1.default.red(`\nFailed to exchange code for tokens: ${errorText}`));
|
|
74
|
+
console.log(chalk_1.default.blue("Initiating login process..."));
|
|
75
|
+
const auth = makeBrowserAuth(process.argv.includes("--debug"));
|
|
76
|
+
const result = yield auth.start();
|
|
77
|
+
if (!result.success) {
|
|
78
|
+
console.log(chalk_1.default.red(`\nAuthentication failed: ${result.error || "Unknown error"}`));
|
|
338
79
|
return false;
|
|
339
80
|
}
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
if (process.argv.includes('--debug')) {
|
|
344
|
-
console.log(chalk_1.default.yellow('DEBUG: Token data received:'));
|
|
81
|
+
(0, client_1.saveAuthToken)(result.accessToken, result.refreshToken, result.expiresIn);
|
|
82
|
+
if (process.argv.includes("--debug")) {
|
|
83
|
+
console.log(chalk_1.default.yellow("DEBUG: Token data received:"));
|
|
345
84
|
console.log(chalk_1.default.yellow(JSON.stringify({
|
|
346
|
-
expires_in:
|
|
347
|
-
refresh_expires_in: tokenData.refresh_expires_in,
|
|
85
|
+
expires_in: result.expiresIn,
|
|
348
86
|
}, null, 2)));
|
|
349
87
|
}
|
|
350
|
-
console.log(chalk_1.default.green(
|
|
351
|
-
// Try to get user info
|
|
88
|
+
console.log(chalk_1.default.green("\n✓ Successfully logged in to Berget"));
|
|
352
89
|
try {
|
|
353
90
|
const profile = yield this.whoami();
|
|
354
91
|
if (profile === null || profile === void 0 ? void 0 : profile.email) {
|
|
@@ -358,17 +95,41 @@ class AuthService {
|
|
|
358
95
|
catch (_a) {
|
|
359
96
|
// Ignore errors fetching profile
|
|
360
97
|
}
|
|
361
|
-
console.log(chalk_1.default.cyan(
|
|
362
|
-
console.log(chalk_1.default.cyan(
|
|
363
|
-
console.log(chalk_1.default.cyan(
|
|
98
|
+
console.log(chalk_1.default.cyan("\nNext steps:"));
|
|
99
|
+
console.log(chalk_1.default.cyan(" • Create an API key: berget api-keys create"));
|
|
100
|
+
console.log(chalk_1.default.cyan(" • Setup OpenCode: berget code init"));
|
|
364
101
|
return true;
|
|
365
102
|
}
|
|
366
103
|
catch (error) {
|
|
367
|
-
(0, error_handler_1.handleError)(
|
|
104
|
+
(0, error_handler_1.handleError)("Login failed", error);
|
|
368
105
|
return false;
|
|
369
106
|
}
|
|
370
107
|
});
|
|
371
108
|
}
|
|
109
|
+
/**
|
|
110
|
+
* Browser-based PKCE login for wizard / programmatic use.
|
|
111
|
+
* Does NOT print to stdout — returns tokens so callers can display
|
|
112
|
+
* their own UI (e.g. via clack/prompts).
|
|
113
|
+
*/
|
|
114
|
+
loginInteractive() {
|
|
115
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
116
|
+
try {
|
|
117
|
+
(0, client_1.clearAuthToken)();
|
|
118
|
+
const auth = makeBrowserAuth(process.argv.includes("--debug"));
|
|
119
|
+
const result = yield auth.start();
|
|
120
|
+
if (result.success) {
|
|
121
|
+
(0, client_1.saveAuthToken)(result.accessToken, result.refreshToken, result.expiresIn);
|
|
122
|
+
}
|
|
123
|
+
return result;
|
|
124
|
+
}
|
|
125
|
+
catch (error) {
|
|
126
|
+
return {
|
|
127
|
+
success: false,
|
|
128
|
+
error: error instanceof Error ? error.message : String(error),
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
}
|
|
372
133
|
}
|
|
373
134
|
exports.AuthService = AuthService;
|
|
374
135
|
// Command group name for this service
|