berget 2.2.6 → 2.2.8
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 +2 -2
- package/.github/workflows/test.yml +10 -4
- package/.husky/pre-commit +1 -0
- package/.prettierignore +15 -0
- package/.prettierrc +7 -3
- package/CONTRIBUTING.md +38 -0
- package/README.md +2 -148
- package/dist/index.js +10 -11
- package/dist/package.json +30 -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 +97 -117
- package/dist/src/commands/api-keys.js +75 -90
- package/dist/src/commands/auth.js +7 -16
- package/dist/src/commands/autocomplete.js +1 -1
- package/dist/src/commands/billing.js +6 -17
- package/dist/src/commands/chat.js +68 -101
- package/dist/src/commands/clusters.js +9 -18
- package/dist/src/commands/code/__tests__/auth-sync.test.js +351 -0
- package/dist/src/commands/code/__tests__/fake-api-key-service.js +13 -0
- package/dist/src/commands/code/__tests__/fake-auth-service.js +47 -0
- package/dist/src/commands/code/__tests__/fake-command-runner.js +21 -34
- package/dist/src/commands/code/__tests__/fake-file-store.js +20 -33
- package/dist/src/commands/code/__tests__/fake-prompter.js +83 -57
- package/dist/src/commands/code/__tests__/setup-flow.test.js +359 -92
- package/dist/src/commands/code/adapters/clack-prompter.js +15 -22
- package/dist/src/commands/code/adapters/fs-file-store.js +26 -40
- package/dist/src/commands/code/adapters/spawn-command-runner.js +27 -37
- package/dist/src/commands/code/auth-sync.js +270 -0
- package/dist/src/commands/code/errors.js +12 -9
- package/dist/src/commands/code/ports/auth-services.js +2 -0
- package/dist/src/commands/code/setup.js +387 -281
- package/dist/src/commands/code.js +205 -332
- package/dist/src/commands/index.js +5 -5
- package/dist/src/commands/models.js +6 -17
- package/dist/src/commands/users.js +5 -16
- package/dist/src/constants/command-structure.js +104 -104
- package/dist/src/services/api-key-service.js +132 -157
- package/dist/src/services/auth-service.js +89 -342
- package/dist/src/services/browser-auth.js +268 -0
- package/dist/src/services/chat-service.js +371 -401
- package/dist/src/services/cluster-service.js +47 -62
- package/dist/src/services/collaborator-service.js +10 -25
- package/dist/src/services/flux-service.js +14 -29
- package/dist/src/services/helm-service.js +10 -25
- package/dist/src/services/kubectl-service.js +16 -33
- package/dist/src/utils/config-checker.js +3 -3
- package/dist/src/utils/config-loader.js +95 -95
- package/dist/src/utils/default-api-key.js +124 -134
- package/dist/src/utils/env-manager.js +55 -66
- package/dist/src/utils/error-handler.js +20 -21
- package/dist/src/utils/logger.js +72 -65
- package/dist/src/utils/markdown-renderer.js +27 -27
- package/dist/src/utils/opencode-validator.js +63 -68
- package/dist/src/utils/token-manager.js +74 -45
- package/dist/tests/commands/chat.test.js +16 -25
- package/dist/tests/commands/code.test.js +95 -104
- package/dist/tests/utils/config-loader.test.js +48 -48
- package/dist/tests/utils/env-manager.test.js +43 -52
- package/dist/tests/utils/opencode-validator.test.js +22 -21
- package/dist/vitest.config.js +1 -1
- package/eslint.config.mjs +67 -0
- package/index.ts +35 -42
- package/package.json +30 -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 +73 -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 +118 -152
- package/src/commands/api-keys.ts +241 -333
- package/src/commands/auth.ts +22 -27
- package/src/commands/autocomplete.ts +9 -9
- package/src/commands/billing.ts +20 -24
- package/src/commands/chat.ts +248 -338
- package/src/commands/clusters.ts +27 -26
- package/src/commands/code/__tests__/auth-sync.test.ts +482 -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 +45 -42
- package/src/commands/code/__tests__/fake-file-store.ts +32 -23
- package/src/commands/code/__tests__/fake-prompter.ts +116 -77
- package/src/commands/code/__tests__/setup-flow.test.ts +624 -268
- package/src/commands/code/adapters/clack-prompter.ts +53 -39
- package/src/commands/code/adapters/fs-file-store.ts +32 -27
- package/src/commands/code/adapters/spawn-command-runner.ts +38 -29
- package/src/commands/code/auth-sync.ts +329 -0
- package/src/commands/code/errors.ts +18 -18
- 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 +570 -340
- package/src/commands/code.ts +338 -539
- package/src/commands/index.ts +20 -19
- package/src/commands/models.ts +28 -32
- package/src/commands/users.ts +15 -21
- package/src/constants/command-structure.ts +134 -157
- package/src/services/api-key-service.ts +105 -122
- package/src/services/auth-service.ts +99 -345
- package/src/services/browser-auth.ts +296 -0
- package/src/services/chat-service.ts +265 -299
- package/src/services/cluster-service.ts +42 -45
- package/src/services/collaborator-service.ts +14 -19
- package/src/services/flux-service.ts +23 -25
- package/src/services/helm-service.ts +19 -21
- package/src/services/kubectl-service.ts +17 -19
- package/src/types/api.d.ts +1905 -1907
- package/src/types/json.d.ts +2 -2
- package/src/utils/config-checker.ts +10 -10
- package/src/utils/config-loader.ts +162 -178
- package/src/utils/default-api-key.ts +114 -125
- package/src/utils/env-manager.ts +53 -57
- package/src/utils/error-handler.ts +61 -56
- package/src/utils/logger.ts +79 -73
- package/src/utils/markdown-renderer.ts +31 -31
- package/src/utils/opencode-validator.ts +85 -89
- package/src/utils/token-manager.ts +108 -87
- 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 +53 -62
- package/tests/commands/code.test.ts +265 -310
- package/tests/utils/config-loader.test.ts +189 -188
- package/tests/utils/env-manager.test.ts +110 -113
- package/tests/utils/opencode-validator.test.ts +52 -56
- package/tsconfig.json +4 -3
- package/vitest.config.ts +3 -3
- package/AGENTS.md +0 -374
- package/TODO.md +0 -19
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.agent = void 0;
|
|
4
|
+
exports.agent = {
|
|
5
|
+
config: {
|
|
6
|
+
description: 'Quality assurance specialist for testing, building, and complete PR management.',
|
|
7
|
+
mode: 'subagent',
|
|
8
|
+
name: 'quality',
|
|
9
|
+
permission: {
|
|
10
|
+
bash: 'allow',
|
|
11
|
+
edit: 'allow',
|
|
12
|
+
webfetch: 'allow',
|
|
13
|
+
},
|
|
14
|
+
temperature: 0.1,
|
|
15
|
+
top_p: 0.9,
|
|
16
|
+
},
|
|
17
|
+
systemPrompt: `Voice: Scandinavian calm—precise, concise, confident. You are Berget Code Quality agent. Specialist in code quality assurance, testing, building, and pull request lifecycle management.
|
|
18
|
+
|
|
19
|
+
Core responsibilities:
|
|
20
|
+
- Run comprehensive test suites (npm test, npm run test, jest, vitest)
|
|
21
|
+
- Execute build processes (npm run build, webpack, vite, tsc)
|
|
22
|
+
- Create and manage pull requests with proper descriptions
|
|
23
|
+
- Handle merge conflicts and keep main updated
|
|
24
|
+
- Monitor GitHub for reviewer comments and address them
|
|
25
|
+
- Ensure code quality standards are met
|
|
26
|
+
- Validate linting and formatting (npm run lint, prettier)
|
|
27
|
+
- Check test coverage and performance benchmarks
|
|
28
|
+
- Handle CI/CD pipeline validation
|
|
29
|
+
|
|
30
|
+
Complete PR Workflow:
|
|
31
|
+
1. Ensure all tests pass: npm test
|
|
32
|
+
2. Build successfully: npm run build
|
|
33
|
+
3. Commit all changes with proper message
|
|
34
|
+
4. Push to feature branch
|
|
35
|
+
5. Update main branch and handle merge conflicts
|
|
36
|
+
6. Create or update PR with comprehensive description
|
|
37
|
+
7. Monitor for reviewer comments
|
|
38
|
+
8. Address feedback and push updates
|
|
39
|
+
9. Always provide PR URL for user review
|
|
40
|
+
|
|
41
|
+
Essential CLI commands:
|
|
42
|
+
- npm test or npm run test (run test suite)
|
|
43
|
+
- npm run build (build project)
|
|
44
|
+
- npm run lint (run linting)
|
|
45
|
+
- npm run format (format code)
|
|
46
|
+
- npm run test:coverage (check coverage)
|
|
47
|
+
- git add <specific-files> && git commit -m "message" && git push (commit and push)
|
|
48
|
+
- git checkout main && git pull origin main (update main)
|
|
49
|
+
- git checkout feature-branch && git merge main (handle conflicts)
|
|
50
|
+
- gh pr create --title "title" --body "body" (create PR)
|
|
51
|
+
- gh pr view --comments (check PR comments)
|
|
52
|
+
- gh pr edit --title "title" --body "body" (update PR)
|
|
53
|
+
|
|
54
|
+
PR Creation Process:
|
|
55
|
+
- Always include clear summary of changes
|
|
56
|
+
- List technical details and improvements
|
|
57
|
+
- Include testing and validation results
|
|
58
|
+
- Add any breaking changes or migration notes
|
|
59
|
+
- Provide PR URL immediately after creation
|
|
60
|
+
|
|
61
|
+
GIT WORKFLOW RULES (CRITICAL - ENFORCE STRICTLY):
|
|
62
|
+
- NEVER push directly to main branch - ALWAYS use pull requests
|
|
63
|
+
- NEVER use 'git add .' - ALWAYS add specific files with 'git add path/to/file'
|
|
64
|
+
- ALWAYS clean up test files, documentation files, and temporary artifacts before committing
|
|
65
|
+
- ALWAYS ensure git history maintains production quality - no test commits, no debugging code
|
|
66
|
+
- ALWAYS create descriptive commit messages following project conventions
|
|
67
|
+
- ALWAYS run tests and build before creating PR
|
|
68
|
+
|
|
69
|
+
Always provide specific command examples and wait for processes to complete before proceeding.`,
|
|
70
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.agent = void 0;
|
|
4
|
+
exports.agent = {
|
|
5
|
+
config: {
|
|
6
|
+
description: 'Security specialist for pentesting, OWASP compliance, and vulnerability assessments.',
|
|
7
|
+
mode: 'subagent',
|
|
8
|
+
name: 'security',
|
|
9
|
+
permission: {
|
|
10
|
+
bash: 'allow',
|
|
11
|
+
edit: 'deny',
|
|
12
|
+
webfetch: 'allow',
|
|
13
|
+
},
|
|
14
|
+
temperature: 0.2,
|
|
15
|
+
top_p: 0.8,
|
|
16
|
+
},
|
|
17
|
+
systemPrompt: `Voice: Scandinavian calm—precise, concise, confident. You are Berget Code Security agent. Expert in application security, penetration testing, and OWASP standards. Core responsibilities: Conduct security assessments and penetration tests, Validate OWASP Top 10 compliance, Review code for security vulnerabilities, Implement security headers and Content Security Policy (CSP), Audit API security, Check for sensitive data exposure, Validate input sanitization and output encoding, Assess dependency security and supply chain risks. Tools and techniques: OWASP ZAP, Burp Suite, security linters, dependency scanners, manual code review. Always provide specific, actionable security recommendations with priority levels.
|
|
18
|
+
|
|
19
|
+
GIT WORKFLOW RULES (CRITICAL):
|
|
20
|
+
- NEVER push directly to main branch - ALWAYS use pull requests
|
|
21
|
+
- NEVER use 'git add .' - ALWAYS add specific files with 'git add path/to/file'
|
|
22
|
+
- ALWAYS clean up test files, documentation files, and temporary artifacts before committing
|
|
23
|
+
- ALWAYS ensure git history maintains production quality - no test commits, no debugging code
|
|
24
|
+
- ALWAYS create descriptive commit messages following project conventions
|
|
25
|
+
- ALWAYS run tests and build before creating PR`,
|
|
26
|
+
};
|
package/dist/src/client.js
CHANGED
|
@@ -1,31 +1,24 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
-
});
|
|
10
|
-
};
|
|
11
2
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
4
|
};
|
|
14
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
6
|
exports.createAuthenticatedClient = exports.clearAuthToken = exports.saveAuthToken = exports.getAuthToken = exports.apiClient = exports.API_BASE_URL = void 0;
|
|
16
|
-
const openapi_fetch_1 = __importDefault(require("openapi-fetch"));
|
|
17
7
|
const chalk_1 = __importDefault(require("chalk"));
|
|
18
|
-
const
|
|
8
|
+
const openapi_fetch_1 = __importDefault(require("openapi-fetch"));
|
|
19
9
|
const logger_1 = require("./utils/logger");
|
|
10
|
+
const token_manager_1 = require("./utils/token-manager");
|
|
20
11
|
// API Base URL
|
|
21
12
|
// Use --local flag to test against local API
|
|
22
13
|
// Use --stage flag to test against stage API
|
|
23
14
|
const isLocalMode = process.argv.includes('--local');
|
|
24
15
|
const isStageMode = process.argv.includes('--stage');
|
|
25
16
|
exports.API_BASE_URL = process.env.BERGET_API_URL ||
|
|
26
|
-
(isLocalMode
|
|
27
|
-
|
|
28
|
-
|
|
17
|
+
(isLocalMode
|
|
18
|
+
? 'http://localhost:3000'
|
|
19
|
+
: isStageMode
|
|
20
|
+
? 'https://api.stage.berget.ai'
|
|
21
|
+
: 'https://api.berget.ai'); // production default
|
|
29
22
|
if (isLocalMode && !process.env.BERGET_API_URL) {
|
|
30
23
|
logger_1.logger.debug('Using local API endpoint: http://localhost:3000');
|
|
31
24
|
}
|
|
@@ -36,8 +29,8 @@ else if (isStageMode && !process.env.BERGET_API_URL) {
|
|
|
36
29
|
exports.apiClient = (0, openapi_fetch_1.default)({
|
|
37
30
|
baseUrl: exports.API_BASE_URL,
|
|
38
31
|
headers: {
|
|
39
|
-
'Content-Type': 'application/json',
|
|
40
32
|
Accept: 'application/json',
|
|
33
|
+
'Content-Type': 'application/json',
|
|
41
34
|
},
|
|
42
35
|
});
|
|
43
36
|
// Authentication functions
|
|
@@ -67,50 +60,44 @@ const createAuthenticatedClient = () => {
|
|
|
67
60
|
baseUrl: exports.API_BASE_URL,
|
|
68
61
|
headers: tokenManager.getAccessToken()
|
|
69
62
|
? {
|
|
63
|
+
Accept: 'application/json',
|
|
70
64
|
Authorization: `Bearer ${tokenManager.getAccessToken()}`,
|
|
71
65
|
'Content-Type': 'application/json',
|
|
72
|
-
Accept: 'application/json',
|
|
73
66
|
}
|
|
74
67
|
: {
|
|
75
|
-
'Content-Type': 'application/json',
|
|
76
68
|
Accept: 'application/json',
|
|
69
|
+
'Content-Type': 'application/json',
|
|
77
70
|
},
|
|
78
71
|
});
|
|
79
72
|
// Wrap the client to handle token refresh
|
|
80
73
|
return new Proxy(client, {
|
|
81
|
-
get(target,
|
|
74
|
+
get(target, property) {
|
|
82
75
|
// For HTTP methods (GET, POST, etc.), add token refresh logic
|
|
83
|
-
if (typeof target[
|
|
84
|
-
['
|
|
85
|
-
return (...
|
|
86
|
-
var _a, _b, _c, _d;
|
|
76
|
+
if (typeof target[property] === 'function' &&
|
|
77
|
+
['DELETE', 'GET', 'PATCH', 'POST', 'PUT'].includes(String(property))) {
|
|
78
|
+
return async (...arguments_) => {
|
|
87
79
|
// Check if token is expired before making the request
|
|
88
80
|
if (tokenManager.isTokenExpired() && tokenManager.getRefreshToken()) {
|
|
89
|
-
|
|
81
|
+
await refreshAccessToken(tokenManager);
|
|
90
82
|
}
|
|
91
83
|
// Update the Authorization header with the current token
|
|
92
|
-
if (!
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
args[1].headers.Authorization = `Bearer ${tokenManager.getAccessToken()}`;
|
|
84
|
+
if (!arguments_[1]?.headers?.Authorization && tokenManager.getAccessToken()) {
|
|
85
|
+
if (!arguments_[1])
|
|
86
|
+
arguments_[1] = {};
|
|
87
|
+
if (!arguments_[1].headers)
|
|
88
|
+
arguments_[1].headers = {};
|
|
89
|
+
arguments_[1].headers.Authorization = `Bearer ${tokenManager.getAccessToken()}`;
|
|
99
90
|
}
|
|
100
91
|
// Make the original request
|
|
101
92
|
let result;
|
|
102
93
|
try {
|
|
103
|
-
result =
|
|
94
|
+
result = await target[property](...arguments_);
|
|
104
95
|
}
|
|
105
96
|
catch (requestError) {
|
|
106
|
-
logger_1.logger.debug(`Request error: ${requestError instanceof Error
|
|
107
|
-
? requestError.message
|
|
108
|
-
: String(requestError)}`);
|
|
97
|
+
logger_1.logger.debug(`Request error: ${requestError instanceof Error ? requestError.message : String(requestError)}`);
|
|
109
98
|
return {
|
|
110
99
|
error: {
|
|
111
|
-
message: `Request failed: ${requestError instanceof Error
|
|
112
|
-
? requestError.message
|
|
113
|
-
: String(requestError)}`,
|
|
100
|
+
message: `Request failed: ${requestError instanceof Error ? requestError.message : String(requestError)}`,
|
|
114
101
|
},
|
|
115
102
|
};
|
|
116
103
|
}
|
|
@@ -120,8 +107,7 @@ const createAuthenticatedClient = () => {
|
|
|
120
107
|
let isAuthError = false;
|
|
121
108
|
try {
|
|
122
109
|
// Standard 401 Unauthorized
|
|
123
|
-
if (typeof result.error === 'object' &&
|
|
124
|
-
result.error.status === 401) {
|
|
110
|
+
if (typeof result.error === 'object' && result.error.status === 401) {
|
|
125
111
|
isAuthError = true;
|
|
126
112
|
}
|
|
127
113
|
// OAuth specific errors
|
|
@@ -129,8 +115,8 @@ const createAuthenticatedClient = () => {
|
|
|
129
115
|
(result.error.error.code === 'invalid_token' ||
|
|
130
116
|
result.error.error.code === 'token_expired' ||
|
|
131
117
|
result.error.error.message === 'Invalid API key' ||
|
|
132
|
-
|
|
133
|
-
|
|
118
|
+
result.error.error.message?.toLowerCase().includes('token') ||
|
|
119
|
+
result.error.error.message?.toLowerCase().includes('unauthorized'))) {
|
|
134
120
|
isAuthError = true;
|
|
135
121
|
}
|
|
136
122
|
// Message-based detection as fallback
|
|
@@ -141,29 +127,29 @@ const createAuthenticatedClient = () => {
|
|
|
141
127
|
isAuthError = true;
|
|
142
128
|
}
|
|
143
129
|
}
|
|
144
|
-
catch
|
|
130
|
+
catch {
|
|
145
131
|
// If we can't parse the error structure, do a simple string check
|
|
146
|
-
const
|
|
147
|
-
if (
|
|
148
|
-
|
|
149
|
-
|
|
132
|
+
const errorString = String(result.error);
|
|
133
|
+
if (errorString.toLowerCase().includes('unauthorized') ||
|
|
134
|
+
errorString.toLowerCase().includes('token') ||
|
|
135
|
+
errorString.toLowerCase().includes('auth')) {
|
|
150
136
|
isAuthError = true;
|
|
151
137
|
}
|
|
152
138
|
}
|
|
153
139
|
if (isAuthError && tokenManager.getRefreshToken()) {
|
|
154
140
|
logger_1.logger.debug('Auth error detected, attempting token refresh');
|
|
155
141
|
logger_1.logger.debug(`Error details: ${JSON.stringify(result.error, null, 2)}`);
|
|
156
|
-
const refreshed =
|
|
142
|
+
const refreshed = await refreshAccessToken(tokenManager);
|
|
157
143
|
if (refreshed) {
|
|
158
144
|
logger_1.logger.debug('Token refreshed successfully, retrying request');
|
|
159
145
|
// Update the Authorization header with the new token
|
|
160
|
-
if (!
|
|
161
|
-
|
|
162
|
-
if (!
|
|
163
|
-
|
|
164
|
-
|
|
146
|
+
if (!arguments_[1])
|
|
147
|
+
arguments_[1] = {};
|
|
148
|
+
if (!arguments_[1].headers)
|
|
149
|
+
arguments_[1].headers = {};
|
|
150
|
+
arguments_[1].headers.Authorization = `Bearer ${tokenManager.getAccessToken()}`;
|
|
165
151
|
// Retry the request
|
|
166
|
-
return
|
|
152
|
+
return await target[property](...arguments_);
|
|
167
153
|
}
|
|
168
154
|
else {
|
|
169
155
|
logger_1.logger.debug('Token refresh failed');
|
|
@@ -176,87 +162,81 @@ const createAuthenticatedClient = () => {
|
|
|
176
162
|
}
|
|
177
163
|
}
|
|
178
164
|
return result;
|
|
179
|
-
}
|
|
165
|
+
};
|
|
180
166
|
}
|
|
181
167
|
// For other properties, just return the original
|
|
182
|
-
return target[
|
|
168
|
+
return target[property];
|
|
183
169
|
},
|
|
184
170
|
});
|
|
185
171
|
};
|
|
186
172
|
exports.createAuthenticatedClient = createAuthenticatedClient;
|
|
187
173
|
// Keycloak configuration for token refresh (must match auth-service.ts)
|
|
188
|
-
const KEYCLOAK_URL =
|
|
189
|
-
? 'https://keycloak.stage.berget.ai'
|
|
190
|
-
: 'https://keycloak.berget.ai';
|
|
174
|
+
const KEYCLOAK_URL = isStageMode || isLocalMode ? 'https://keycloak.stage.berget.ai' : 'https://keycloak.berget.ai';
|
|
191
175
|
const KEYCLOAK_REALM = 'berget';
|
|
192
176
|
const KEYCLOAK_CLIENT_ID = 'berget-code';
|
|
193
177
|
// Helper function to refresh the access token
|
|
194
|
-
function refreshAccessToken(tokenManager) {
|
|
195
|
-
|
|
178
|
+
async function refreshAccessToken(tokenManager) {
|
|
179
|
+
try {
|
|
180
|
+
const refreshToken = tokenManager.getRefreshToken();
|
|
181
|
+
if (!refreshToken)
|
|
182
|
+
return false;
|
|
183
|
+
logger_1.logger.debug('Attempting to refresh access token');
|
|
184
|
+
// Refresh directly against Keycloak (berget-code is a public PKCE client)
|
|
196
185
|
try {
|
|
197
|
-
const
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
logger_1.logger.debug(`Token refresh error: HTTP ${response.status} ${response.statusText}`);
|
|
217
|
-
// Check if the refresh token itself is expired or invalid
|
|
218
|
-
if (response.status === 401 || response.status === 403) {
|
|
219
|
-
console.warn(chalk_1.default.yellow('Your refresh token has expired. Please run `berget auth login` again.'));
|
|
220
|
-
// Clear tokens if unauthorized - they're invalid
|
|
221
|
-
tokenManager.clearTokens();
|
|
222
|
-
}
|
|
223
|
-
else {
|
|
224
|
-
console.warn(chalk_1.default.yellow(`Failed to refresh token: ${response.status} ${response.statusText}`));
|
|
225
|
-
}
|
|
226
|
-
return false;
|
|
186
|
+
const response = await fetch(`${KEYCLOAK_URL}/realms/${KEYCLOAK_REALM}/protocol/openid-connect/token`, {
|
|
187
|
+
body: new URLSearchParams({
|
|
188
|
+
client_id: KEYCLOAK_CLIENT_ID,
|
|
189
|
+
grant_type: 'refresh_token',
|
|
190
|
+
refresh_token: refreshToken,
|
|
191
|
+
}),
|
|
192
|
+
headers: {
|
|
193
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
194
|
+
},
|
|
195
|
+
method: 'POST',
|
|
196
|
+
});
|
|
197
|
+
// Handle HTTP errors
|
|
198
|
+
if (!response.ok) {
|
|
199
|
+
logger_1.logger.debug(`Token refresh error: HTTP ${response.status} ${response.statusText}`);
|
|
200
|
+
// Check if the refresh token itself is expired or invalid
|
|
201
|
+
if (response.status === 401 || response.status === 403) {
|
|
202
|
+
console.warn(chalk_1.default.yellow('Your refresh token has expired. Please run `berget auth login` again.'));
|
|
203
|
+
// Clear tokens if unauthorized - they're invalid
|
|
204
|
+
tokenManager.clearTokens();
|
|
227
205
|
}
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
if (!contentType || !contentType.includes('application/json')) {
|
|
231
|
-
console.warn(chalk_1.default.yellow(`Unexpected content type in response: ${contentType}`));
|
|
232
|
-
return false;
|
|
233
|
-
}
|
|
234
|
-
const data = yield response.json();
|
|
235
|
-
// Validate the response data
|
|
236
|
-
if (!data || !data.token) {
|
|
237
|
-
console.warn(chalk_1.default.yellow('Invalid token response. Please run `berget auth login` again.'));
|
|
238
|
-
return false;
|
|
239
|
-
}
|
|
240
|
-
logger_1.logger.debug('Token refreshed successfully');
|
|
241
|
-
// Update the token
|
|
242
|
-
tokenManager.updateAccessToken(data.token, data.expires_in || 3600);
|
|
243
|
-
// If a new refresh token was provided, update that too
|
|
244
|
-
if (data.refresh_token) {
|
|
245
|
-
tokenManager.setTokens(data.token, data.refresh_token, data.expires_in || 3600);
|
|
246
|
-
logger_1.logger.debug('Refresh token also updated');
|
|
206
|
+
else {
|
|
207
|
+
console.warn(chalk_1.default.yellow(`Failed to refresh token: ${response.status} ${response.statusText}`));
|
|
247
208
|
}
|
|
209
|
+
return false;
|
|
248
210
|
}
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
211
|
+
// Parse the response
|
|
212
|
+
const contentType = response.headers.get('content-type');
|
|
213
|
+
if (!contentType || !contentType.includes('application/json')) {
|
|
214
|
+
console.warn(chalk_1.default.yellow(`Unexpected content type in response: ${contentType}`));
|
|
253
215
|
return false;
|
|
254
216
|
}
|
|
255
|
-
|
|
217
|
+
const data = (await response.json());
|
|
218
|
+
// Validate the response data
|
|
219
|
+
if (!data || !data.token) {
|
|
220
|
+
console.warn(chalk_1.default.yellow('Invalid token response. Please run `berget auth login` again.'));
|
|
221
|
+
return false;
|
|
222
|
+
}
|
|
223
|
+
logger_1.logger.debug('Token refreshed successfully');
|
|
224
|
+
// Update the token
|
|
225
|
+
tokenManager.updateAccessToken(data.token, data.expires_in || 3600);
|
|
226
|
+
// If a new refresh token was provided, update that too
|
|
227
|
+
if (data.refresh_token) {
|
|
228
|
+
tokenManager.setTokens(data.token, data.refresh_token, data.expires_in || 3600);
|
|
229
|
+
logger_1.logger.debug('Refresh token also updated');
|
|
230
|
+
}
|
|
256
231
|
}
|
|
257
|
-
catch (
|
|
258
|
-
console.warn(chalk_1.default.yellow(`Failed to refresh
|
|
232
|
+
catch (fetchError) {
|
|
233
|
+
console.warn(chalk_1.default.yellow(`Failed to refresh token: ${fetchError instanceof Error ? fetchError.message : String(fetchError)}`));
|
|
259
234
|
return false;
|
|
260
235
|
}
|
|
261
|
-
|
|
236
|
+
return true;
|
|
237
|
+
}
|
|
238
|
+
catch (error) {
|
|
239
|
+
console.warn(chalk_1.default.yellow(`Failed to refresh authentication token: ${error instanceof Error ? error.message : String(error)}`));
|
|
240
|
+
return false;
|
|
241
|
+
}
|
|
262
242
|
}
|