berget 1.1.0 → 1.3.0
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/-27b-it +0 -0
- package/dist/index.js +47 -1
- package/dist/package.json +35 -0
- package/dist/src/client.js +55 -48
- package/dist/src/commands/api-keys.js +13 -7
- package/dist/src/commands/chat.js +100 -18
- package/dist/src/services/api-key-service.js +6 -16
- package/dist/src/services/chat-service.js +284 -56
- package/dist/src/utils/default-api-key.js +115 -6
- package/dist/src/utils/error-handler.js +4 -4
- package/dist/src/utils/logger.js +160 -0
- package/dist/src/utils/token-manager.js +6 -9
- package/index.ts +52 -1
- package/package.json +3 -2
- package/src/client.ts +83 -81
- package/src/commands/api-keys.ts +17 -7
- package/src/commands/chat.ts +142 -22
- package/src/services/api-key-service.ts +12 -20
- package/src/services/chat-service.ts +407 -87
- package/src/types/api.d.ts +203 -9
- package/src/types/json.d.ts +4 -0
- package/src/utils/default-api-key.ts +124 -6
- package/src/utils/error-handler.ts +4 -4
- package/src/utils/logger.ts +159 -0
- package/src/utils/token-manager.ts +6 -5
- package/tsconfig.json +1 -1
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.logger = exports.Logger = exports.LogLevel = void 0;
|
|
7
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
8
|
+
/**
|
|
9
|
+
* Log levels in order of increasing verbosity
|
|
10
|
+
*/
|
|
11
|
+
var LogLevel;
|
|
12
|
+
(function (LogLevel) {
|
|
13
|
+
LogLevel[LogLevel["NONE"] = 0] = "NONE";
|
|
14
|
+
LogLevel[LogLevel["ERROR"] = 1] = "ERROR";
|
|
15
|
+
LogLevel[LogLevel["WARN"] = 2] = "WARN";
|
|
16
|
+
LogLevel[LogLevel["INFO"] = 3] = "INFO";
|
|
17
|
+
LogLevel[LogLevel["DEBUG"] = 4] = "DEBUG";
|
|
18
|
+
})(LogLevel || (exports.LogLevel = LogLevel = {}));
|
|
19
|
+
/**
|
|
20
|
+
* Logger class for centralized logging with configurable log levels
|
|
21
|
+
*/
|
|
22
|
+
class Logger {
|
|
23
|
+
constructor() {
|
|
24
|
+
this.logLevel = LogLevel.INFO; // Default log level
|
|
25
|
+
// Set log level from environment variable or command line argument
|
|
26
|
+
if (process.env.LOG_LEVEL) {
|
|
27
|
+
this.setLogLevelFromString(process.env.LOG_LEVEL);
|
|
28
|
+
}
|
|
29
|
+
else if (process.argv.includes('--debug')) {
|
|
30
|
+
this.logLevel = LogLevel.DEBUG;
|
|
31
|
+
}
|
|
32
|
+
else if (process.argv.includes('--quiet')) {
|
|
33
|
+
this.logLevel = LogLevel.ERROR;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
static getInstance() {
|
|
37
|
+
if (!Logger.instance) {
|
|
38
|
+
Logger.instance = new Logger();
|
|
39
|
+
}
|
|
40
|
+
return Logger.instance;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Set the log level from a string
|
|
44
|
+
*/
|
|
45
|
+
setLogLevelFromString(level) {
|
|
46
|
+
switch (level.toLowerCase()) {
|
|
47
|
+
case 'none':
|
|
48
|
+
this.logLevel = LogLevel.NONE;
|
|
49
|
+
break;
|
|
50
|
+
case 'error':
|
|
51
|
+
this.logLevel = LogLevel.ERROR;
|
|
52
|
+
break;
|
|
53
|
+
case 'warn':
|
|
54
|
+
this.logLevel = LogLevel.WARN;
|
|
55
|
+
break;
|
|
56
|
+
case 'info':
|
|
57
|
+
this.logLevel = LogLevel.INFO;
|
|
58
|
+
break;
|
|
59
|
+
case 'debug':
|
|
60
|
+
this.logLevel = LogLevel.DEBUG;
|
|
61
|
+
break;
|
|
62
|
+
default:
|
|
63
|
+
// Invalid log level, keep default
|
|
64
|
+
console.warn(`Invalid log level: ${level}. Using default (INFO).`);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Set the log level
|
|
69
|
+
*/
|
|
70
|
+
setLogLevel(level) {
|
|
71
|
+
this.logLevel = level;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Get the current log level
|
|
75
|
+
*/
|
|
76
|
+
getLogLevel() {
|
|
77
|
+
return this.logLevel;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Log a debug message (only shown at DEBUG level)
|
|
81
|
+
*/
|
|
82
|
+
debug(message, ...args) {
|
|
83
|
+
if (this.logLevel >= LogLevel.DEBUG) {
|
|
84
|
+
if (args.length > 0) {
|
|
85
|
+
console.log(chalk_1.default.yellow(`DEBUG: ${message}`), ...args);
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
console.log(chalk_1.default.yellow(`DEBUG: ${message}`));
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Log an info message (shown at INFO level and above)
|
|
94
|
+
*/
|
|
95
|
+
info(message, ...args) {
|
|
96
|
+
if (this.logLevel >= LogLevel.INFO) {
|
|
97
|
+
if (args.length > 0) {
|
|
98
|
+
console.log(chalk_1.default.blue(message), ...args);
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
console.log(chalk_1.default.blue(message));
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Log a warning message (shown at WARN level and above)
|
|
107
|
+
*/
|
|
108
|
+
warn(message, ...args) {
|
|
109
|
+
if (this.logLevel >= LogLevel.WARN) {
|
|
110
|
+
if (args.length > 0) {
|
|
111
|
+
console.log(chalk_1.default.yellow(message), ...args);
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
console.log(chalk_1.default.yellow(message));
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Log an error message (shown at ERROR level and above)
|
|
120
|
+
*/
|
|
121
|
+
error(message, ...args) {
|
|
122
|
+
if (this.logLevel >= LogLevel.ERROR) {
|
|
123
|
+
if (args.length > 0) {
|
|
124
|
+
console.error(chalk_1.default.red(message), ...args);
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
console.error(chalk_1.default.red(message));
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Log a success message (shown at INFO level and above)
|
|
133
|
+
*/
|
|
134
|
+
success(message, ...args) {
|
|
135
|
+
if (this.logLevel >= LogLevel.INFO) {
|
|
136
|
+
if (args.length > 0) {
|
|
137
|
+
console.log(chalk_1.default.green(message), ...args);
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
console.log(chalk_1.default.green(message));
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Log a plain message without color (shown at INFO level and above)
|
|
146
|
+
*/
|
|
147
|
+
log(message, ...args) {
|
|
148
|
+
if (this.logLevel >= LogLevel.INFO) {
|
|
149
|
+
if (args.length > 0) {
|
|
150
|
+
console.log(message, ...args);
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
console.log(message);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
exports.Logger = Logger;
|
|
159
|
+
// Export a singleton instance for easy import
|
|
160
|
+
exports.logger = Logger.getInstance();
|
|
@@ -22,15 +22,12 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
22
22
|
__setModuleDefault(result, mod);
|
|
23
23
|
return result;
|
|
24
24
|
};
|
|
25
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
|
-
};
|
|
28
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
26
|
exports.TokenManager = void 0;
|
|
30
27
|
const fs = __importStar(require("fs"));
|
|
31
28
|
const path = __importStar(require("path"));
|
|
32
29
|
const os = __importStar(require("os"));
|
|
33
|
-
const
|
|
30
|
+
const logger_1 = require("./logger");
|
|
34
31
|
/**
|
|
35
32
|
* Manages authentication tokens including refresh functionality
|
|
36
33
|
*/
|
|
@@ -62,7 +59,7 @@ class TokenManager {
|
|
|
62
59
|
}
|
|
63
60
|
}
|
|
64
61
|
catch (error) {
|
|
65
|
-
|
|
62
|
+
logger_1.logger.error('Failed to load authentication token');
|
|
66
63
|
this.tokenData = null;
|
|
67
64
|
}
|
|
68
65
|
}
|
|
@@ -84,7 +81,7 @@ class TokenManager {
|
|
|
84
81
|
}
|
|
85
82
|
}
|
|
86
83
|
catch (error) {
|
|
87
|
-
|
|
84
|
+
logger_1.logger.error('Failed to save authentication token');
|
|
88
85
|
}
|
|
89
86
|
}
|
|
90
87
|
/**
|
|
@@ -117,14 +114,14 @@ class TokenManager {
|
|
|
117
114
|
// Using a larger buffer to be more proactive about refreshing
|
|
118
115
|
const expirationBuffer = 10 * 60 * 1000; // 10 minutes in milliseconds
|
|
119
116
|
const isExpired = Date.now() + expirationBuffer >= this.tokenData.expires_at;
|
|
120
|
-
if (isExpired
|
|
121
|
-
|
|
117
|
+
if (isExpired) {
|
|
118
|
+
logger_1.logger.debug(`Token expired or expiring soon. Current time: ${new Date().toISOString()}, Expiry: ${new Date(this.tokenData.expires_at).toISOString()}`);
|
|
122
119
|
}
|
|
123
120
|
return isExpired;
|
|
124
121
|
}
|
|
125
122
|
catch (error) {
|
|
126
123
|
// If there's any error checking expiration, assume token is expired
|
|
127
|
-
|
|
124
|
+
logger_1.logger.error(`Error checking token expiration: ${error instanceof Error ? error.message : String(error)}`);
|
|
128
125
|
return true;
|
|
129
126
|
}
|
|
130
127
|
}
|
package/index.ts
CHANGED
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
import { program } from 'commander'
|
|
4
4
|
import { registerCommands } from './src/commands'
|
|
5
5
|
import { checkBergetConfig } from './src/utils/config-checker'
|
|
6
|
+
import chalk from 'chalk'
|
|
7
|
+
import { version } from './package.json'
|
|
6
8
|
|
|
7
9
|
// Set version and description
|
|
8
10
|
program
|
|
@@ -17,7 +19,7 @@ program
|
|
|
17
19
|
__/ |
|
|
18
20
|
|___/ AI on European terms`
|
|
19
21
|
)
|
|
20
|
-
.version(
|
|
22
|
+
.version(version, '-v, --version')
|
|
21
23
|
.option('--local', 'Use local API endpoint (hidden)', false)
|
|
22
24
|
.option('--debug', 'Enable debug output', false)
|
|
23
25
|
|
|
@@ -27,6 +29,55 @@ registerCommands(program)
|
|
|
27
29
|
// Check for .bergetconfig if not running a command
|
|
28
30
|
if (process.argv.length <= 2) {
|
|
29
31
|
checkBergetConfig()
|
|
32
|
+
|
|
33
|
+
// Show helpful welcome message
|
|
34
|
+
console.log(chalk.blue('\nWelcome to the Berget CLI!'));
|
|
35
|
+
console.log(chalk.blue('Common commands:'));
|
|
36
|
+
console.log(chalk.blue(` ${chalk.bold('berget auth login')} - Log in to Berget`));
|
|
37
|
+
console.log(chalk.blue(` ${chalk.bold('berget models list')} - List available AI models`));
|
|
38
|
+
console.log(chalk.blue(` ${chalk.bold('berget chat run')} - Start a chat session`));
|
|
39
|
+
console.log(chalk.blue(` ${chalk.bold('berget api-keys list')} - List your API keys`));
|
|
40
|
+
console.log(chalk.blue(`\nRun ${chalk.bold('berget --help')} for a complete list of commands.`));
|
|
30
41
|
}
|
|
31
42
|
|
|
43
|
+
// Add helpful suggestions for common command mistakes
|
|
44
|
+
const commonMistakes: Record<string, string> = {
|
|
45
|
+
'login': 'auth login',
|
|
46
|
+
'logout': 'auth logout',
|
|
47
|
+
'whoami': 'auth whoami',
|
|
48
|
+
'list-models': 'models list',
|
|
49
|
+
'list-keys': 'api-keys list',
|
|
50
|
+
'create-key': 'api-keys create',
|
|
51
|
+
'list-clusters': 'clusters list',
|
|
52
|
+
'usage': 'billing usage'
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
// Add error handler for unknown commands
|
|
56
|
+
program.on('command:*', (operands) => {
|
|
57
|
+
const unknownCommand = operands[0] as string;
|
|
58
|
+
console.error(chalk.red(`Error: unknown command '${unknownCommand}'`));
|
|
59
|
+
|
|
60
|
+
// Check if this is a known mistake and suggest the correct command
|
|
61
|
+
if (unknownCommand in commonMistakes) {
|
|
62
|
+
console.log(chalk.yellow(`Did you mean? ${chalk.bold(`berget ${commonMistakes[unknownCommand]}`)}`));
|
|
63
|
+
} else {
|
|
64
|
+
// Try to find similar commands
|
|
65
|
+
const availableCommands = program.commands.map(cmd => cmd.name());
|
|
66
|
+
const similarCommands = availableCommands.filter(cmd =>
|
|
67
|
+
cmd.includes(unknownCommand) || unknownCommand.includes(cmd)
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
if (similarCommands.length > 0) {
|
|
71
|
+
console.log(chalk.yellow('Similar commands:'));
|
|
72
|
+
similarCommands.forEach(cmd => {
|
|
73
|
+
console.log(chalk.yellow(` ${chalk.bold(`berget ${cmd}`)}`));
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
console.log(chalk.blue('\nRun `berget --help` for a list of available commands.'));
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
process.exit(1);
|
|
81
|
+
});
|
|
82
|
+
|
|
32
83
|
program.parse(process.argv)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "berget",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"bin": {
|
|
6
6
|
"berget": "dist/index.js"
|
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
"fs-extra": "^11.3.0",
|
|
30
30
|
"open": "^9.1.0",
|
|
31
31
|
"openapi-fetch": "^0.9.1",
|
|
32
|
-
"openapi-typescript": "^6.7.4"
|
|
32
|
+
"openapi-typescript": "^6.7.4",
|
|
33
|
+
"readline": "^1.3.0"
|
|
33
34
|
}
|
|
34
35
|
}
|
package/src/client.ts
CHANGED
|
@@ -5,16 +5,17 @@ import * as path from 'path'
|
|
|
5
5
|
import * as os from 'os'
|
|
6
6
|
import chalk from 'chalk'
|
|
7
7
|
import { TokenManager } from './utils/token-manager'
|
|
8
|
+
import { logger } from './utils/logger'
|
|
8
9
|
|
|
9
10
|
// API Base URL
|
|
10
11
|
// Use --local flag to test against local API
|
|
11
12
|
const isLocalMode = process.argv.includes('--local')
|
|
12
|
-
const API_BASE_URL =
|
|
13
|
+
export const API_BASE_URL =
|
|
13
14
|
process.env.BERGET_API_URL ||
|
|
14
15
|
(isLocalMode ? 'http://localhost:3000' : 'https://api.berget.ai')
|
|
15
16
|
|
|
16
|
-
if (isLocalMode && !process.env.BERGET_API_URL
|
|
17
|
-
|
|
17
|
+
if (isLocalMode && !process.env.BERGET_API_URL) {
|
|
18
|
+
logger.debug('Using local API endpoint: http://localhost:3000')
|
|
18
19
|
}
|
|
19
20
|
|
|
20
21
|
// Create a typed client for the Berget API
|
|
@@ -50,11 +51,9 @@ export const clearAuthToken = (): void => {
|
|
|
50
51
|
export const createAuthenticatedClient = () => {
|
|
51
52
|
const tokenManager = TokenManager.getInstance()
|
|
52
53
|
|
|
53
|
-
if (!tokenManager.getAccessToken()
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
'No authentication token found. Please run `berget auth login` first.'
|
|
57
|
-
)
|
|
54
|
+
if (!tokenManager.getAccessToken()) {
|
|
55
|
+
logger.debug(
|
|
56
|
+
'No authentication token found. Please run `berget auth login` first.'
|
|
58
57
|
)
|
|
59
58
|
}
|
|
60
59
|
|
|
@@ -88,7 +87,10 @@ export const createAuthenticatedClient = () => {
|
|
|
88
87
|
}
|
|
89
88
|
|
|
90
89
|
// Update the Authorization header with the current token
|
|
91
|
-
if (
|
|
90
|
+
if (
|
|
91
|
+
!args[1]?.headers?.Authorization &&
|
|
92
|
+
tokenManager.getAccessToken()
|
|
93
|
+
) {
|
|
92
94
|
if (!args[1]) args[1] = {}
|
|
93
95
|
if (!args[1].headers) args[1].headers = {}
|
|
94
96
|
args[1].headers.Authorization = `Bearer ${tokenManager.getAccessToken()}`
|
|
@@ -101,17 +103,13 @@ export const createAuthenticatedClient = () => {
|
|
|
101
103
|
...args
|
|
102
104
|
)
|
|
103
105
|
} catch (requestError) {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
}`
|
|
112
|
-
)
|
|
113
|
-
)
|
|
114
|
-
}
|
|
106
|
+
logger.debug(
|
|
107
|
+
`Request error: ${
|
|
108
|
+
requestError instanceof Error
|
|
109
|
+
? requestError.message
|
|
110
|
+
: String(requestError)
|
|
111
|
+
}`
|
|
112
|
+
)
|
|
115
113
|
return {
|
|
116
114
|
error: {
|
|
117
115
|
message: `Request failed: ${
|
|
@@ -126,49 +124,59 @@ export const createAuthenticatedClient = () => {
|
|
|
126
124
|
// If we get an auth error, try to refresh the token and retry
|
|
127
125
|
if (result.error) {
|
|
128
126
|
// Detect various forms of authentication errors
|
|
129
|
-
|
|
127
|
+
let isAuthError = false
|
|
128
|
+
|
|
129
|
+
try {
|
|
130
130
|
// Standard 401 Unauthorized
|
|
131
|
-
(
|
|
131
|
+
if (
|
|
132
|
+
typeof result.error === 'object' &&
|
|
133
|
+
result.error.status === 401
|
|
134
|
+
) {
|
|
135
|
+
isAuthError = true
|
|
136
|
+
}
|
|
132
137
|
// OAuth specific errors
|
|
133
|
-
(
|
|
138
|
+
else if (
|
|
139
|
+
result.error.error &&
|
|
134
140
|
(result.error.error.code === 'invalid_token' ||
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
141
|
+
result.error.error.code === 'token_expired' ||
|
|
142
|
+
result.error.error.message === 'Invalid API key' ||
|
|
143
|
+
result.error.error.message?.toLowerCase().includes('token') ||
|
|
144
|
+
result.error.error.message
|
|
145
|
+
?.toLowerCase()
|
|
146
|
+
.includes('unauthorized'))
|
|
147
|
+
) {
|
|
148
|
+
isAuthError = true
|
|
149
|
+
}
|
|
139
150
|
// Message-based detection as fallback
|
|
140
|
-
|
|
151
|
+
else if (
|
|
152
|
+
typeof result.error === 'string' &&
|
|
141
153
|
(result.error.toLowerCase().includes('unauthorized') ||
|
|
142
|
-
|
|
143
|
-
|
|
154
|
+
result.error.toLowerCase().includes('token') ||
|
|
155
|
+
result.error.toLowerCase().includes('auth'))
|
|
156
|
+
) {
|
|
157
|
+
isAuthError = true
|
|
158
|
+
}
|
|
159
|
+
} catch (parseError) {
|
|
160
|
+
// If we can't parse the error structure, do a simple string check
|
|
161
|
+
const errorStr = String(result.error)
|
|
162
|
+
if (
|
|
163
|
+
errorStr.toLowerCase().includes('unauthorized') ||
|
|
164
|
+
errorStr.toLowerCase().includes('token') ||
|
|
165
|
+
errorStr.toLowerCase().includes('auth')
|
|
166
|
+
) {
|
|
167
|
+
isAuthError = true
|
|
168
|
+
}
|
|
169
|
+
}
|
|
144
170
|
|
|
145
171
|
if (isAuthError && tokenManager.getRefreshToken()) {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
)
|
|
151
|
-
)
|
|
152
|
-
console.log(
|
|
153
|
-
chalk.yellow(
|
|
154
|
-
`DEBUG: Error details: ${JSON.stringify(
|
|
155
|
-
result.error,
|
|
156
|
-
null,
|
|
157
|
-
2
|
|
158
|
-
)}`
|
|
159
|
-
)
|
|
160
|
-
)
|
|
161
|
-
}
|
|
172
|
+
logger.debug('Auth error detected, attempting token refresh')
|
|
173
|
+
logger.debug(
|
|
174
|
+
`Error details: ${JSON.stringify(result.error, null, 2)}`
|
|
175
|
+
)
|
|
162
176
|
|
|
163
177
|
const refreshed = await refreshAccessToken(tokenManager)
|
|
164
178
|
if (refreshed) {
|
|
165
|
-
|
|
166
|
-
console.log(
|
|
167
|
-
chalk.green(
|
|
168
|
-
'DEBUG: Token refreshed successfully, retrying request'
|
|
169
|
-
)
|
|
170
|
-
)
|
|
171
|
-
}
|
|
179
|
+
logger.debug('Token refreshed successfully, retrying request')
|
|
172
180
|
|
|
173
181
|
// Update the Authorization header with the new token
|
|
174
182
|
if (!args[1]) args[1] = {}
|
|
@@ -180,13 +188,12 @@ export const createAuthenticatedClient = () => {
|
|
|
180
188
|
...args
|
|
181
189
|
)
|
|
182
190
|
} else {
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
}
|
|
186
|
-
|
|
191
|
+
logger.debug('Token refresh failed')
|
|
192
|
+
|
|
187
193
|
// Add a more helpful error message for users
|
|
188
194
|
if (typeof result.error === 'object') {
|
|
189
|
-
result.error.userMessage =
|
|
195
|
+
result.error.userMessage =
|
|
196
|
+
'Your session has expired. Please run `berget auth login` to log in again.'
|
|
190
197
|
}
|
|
191
198
|
}
|
|
192
199
|
}
|
|
@@ -210,9 +217,7 @@ async function refreshAccessToken(
|
|
|
210
217
|
const refreshToken = tokenManager.getRefreshToken()
|
|
211
218
|
if (!refreshToken) return false
|
|
212
219
|
|
|
213
|
-
|
|
214
|
-
console.log(chalk.yellow('DEBUG: Attempting to refresh access token'))
|
|
215
|
-
}
|
|
220
|
+
logger.debug('Attempting to refresh access token')
|
|
216
221
|
|
|
217
222
|
// Use fetch directly since this endpoint might not be in the OpenAPI spec
|
|
218
223
|
try {
|
|
@@ -223,15 +228,13 @@ async function refreshAccessToken(
|
|
|
223
228
|
Accept: 'application/json',
|
|
224
229
|
},
|
|
225
230
|
body: JSON.stringify({ refresh_token: refreshToken }),
|
|
226
|
-
})
|
|
231
|
+
})
|
|
227
232
|
|
|
228
233
|
// Handle HTTP errors
|
|
229
234
|
if (!response.ok) {
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
)
|
|
234
|
-
}
|
|
235
|
+
logger.debug(
|
|
236
|
+
`Token refresh error: HTTP ${response.status} ${response.statusText}`
|
|
237
|
+
)
|
|
235
238
|
|
|
236
239
|
// Check if the refresh token itself is expired or invalid
|
|
237
240
|
if (response.status === 401 || response.status === 403) {
|
|
@@ -273,34 +276,33 @@ async function refreshAccessToken(
|
|
|
273
276
|
return false
|
|
274
277
|
}
|
|
275
278
|
|
|
276
|
-
|
|
277
|
-
console.log(chalk.green('DEBUG: Token refreshed successfully'))
|
|
278
|
-
}
|
|
279
|
+
logger.debug('Token refreshed successfully')
|
|
279
280
|
|
|
280
281
|
// Update the token
|
|
281
|
-
tokenManager.updateAccessToken(
|
|
282
|
-
|
|
283
|
-
data.expires_in || 3600
|
|
284
|
-
)
|
|
285
|
-
|
|
282
|
+
tokenManager.updateAccessToken(data.token, data.expires_in || 3600)
|
|
283
|
+
|
|
286
284
|
// If a new refresh token was provided, update that too
|
|
287
285
|
if (data.refresh_token) {
|
|
288
|
-
tokenManager.setTokens(
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
286
|
+
tokenManager.setTokens(
|
|
287
|
+
data.token,
|
|
288
|
+
data.refresh_token,
|
|
289
|
+
data.expires_in || 3600
|
|
290
|
+
)
|
|
291
|
+
logger.debug('Refresh token also updated')
|
|
292
292
|
}
|
|
293
293
|
} catch (fetchError) {
|
|
294
294
|
console.warn(
|
|
295
295
|
chalk.yellow(
|
|
296
296
|
`Failed to refresh token: ${
|
|
297
|
-
fetchError instanceof Error
|
|
297
|
+
fetchError instanceof Error
|
|
298
|
+
? fetchError.message
|
|
299
|
+
: String(fetchError)
|
|
298
300
|
}`
|
|
299
301
|
)
|
|
300
302
|
)
|
|
301
303
|
return false
|
|
302
304
|
}
|
|
303
|
-
|
|
305
|
+
|
|
304
306
|
return true
|
|
305
307
|
} catch (error) {
|
|
306
308
|
console.warn(
|
package/src/commands/api-keys.ts
CHANGED
|
@@ -50,10 +50,15 @@ export function registerApiKeyCommands(program: Command): void {
|
|
|
50
50
|
? chalk.green('● Active')
|
|
51
51
|
: chalk.red('● Inactive')
|
|
52
52
|
|
|
53
|
+
// Format the prefix to ensure it's not too long
|
|
54
|
+
const prefixStr = key.prefix.length > 12
|
|
55
|
+
? key.prefix.substring(0, 12) + '...'
|
|
56
|
+
: key.prefix
|
|
57
|
+
|
|
53
58
|
console.log(
|
|
54
59
|
String(key.id).padEnd(10) +
|
|
55
60
|
key.name.padEnd(25) +
|
|
56
|
-
|
|
61
|
+
prefixStr.padEnd(15) +
|
|
57
62
|
status.padEnd(12) +
|
|
58
63
|
key.created.substring(0, 10).padEnd(12) +
|
|
59
64
|
lastUsed
|
|
@@ -318,10 +323,15 @@ export function registerApiKeyCommands(program: Command): void {
|
|
|
318
323
|
|
|
319
324
|
// Save the default API key
|
|
320
325
|
const defaultApiKeyManager = DefaultApiKeyManager.getInstance()
|
|
326
|
+
|
|
327
|
+
// We need to rotate the key to get the actual key value
|
|
328
|
+
const rotatedKey = await apiKeyService.rotate(id)
|
|
329
|
+
|
|
321
330
|
defaultApiKeyManager.setDefaultApiKey(
|
|
322
331
|
id,
|
|
323
332
|
selectedKey.name,
|
|
324
|
-
selectedKey.prefix
|
|
333
|
+
selectedKey.prefix,
|
|
334
|
+
rotatedKey.key
|
|
325
335
|
)
|
|
326
336
|
|
|
327
337
|
console.log(chalk.green(`✓ API key "${selectedKey.name}" set as default for chat commands`))
|
|
@@ -339,9 +349,9 @@ export function registerApiKeyCommands(program: Command): void {
|
|
|
339
349
|
.action(() => {
|
|
340
350
|
try {
|
|
341
351
|
const defaultApiKeyManager = DefaultApiKeyManager.getInstance()
|
|
342
|
-
const
|
|
352
|
+
const defaultApiKeyData = defaultApiKeyManager.getDefaultApiKeyData()
|
|
343
353
|
|
|
344
|
-
if (!
|
|
354
|
+
if (!defaultApiKeyData) {
|
|
345
355
|
console.log(chalk.yellow('No default API key set'))
|
|
346
356
|
console.log('')
|
|
347
357
|
console.log('To set a default API key, run:')
|
|
@@ -351,9 +361,9 @@ export function registerApiKeyCommands(program: Command): void {
|
|
|
351
361
|
|
|
352
362
|
console.log(chalk.bold('Default API key:'))
|
|
353
363
|
console.log('')
|
|
354
|
-
console.log(`${chalk.dim('ID:')} ${
|
|
355
|
-
console.log(`${chalk.dim('Name:')} ${
|
|
356
|
-
console.log(`${chalk.dim('Prefix:')} ${
|
|
364
|
+
console.log(`${chalk.dim('ID:')} ${defaultApiKeyData.id}`)
|
|
365
|
+
console.log(`${chalk.dim('Name:')} ${defaultApiKeyData.name}`)
|
|
366
|
+
console.log(`${chalk.dim('Prefix:')} ${defaultApiKeyData.prefix}`)
|
|
357
367
|
console.log('')
|
|
358
368
|
console.log(chalk.dim('This API key will be used by default when running chat commands'))
|
|
359
369
|
console.log(chalk.dim('You can override it with --api-key or --api-key-id options'))
|