berget 2.0.4 ā 2.0.6
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/dist/index.js +3 -9
- package/dist/package.json +1 -1
- package/dist/src/commands/api-keys.js +67 -20
- package/dist/src/commands/chat.js +6 -6
- package/dist/src/utils/error-handler.js +98 -22
- package/index.ts +3 -31
- package/package.json +1 -1
- package/src/commands/api-keys.ts +66 -23
- package/src/commands/chat.ts +6 -6
- package/src/utils/error-handler.ts +120 -23
package/dist/index.js
CHANGED
|
@@ -31,15 +31,9 @@ Version: ${package_json_1.version}`)
|
|
|
31
31
|
// Check for .bergetconfig if not running a command
|
|
32
32
|
if (process.argv.length <= 2) {
|
|
33
33
|
(0, config_checker_1.checkBergetConfig)();
|
|
34
|
-
// Show
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
console.log(chalk_1.default.blue(` ${chalk_1.default.bold('berget auth login')} - Log in to Berget`));
|
|
38
|
-
console.log(chalk_1.default.blue(` ${chalk_1.default.bold('berget models list')} - List available AI models`));
|
|
39
|
-
console.log(chalk_1.default.blue(` ${chalk_1.default.bold('berget chat run')} - Start a chat session`));
|
|
40
|
-
console.log(chalk_1.default.blue(` ${chalk_1.default.bold('berget code init')} - Initialize AI coding assistant`));
|
|
41
|
-
console.log(chalk_1.default.blue(` ${chalk_1.default.bold('berget api-keys list')} - List your API keys`));
|
|
42
|
-
console.log(chalk_1.default.blue(`\nRun ${chalk_1.default.bold('berget --help')} for a complete list of commands.`));
|
|
34
|
+
// Show the full help (including logo and commands)
|
|
35
|
+
commander_1.program.outputHelp();
|
|
36
|
+
process.exit(0);
|
|
43
37
|
}
|
|
44
38
|
// Add helpful suggestions for common command mistakes
|
|
45
39
|
const commonMistakes = {
|
package/dist/package.json
CHANGED
|
@@ -17,6 +17,41 @@ const chalk_1 = __importDefault(require("chalk"));
|
|
|
17
17
|
const api_key_service_1 = require("../services/api-key-service");
|
|
18
18
|
const error_handler_1 = require("../utils/error-handler");
|
|
19
19
|
const default_api_key_1 = require("../utils/default-api-key");
|
|
20
|
+
// Helper functions for better date formatting
|
|
21
|
+
function formatDate(dateString) {
|
|
22
|
+
const date = new Date(dateString);
|
|
23
|
+
const now = new Date();
|
|
24
|
+
const diffTime = Math.abs(now.getTime() - date.getTime());
|
|
25
|
+
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
|
|
26
|
+
if (diffDays === 0)
|
|
27
|
+
return chalk_1.default.green('Today');
|
|
28
|
+
if (diffDays === 1)
|
|
29
|
+
return chalk_1.default.yellow('Yesterday');
|
|
30
|
+
if (diffDays < 7)
|
|
31
|
+
return chalk_1.default.yellow(`${diffDays} days ago`);
|
|
32
|
+
if (diffDays < 30)
|
|
33
|
+
return chalk_1.default.blue(`${Math.floor(diffDays / 7)} weeks ago`);
|
|
34
|
+
if (diffDays < 365)
|
|
35
|
+
return chalk_1.default.magenta(`${Math.floor(diffDays / 30)} months ago`);
|
|
36
|
+
return chalk_1.default.gray(`${Math.floor(diffDays / 365)} years ago`);
|
|
37
|
+
}
|
|
38
|
+
function formatLastUsed(dateString) {
|
|
39
|
+
const date = new Date(dateString);
|
|
40
|
+
const now = new Date();
|
|
41
|
+
const diffTime = Math.abs(now.getTime() - date.getTime());
|
|
42
|
+
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
|
|
43
|
+
if (diffDays === 0)
|
|
44
|
+
return chalk_1.default.green('Today');
|
|
45
|
+
if (diffDays === 1)
|
|
46
|
+
return chalk_1.default.yellow('Yesterday');
|
|
47
|
+
if (diffDays < 7)
|
|
48
|
+
return chalk_1.default.yellow(`${diffDays} days ago`);
|
|
49
|
+
if (diffDays < 30)
|
|
50
|
+
return chalk_1.default.blue(`${Math.floor(diffDays / 7)} weeks ago`);
|
|
51
|
+
if (diffDays < 365)
|
|
52
|
+
return chalk_1.default.magenta(`${Math.floor(diffDays / 30)} months ago`);
|
|
53
|
+
return chalk_1.default.gray(`${Math.floor(diffDays / 365)} years ago`);
|
|
54
|
+
}
|
|
20
55
|
/**
|
|
21
56
|
* Register API key commands
|
|
22
57
|
*/
|
|
@@ -35,34 +70,46 @@ function registerApiKeyCommands(program) {
|
|
|
35
70
|
console.log(chalk_1.default.yellow('No API keys found. Create one with `berget api-key create --name <name>`'));
|
|
36
71
|
return;
|
|
37
72
|
}
|
|
38
|
-
console.log(chalk_1.default.bold('Your API keys:'));
|
|
73
|
+
console.log(chalk_1.default.bold('š Your API keys:'));
|
|
39
74
|
console.log('');
|
|
40
|
-
// Create a table
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
75
|
+
// Create a more readable table with better spacing and colors
|
|
76
|
+
const idWidth = 10;
|
|
77
|
+
const nameWidth = 30;
|
|
78
|
+
const prefixWidth = 20;
|
|
79
|
+
const statusWidth = 12;
|
|
80
|
+
const createdWidth = 12;
|
|
81
|
+
const usedWidth = 15;
|
|
82
|
+
console.log(chalk_1.default.dim('ID'.padEnd(idWidth)) +
|
|
83
|
+
chalk_1.default.dim('NAME'.padEnd(nameWidth)) +
|
|
84
|
+
chalk_1.default.dim('PREFIX'.padEnd(prefixWidth)) +
|
|
85
|
+
chalk_1.default.dim('STATUS'.padEnd(statusWidth)) +
|
|
86
|
+
chalk_1.default.dim('CREATED'.padEnd(createdWidth)) +
|
|
46
87
|
chalk_1.default.dim('LAST USED'));
|
|
47
|
-
console.log(chalk_1.default.dim('ā'.repeat(
|
|
88
|
+
console.log(chalk_1.default.dim('ā'.repeat(idWidth + nameWidth + prefixWidth + statusWidth + createdWidth + usedWidth + 5)));
|
|
48
89
|
keys.forEach((key) => {
|
|
49
90
|
const lastUsed = key.lastUsed
|
|
50
|
-
? key.lastUsed
|
|
51
|
-
: 'Never';
|
|
91
|
+
? formatLastUsed(key.lastUsed)
|
|
92
|
+
: chalk_1.default.yellow('Never used');
|
|
52
93
|
const status = key.active
|
|
53
94
|
? chalk_1.default.green('ā Active')
|
|
54
95
|
: chalk_1.default.red('ā Inactive');
|
|
55
96
|
// Show only first 8 characters of ID for easier reading
|
|
56
|
-
const shortId = String(key.id).substring(0, 8);
|
|
57
|
-
// Format the prefix
|
|
58
|
-
const prefixStr = key.prefix.length >
|
|
59
|
-
? key.prefix.substring(0,
|
|
60
|
-
: key.prefix;
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
97
|
+
const shortId = chalk_1.default.cyan(String(key.id).substring(0, 8));
|
|
98
|
+
// Format the prefix with better truncation
|
|
99
|
+
const prefixStr = key.prefix.length > prefixWidth
|
|
100
|
+
? key.prefix.substring(0, prefixWidth - 3) + '...'
|
|
101
|
+
: chalk_1.default.gray(key.prefix);
|
|
102
|
+
// Truncate name if too long
|
|
103
|
+
const nameStr = key.name.length > nameWidth
|
|
104
|
+
? key.name.substring(0, nameWidth - 3) + '...'
|
|
105
|
+
: key.name;
|
|
106
|
+
// Format created date
|
|
107
|
+
const createdDate = formatDate(key.created);
|
|
108
|
+
console.log(shortId.padEnd(idWidth) +
|
|
109
|
+
nameStr.padEnd(nameWidth) +
|
|
110
|
+
prefixStr.padEnd(prefixWidth) +
|
|
111
|
+
status.padEnd(statusWidth) +
|
|
112
|
+
createdDate.padEnd(createdWidth) +
|
|
66
113
|
lastUsed);
|
|
67
114
|
});
|
|
68
115
|
console.log('');
|
|
@@ -56,15 +56,15 @@ function registerChatCommands(program) {
|
|
|
56
56
|
chat
|
|
57
57
|
.command(command_structure_1.SUBCOMMANDS.CHAT.RUN)
|
|
58
58
|
.description('Run a chat session with a specified model')
|
|
59
|
-
.argument('[model]', 'Model to use (default: openai/gpt-oss)')
|
|
60
59
|
.argument('[message]', 'Message to send directly (skips interactive mode)')
|
|
61
|
-
.option('-
|
|
60
|
+
.option('-m, --model <model>', 'Model to use (default: deepseek-r1)')
|
|
61
|
+
.option('--no-reasoning', 'Disable reasoning mode (adds </think> to messages)')
|
|
62
62
|
.option('-t, --temperature <temp>', 'Temperature (0-1)', parseFloat)
|
|
63
|
-
.option('
|
|
63
|
+
.option('--max-tokens <tokens>', 'Maximum tokens to generate', parseInt)
|
|
64
64
|
.option('-k, --api-key <key>', 'API key to use for this chat session')
|
|
65
65
|
.option('--api-key-id <id>', 'ID of the API key to use from your saved keys')
|
|
66
66
|
.option('--no-stream', 'Disable streaming (streaming is enabled by default)')
|
|
67
|
-
.action((
|
|
67
|
+
.action((message, options) => __awaiter(this, void 0, void 0, function* () {
|
|
68
68
|
var _a, e_1, _b, _c;
|
|
69
69
|
try {
|
|
70
70
|
const chatService = chat_service_1.ChatService.getInstance();
|
|
@@ -226,7 +226,7 @@ function registerChatCommands(program) {
|
|
|
226
226
|
try {
|
|
227
227
|
// Call the API
|
|
228
228
|
const completionOptions = {
|
|
229
|
-
model: model || 'openai/gpt-oss',
|
|
229
|
+
model: options.model || 'openai/gpt-oss',
|
|
230
230
|
messages: messages,
|
|
231
231
|
temperature: options.temperature !== undefined ? options.temperature : 0.7,
|
|
232
232
|
max_tokens: options.maxTokens || 4096,
|
|
@@ -334,7 +334,7 @@ function registerChatCommands(program) {
|
|
|
334
334
|
try {
|
|
335
335
|
// Call the API
|
|
336
336
|
const completionOptions = {
|
|
337
|
-
model: model || 'openai/gpt-oss',
|
|
337
|
+
model: options.model || 'openai/gpt-oss',
|
|
338
338
|
messages: messages,
|
|
339
339
|
temperature: options.temperature !== undefined ? options.temperature : 0.7,
|
|
340
340
|
max_tokens: options.maxTokens || 4096,
|
|
@@ -9,44 +9,120 @@ const chalk_1 = __importDefault(require("chalk"));
|
|
|
9
9
|
* Formats and prints error messages in a consistent way
|
|
10
10
|
*/
|
|
11
11
|
function handleError(message, error) {
|
|
12
|
-
console.error(chalk_1.default.red(
|
|
12
|
+
console.error(chalk_1.default.red(`ā Error: ${message}`));
|
|
13
|
+
let errorDetails = '';
|
|
14
|
+
let errorCode = '';
|
|
15
|
+
let errorType = '';
|
|
13
16
|
// If the error is a string (like JSON.stringify(error))
|
|
14
17
|
if (typeof error === 'string') {
|
|
15
18
|
try {
|
|
16
19
|
// Try to parse it as JSON
|
|
17
20
|
const parsedError = JSON.parse(error);
|
|
18
21
|
if (parsedError.error) {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}
|
|
22
|
+
errorDetails = parsedError.error.message || parsedError.error;
|
|
23
|
+
errorCode = parsedError.error.code || parsedError.code;
|
|
24
|
+
errorType = parsedError.error.type || '';
|
|
23
25
|
}
|
|
24
26
|
else {
|
|
25
|
-
|
|
27
|
+
errorDetails = error;
|
|
26
28
|
}
|
|
27
29
|
}
|
|
28
30
|
catch (_a) {
|
|
29
31
|
// If it's not valid JSON, just print the string
|
|
30
|
-
|
|
32
|
+
errorDetails = error;
|
|
31
33
|
}
|
|
32
34
|
}
|
|
33
35
|
else if (error && error.message) {
|
|
34
36
|
// If it's an Error object
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
if ((typeof error === 'string' &&
|
|
39
|
-
(error.includes('Unauthorized') ||
|
|
40
|
-
error.includes('Authentication failed'))) ||
|
|
41
|
-
(error &&
|
|
42
|
-
error.message &&
|
|
43
|
-
(error.message.includes('Unauthorized') ||
|
|
44
|
-
error.message.includes('Authentication failed'))) ||
|
|
45
|
-
(error &&
|
|
46
|
-
error.code &&
|
|
47
|
-
(error.code === 401 || error.code === 'AUTH_FAILED'))) {
|
|
48
|
-
console.error(chalk_1.default.yellow('\nYou need to be logged in to use this command.'));
|
|
49
|
-
console.error(chalk_1.default.yellow('Run `berget auth login` to authenticate.'));
|
|
37
|
+
errorDetails = error.message;
|
|
38
|
+
errorCode = error.code;
|
|
39
|
+
errorType = error.type;
|
|
50
40
|
}
|
|
41
|
+
// Print error details
|
|
42
|
+
if (errorDetails) {
|
|
43
|
+
console.error(chalk_1.default.dim(`š Details: ${errorDetails}`));
|
|
44
|
+
}
|
|
45
|
+
if (errorCode) {
|
|
46
|
+
console.error(chalk_1.default.dim(`š¢ Code: ${errorCode}`));
|
|
47
|
+
}
|
|
48
|
+
// Provide helpful troubleshooting based on error type
|
|
49
|
+
provideTroubleshootingTips(errorType, errorCode, errorDetails);
|
|
51
50
|
}
|
|
52
51
|
exports.handleError = handleError;
|
|
52
|
+
/**
|
|
53
|
+
* Provides helpful troubleshooting tips based on error type
|
|
54
|
+
*/
|
|
55
|
+
function provideTroubleshootingTips(errorType, errorCode, errorDetails) {
|
|
56
|
+
console.error(chalk_1.default.blue('\nš” Troubleshooting tips:'));
|
|
57
|
+
// Authentication errors
|
|
58
|
+
if (errorType === 'authentication_error' ||
|
|
59
|
+
errorCode === 'AUTH_FAILED' ||
|
|
60
|
+
(errorDetails === null || errorDetails === void 0 ? void 0 : errorDetails.includes('Unauthorized')) ||
|
|
61
|
+
(errorDetails === null || errorDetails === void 0 ? void 0 : errorDetails.includes('Authentication failed'))) {
|
|
62
|
+
console.error(chalk_1.default.yellow(' š Authentication issue detected:'));
|
|
63
|
+
console.error(chalk_1.default.white(' ⢠Run `berget auth login` to log in'));
|
|
64
|
+
console.error(chalk_1.default.white(' ⢠Check if your session has expired'));
|
|
65
|
+
console.error(chalk_1.default.white(' ⢠Verify you have the correct permissions'));
|
|
66
|
+
}
|
|
67
|
+
// Network/connection errors
|
|
68
|
+
if ((errorDetails === null || errorDetails === void 0 ? void 0 : errorDetails.includes('fetch failed')) ||
|
|
69
|
+
(errorDetails === null || errorDetails === void 0 ? void 0 : errorDetails.includes('ECONNREFUSED')) ||
|
|
70
|
+
(errorDetails === null || errorDetails === void 0 ? void 0 : errorDetails.includes('ENOTFOUND')) ||
|
|
71
|
+
(errorDetails === null || errorDetails === void 0 ? void 0 : errorDetails.includes('network'))) {
|
|
72
|
+
console.error(chalk_1.default.yellow(' š Network issue detected:'));
|
|
73
|
+
console.error(chalk_1.default.white(' ⢠Check your internet connection'));
|
|
74
|
+
console.error(chalk_1.default.white(' ⢠Verify you can reach api.berget.ai'));
|
|
75
|
+
console.error(chalk_1.default.white(' ⢠Try again in a few minutes'));
|
|
76
|
+
console.error(chalk_1.default.white(' ⢠Check if any firewall is blocking the request'));
|
|
77
|
+
}
|
|
78
|
+
// API key errors
|
|
79
|
+
if ((errorCode === null || errorCode === void 0 ? void 0 : errorCode.includes('API_KEY')) ||
|
|
80
|
+
(errorDetails === null || errorDetails === void 0 ? void 0 : errorDetails.includes('API key')) ||
|
|
81
|
+
errorType === 'invalid_request_error') {
|
|
82
|
+
console.error(chalk_1.default.yellow(' š API key issue detected:'));
|
|
83
|
+
console.error(chalk_1.default.white(' ⢠Run `berget api-keys list` to check your keys'));
|
|
84
|
+
console.error(chalk_1.default.white(' ⢠Create a new key with `berget api-keys create --name "My Key"`'));
|
|
85
|
+
console.error(chalk_1.default.white(' ⢠Set a default key with `berget api-keys set-default <id>`'));
|
|
86
|
+
console.error(chalk_1.default.white(' ⢠Check if your API key has expired'));
|
|
87
|
+
}
|
|
88
|
+
// Rate limiting
|
|
89
|
+
if (errorCode === 'RATE_LIMIT_EXCEEDED' ||
|
|
90
|
+
(errorDetails === null || errorDetails === void 0 ? void 0 : errorDetails.includes('rate limit')) ||
|
|
91
|
+
(errorDetails === null || errorDetails === void 0 ? void 0 : errorDetails.includes('too many requests'))) {
|
|
92
|
+
console.error(chalk_1.default.yellow(' ā±ļø Rate limit exceeded:'));
|
|
93
|
+
console.error(chalk_1.default.white(' ⢠Wait a few minutes before trying again'));
|
|
94
|
+
console.error(chalk_1.default.white(' ⢠Consider upgrading your plan for higher limits'));
|
|
95
|
+
console.error(chalk_1.default.white(' ⢠Use `berget billing get-usage` to check your usage'));
|
|
96
|
+
}
|
|
97
|
+
// Server errors
|
|
98
|
+
if ((errorCode === null || errorCode === void 0 ? void 0 : errorCode.includes('SERVER_ERROR')) ||
|
|
99
|
+
errorType === 'server_error' ||
|
|
100
|
+
(errorCode && parseInt(errorCode) >= 500)) {
|
|
101
|
+
console.error(chalk_1.default.yellow(' š„ļø Server issue detected:'));
|
|
102
|
+
console.error(chalk_1.default.white(' ⢠This is a temporary problem on our end'));
|
|
103
|
+
console.error(chalk_1.default.white(' ⢠Try again in a few minutes'));
|
|
104
|
+
console.error(chalk_1.default.white(' ⢠Check status.berget.ai for service status'));
|
|
105
|
+
console.error(chalk_1.default.white(' ⢠Contact support if the problem persists'));
|
|
106
|
+
}
|
|
107
|
+
// Cluster errors
|
|
108
|
+
if ((errorCode === null || errorCode === void 0 ? void 0 : errorCode.includes('CLUSTERS')) ||
|
|
109
|
+
(errorDetails === null || errorDetails === void 0 ? void 0 : errorDetails.includes('cluster'))) {
|
|
110
|
+
console.error(chalk_1.default.yellow(' šļø Cluster issue detected:'));
|
|
111
|
+
console.error(chalk_1.default.white(' ⢠Clusters may be temporarily unavailable'));
|
|
112
|
+
console.error(chalk_1.default.white(' ⢠Try again later or contact support'));
|
|
113
|
+
console.error(chalk_1.default.white(' ⢠Check your cluster permissions'));
|
|
114
|
+
}
|
|
115
|
+
// Generic fallback
|
|
116
|
+
if (!(errorType === null || errorType === void 0 ? void 0 : errorType.includes('authentication')) &&
|
|
117
|
+
!(errorDetails === null || errorDetails === void 0 ? void 0 : errorDetails.includes('fetch failed')) &&
|
|
118
|
+
!(errorCode === null || errorCode === void 0 ? void 0 : errorCode.includes('API_KEY')) &&
|
|
119
|
+
!(errorCode === null || errorCode === void 0 ? void 0 : errorCode.includes('RATE_LIMIT')) &&
|
|
120
|
+
!(errorCode === null || errorCode === void 0 ? void 0 : errorCode.includes('SERVER_ERROR')) &&
|
|
121
|
+
!(errorCode === null || errorCode === void 0 ? void 0 : errorCode.includes('CLUSTERS'))) {
|
|
122
|
+
console.error(chalk_1.default.yellow(' ā General issue:'));
|
|
123
|
+
console.error(chalk_1.default.white(' ⢠Try running the command with --debug for more info'));
|
|
124
|
+
console.error(chalk_1.default.white(' ⢠Check your configuration with `berget auth whoami`'));
|
|
125
|
+
console.error(chalk_1.default.white(' ⢠Contact support if the problem persists'));
|
|
126
|
+
}
|
|
127
|
+
console.error(chalk_1.default.dim('\nNeed more help? Visit https://docs.berget.ai or contact support@berget.ai'));
|
|
128
|
+
}
|
package/index.ts
CHANGED
|
@@ -33,37 +33,9 @@ registerCommands(program)
|
|
|
33
33
|
if (process.argv.length <= 2) {
|
|
34
34
|
checkBergetConfig()
|
|
35
35
|
|
|
36
|
-
// Show
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
console.log(
|
|
40
|
-
chalk.blue(` ${chalk.bold('berget auth login')} - Log in to Berget`)
|
|
41
|
-
)
|
|
42
|
-
console.log(
|
|
43
|
-
chalk.blue(
|
|
44
|
-
` ${chalk.bold('berget models list')} - List available AI models`
|
|
45
|
-
)
|
|
46
|
-
)
|
|
47
|
-
console.log(
|
|
48
|
-
chalk.blue(
|
|
49
|
-
` ${chalk.bold('berget chat run')} - Start a chat session`
|
|
50
|
-
)
|
|
51
|
-
)
|
|
52
|
-
console.log(
|
|
53
|
-
chalk.blue(
|
|
54
|
-
` ${chalk.bold(
|
|
55
|
-
'berget code init'
|
|
56
|
-
)} - Initialize AI coding assistant`
|
|
57
|
-
)
|
|
58
|
-
)
|
|
59
|
-
console.log(
|
|
60
|
-
chalk.blue(` ${chalk.bold('berget api-keys list')} - List your API keys`)
|
|
61
|
-
)
|
|
62
|
-
console.log(
|
|
63
|
-
chalk.blue(
|
|
64
|
-
`\nRun ${chalk.bold('berget --help')} for a complete list of commands.`
|
|
65
|
-
)
|
|
66
|
-
)
|
|
36
|
+
// Show the full help (including logo and commands)
|
|
37
|
+
program.outputHelp()
|
|
38
|
+
process.exit(0)
|
|
67
39
|
}
|
|
68
40
|
|
|
69
41
|
// Add helpful suggestions for common command mistakes
|
package/package.json
CHANGED
package/src/commands/api-keys.ts
CHANGED
|
@@ -4,6 +4,35 @@ import { ApiKeyService, ApiKey } from '../services/api-key-service'
|
|
|
4
4
|
import { handleError } from '../utils/error-handler'
|
|
5
5
|
import { DefaultApiKeyManager } from '../utils/default-api-key'
|
|
6
6
|
|
|
7
|
+
// Helper functions for better date formatting
|
|
8
|
+
function formatDate(dateString: string): string {
|
|
9
|
+
const date = new Date(dateString)
|
|
10
|
+
const now = new Date()
|
|
11
|
+
const diffTime = Math.abs(now.getTime() - date.getTime())
|
|
12
|
+
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24))
|
|
13
|
+
|
|
14
|
+
if (diffDays === 0) return chalk.green('Today')
|
|
15
|
+
if (diffDays === 1) return chalk.yellow('Yesterday')
|
|
16
|
+
if (diffDays < 7) return chalk.yellow(`${diffDays} days ago`)
|
|
17
|
+
if (diffDays < 30) return chalk.blue(`${Math.floor(diffDays / 7)} weeks ago`)
|
|
18
|
+
if (diffDays < 365) return chalk.magenta(`${Math.floor(diffDays / 30)} months ago`)
|
|
19
|
+
return chalk.gray(`${Math.floor(diffDays / 365)} years ago`)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function formatLastUsed(dateString: string): string {
|
|
23
|
+
const date = new Date(dateString)
|
|
24
|
+
const now = new Date()
|
|
25
|
+
const diffTime = Math.abs(now.getTime() - date.getTime())
|
|
26
|
+
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24))
|
|
27
|
+
|
|
28
|
+
if (diffDays === 0) return chalk.green('Today')
|
|
29
|
+
if (diffDays === 1) return chalk.yellow('Yesterday')
|
|
30
|
+
if (diffDays < 7) return chalk.yellow(`${diffDays} days ago`)
|
|
31
|
+
if (diffDays < 30) return chalk.blue(`${Math.floor(diffDays / 7)} weeks ago`)
|
|
32
|
+
if (diffDays < 365) return chalk.magenta(`${Math.floor(diffDays / 30)} months ago`)
|
|
33
|
+
return chalk.gray(`${Math.floor(diffDays / 365)} years ago`)
|
|
34
|
+
}
|
|
35
|
+
|
|
7
36
|
/**
|
|
8
37
|
* Register API key commands
|
|
9
38
|
*/
|
|
@@ -29,45 +58,59 @@ export function registerApiKeyCommands(program: Command): void {
|
|
|
29
58
|
return
|
|
30
59
|
}
|
|
31
60
|
|
|
32
|
-
console.log(chalk.bold('Your API keys:'))
|
|
61
|
+
console.log(chalk.bold('š Your API keys:'))
|
|
33
62
|
console.log('')
|
|
34
63
|
|
|
35
|
-
// Create a table
|
|
64
|
+
// Create a more readable table with better spacing and colors
|
|
65
|
+
const idWidth = 10
|
|
66
|
+
const nameWidth = 30
|
|
67
|
+
const prefixWidth = 20
|
|
68
|
+
const statusWidth = 12
|
|
69
|
+
const createdWidth = 12
|
|
70
|
+
const usedWidth = 15
|
|
71
|
+
|
|
36
72
|
console.log(
|
|
37
|
-
chalk.dim('ID
|
|
38
|
-
chalk.dim('NAME'.padEnd(
|
|
39
|
-
chalk.dim('PREFIX'.padEnd(
|
|
40
|
-
chalk.dim('STATUS'.padEnd(
|
|
41
|
-
chalk.dim('CREATED'.padEnd(
|
|
42
|
-
chalk.dim('LAST USED')
|
|
73
|
+
chalk.dim('ID'.padEnd(idWidth)) +
|
|
74
|
+
chalk.dim('NAME'.padEnd(nameWidth)) +
|
|
75
|
+
chalk.dim('PREFIX'.padEnd(prefixWidth)) +
|
|
76
|
+
chalk.dim('STATUS'.padEnd(statusWidth)) +
|
|
77
|
+
chalk.dim('CREATED'.padEnd(createdWidth)) +
|
|
78
|
+
chalk.dim('LAST USED')
|
|
43
79
|
)
|
|
44
80
|
|
|
45
|
-
console.log(chalk.dim('ā'.repeat(
|
|
81
|
+
console.log(chalk.dim('ā'.repeat(idWidth + nameWidth + prefixWidth + statusWidth + createdWidth + usedWidth + 5)))
|
|
46
82
|
|
|
47
83
|
keys.forEach((key: ApiKey) => {
|
|
48
84
|
const lastUsed = key.lastUsed
|
|
49
|
-
? key.lastUsed
|
|
50
|
-
: 'Never'
|
|
85
|
+
? formatLastUsed(key.lastUsed)
|
|
86
|
+
: chalk.yellow('Never used')
|
|
51
87
|
const status = key.active
|
|
52
88
|
? chalk.green('ā Active')
|
|
53
89
|
: chalk.red('ā Inactive')
|
|
54
90
|
|
|
55
91
|
// Show only first 8 characters of ID for easier reading
|
|
56
|
-
const shortId = String(key.id).substring(0, 8)
|
|
92
|
+
const shortId = chalk.cyan(String(key.id).substring(0, 8))
|
|
93
|
+
|
|
94
|
+
// Format the prefix with better truncation
|
|
95
|
+
const prefixStr = key.prefix.length > prefixWidth
|
|
96
|
+
? key.prefix.substring(0, prefixWidth - 3) + '...'
|
|
97
|
+
: chalk.gray(key.prefix)
|
|
98
|
+
|
|
99
|
+
// Truncate name if too long
|
|
100
|
+
const nameStr = key.name.length > nameWidth
|
|
101
|
+
? key.name.substring(0, nameWidth - 3) + '...'
|
|
102
|
+
: key.name
|
|
57
103
|
|
|
58
|
-
// Format
|
|
59
|
-
const
|
|
60
|
-
key.prefix.length > 12
|
|
61
|
-
? key.prefix.substring(0, 12) + '...'
|
|
62
|
-
: key.prefix
|
|
104
|
+
// Format created date
|
|
105
|
+
const createdDate = formatDate(key.created)
|
|
63
106
|
|
|
64
107
|
console.log(
|
|
65
|
-
shortId.padEnd(
|
|
66
|
-
|
|
67
|
-
prefixStr.padEnd(
|
|
68
|
-
status.padEnd(
|
|
69
|
-
|
|
70
|
-
lastUsed
|
|
108
|
+
shortId.padEnd(idWidth) +
|
|
109
|
+
nameStr.padEnd(nameWidth) +
|
|
110
|
+
prefixStr.padEnd(prefixWidth) +
|
|
111
|
+
status.padEnd(statusWidth) +
|
|
112
|
+
createdDate.padEnd(createdWidth) +
|
|
113
|
+
lastUsed
|
|
71
114
|
)
|
|
72
115
|
})
|
|
73
116
|
|
package/src/commands/chat.ts
CHANGED
|
@@ -41,11 +41,11 @@ export function registerChatCommands(program: Command): void {
|
|
|
41
41
|
chat
|
|
42
42
|
.command(SUBCOMMANDS.CHAT.RUN)
|
|
43
43
|
.description('Run a chat session with a specified model')
|
|
44
|
-
.argument('[model]', 'Model to use (default: openai/gpt-oss)')
|
|
45
44
|
.argument('[message]', 'Message to send directly (skips interactive mode)')
|
|
46
|
-
|
|
45
|
+
.option('-m, --model <model>', 'Model to use (default: deepseek-r1)')
|
|
46
|
+
.option('--no-reasoning', 'Disable reasoning mode (adds </think> to messages)')
|
|
47
47
|
.option('-t, --temperature <temp>', 'Temperature (0-1)', parseFloat)
|
|
48
|
-
.option('
|
|
48
|
+
.option('--max-tokens <tokens>', 'Maximum tokens to generate', parseInt)
|
|
49
49
|
.option('-k, --api-key <key>', 'API key to use for this chat session')
|
|
50
50
|
.option(
|
|
51
51
|
'--api-key-id <id>',
|
|
@@ -55,7 +55,7 @@ export function registerChatCommands(program: Command): void {
|
|
|
55
55
|
'--no-stream',
|
|
56
56
|
'Disable streaming (streaming is enabled by default)',
|
|
57
57
|
)
|
|
58
|
-
.action(async (
|
|
58
|
+
.action(async (message, options) => {
|
|
59
59
|
try {
|
|
60
60
|
const chatService = ChatService.getInstance()
|
|
61
61
|
|
|
@@ -279,7 +279,7 @@ export function registerChatCommands(program: Command): void {
|
|
|
279
279
|
try {
|
|
280
280
|
// Call the API
|
|
281
281
|
const completionOptions: ChatCompletionOptions = {
|
|
282
|
-
model: model || 'openai/gpt-oss',
|
|
282
|
+
model: options.model || 'openai/gpt-oss',
|
|
283
283
|
messages: messages,
|
|
284
284
|
temperature:
|
|
285
285
|
options.temperature !== undefined ? options.temperature : 0.7,
|
|
@@ -415,7 +415,7 @@ export function registerChatCommands(program: Command): void {
|
|
|
415
415
|
try {
|
|
416
416
|
// Call the API
|
|
417
417
|
const completionOptions: ChatCompletionOptions = {
|
|
418
|
-
model: model || 'openai/gpt-oss',
|
|
418
|
+
model: options.model || 'openai/gpt-oss',
|
|
419
419
|
messages: messages,
|
|
420
420
|
temperature:
|
|
421
421
|
options.temperature !== undefined ? options.temperature : 0.7,
|
|
@@ -4,7 +4,11 @@ import chalk from 'chalk'
|
|
|
4
4
|
* Formats and prints error messages in a consistent way
|
|
5
5
|
*/
|
|
6
6
|
export function handleError(message: string, error: any): void {
|
|
7
|
-
console.error(chalk.red(
|
|
7
|
+
console.error(chalk.red(`ā Error: ${message}`))
|
|
8
|
+
|
|
9
|
+
let errorDetails = ''
|
|
10
|
+
let errorCode = ''
|
|
11
|
+
let errorType = ''
|
|
8
12
|
|
|
9
13
|
// If the error is a string (like JSON.stringify(error))
|
|
10
14
|
if (typeof error === 'string') {
|
|
@@ -12,38 +16,131 @@ export function handleError(message: string, error: any): void {
|
|
|
12
16
|
// Try to parse it as JSON
|
|
13
17
|
const parsedError = JSON.parse(error)
|
|
14
18
|
if (parsedError.error) {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
}
|
|
19
|
+
errorDetails = parsedError.error.message || parsedError.error
|
|
20
|
+
errorCode = parsedError.error.code || parsedError.code
|
|
21
|
+
errorType = parsedError.error.type || ''
|
|
19
22
|
} else {
|
|
20
|
-
|
|
23
|
+
errorDetails = error
|
|
21
24
|
}
|
|
22
25
|
} catch {
|
|
23
26
|
// If it's not valid JSON, just print the string
|
|
24
|
-
|
|
27
|
+
errorDetails = error
|
|
25
28
|
}
|
|
26
29
|
} else if (error && error.message) {
|
|
27
30
|
// If it's an Error object
|
|
28
|
-
|
|
31
|
+
errorDetails = error.message
|
|
32
|
+
errorCode = error.code
|
|
33
|
+
errorType = error.type
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Print error details
|
|
37
|
+
if (errorDetails) {
|
|
38
|
+
console.error(chalk.dim(`š Details: ${errorDetails}`))
|
|
39
|
+
}
|
|
40
|
+
if (errorCode) {
|
|
41
|
+
console.error(chalk.dim(`š¢ Code: ${errorCode}`))
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Provide helpful troubleshooting based on error type
|
|
45
|
+
provideTroubleshootingTips(errorType, errorCode, errorDetails)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Provides helpful troubleshooting tips based on error type
|
|
50
|
+
*/
|
|
51
|
+
function provideTroubleshootingTips(errorType: string, errorCode: string, errorDetails: string): void {
|
|
52
|
+
console.error(chalk.blue('\nš” Troubleshooting tips:'))
|
|
53
|
+
|
|
54
|
+
// Authentication errors
|
|
55
|
+
if (
|
|
56
|
+
errorType === 'authentication_error' ||
|
|
57
|
+
errorCode === 'AUTH_FAILED' ||
|
|
58
|
+
errorDetails?.includes('Unauthorized') ||
|
|
59
|
+
errorDetails?.includes('Authentication failed')
|
|
60
|
+
) {
|
|
61
|
+
console.error(chalk.yellow(' š Authentication issue detected:'))
|
|
62
|
+
console.error(chalk.white(' ⢠Run `berget auth login` to log in'))
|
|
63
|
+
console.error(chalk.white(' ⢠Check if your session has expired'))
|
|
64
|
+
console.error(chalk.white(' ⢠Verify you have the correct permissions'))
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Network/connection errors
|
|
68
|
+
if (
|
|
69
|
+
errorDetails?.includes('fetch failed') ||
|
|
70
|
+
errorDetails?.includes('ECONNREFUSED') ||
|
|
71
|
+
errorDetails?.includes('ENOTFOUND') ||
|
|
72
|
+
errorDetails?.includes('network')
|
|
73
|
+
) {
|
|
74
|
+
console.error(chalk.yellow(' š Network issue detected:'))
|
|
75
|
+
console.error(chalk.white(' ⢠Check your internet connection'))
|
|
76
|
+
console.error(chalk.white(' ⢠Verify you can reach api.berget.ai'))
|
|
77
|
+
console.error(chalk.white(' ⢠Try again in a few minutes'))
|
|
78
|
+
console.error(chalk.white(' ⢠Check if any firewall is blocking the request'))
|
|
29
79
|
}
|
|
30
80
|
|
|
31
|
-
//
|
|
81
|
+
// API key errors
|
|
32
82
|
if (
|
|
33
|
-
(
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
(error &&
|
|
37
|
-
error.message &&
|
|
38
|
-
(error.message.includes('Unauthorized') ||
|
|
39
|
-
error.message.includes('Authentication failed'))) ||
|
|
40
|
-
(error &&
|
|
41
|
-
error.code &&
|
|
42
|
-
(error.code === 401 || error.code === 'AUTH_FAILED'))
|
|
83
|
+
errorCode?.includes('API_KEY') ||
|
|
84
|
+
errorDetails?.includes('API key') ||
|
|
85
|
+
errorType === 'invalid_request_error'
|
|
43
86
|
) {
|
|
44
|
-
console.error(
|
|
45
|
-
|
|
46
|
-
)
|
|
47
|
-
console.error(chalk.
|
|
87
|
+
console.error(chalk.yellow(' š API key issue detected:'))
|
|
88
|
+
console.error(chalk.white(' ⢠Run `berget api-keys list` to check your keys'))
|
|
89
|
+
console.error(chalk.white(' ⢠Create a new key with `berget api-keys create --name "My Key"`'))
|
|
90
|
+
console.error(chalk.white(' ⢠Set a default key with `berget api-keys set-default <id>`'))
|
|
91
|
+
console.error(chalk.white(' ⢠Check if your API key has expired'))
|
|
48
92
|
}
|
|
93
|
+
|
|
94
|
+
// Rate limiting
|
|
95
|
+
if (
|
|
96
|
+
errorCode === 'RATE_LIMIT_EXCEEDED' ||
|
|
97
|
+
errorDetails?.includes('rate limit') ||
|
|
98
|
+
errorDetails?.includes('too many requests')
|
|
99
|
+
) {
|
|
100
|
+
console.error(chalk.yellow(' ā±ļø Rate limit exceeded:'))
|
|
101
|
+
console.error(chalk.white(' ⢠Wait a few minutes before trying again'))
|
|
102
|
+
console.error(chalk.white(' ⢠Consider upgrading your plan for higher limits'))
|
|
103
|
+
console.error(chalk.white(' ⢠Use `berget billing get-usage` to check your usage'))
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Server errors
|
|
107
|
+
if (
|
|
108
|
+
errorCode?.includes('SERVER_ERROR') ||
|
|
109
|
+
errorType === 'server_error' ||
|
|
110
|
+
(errorCode && parseInt(errorCode) >= 500)
|
|
111
|
+
) {
|
|
112
|
+
console.error(chalk.yellow(' š„ļø Server issue detected:'))
|
|
113
|
+
console.error(chalk.white(' ⢠This is a temporary problem on our end'))
|
|
114
|
+
console.error(chalk.white(' ⢠Try again in a few minutes'))
|
|
115
|
+
console.error(chalk.white(' ⢠Check status.berget.ai for service status'))
|
|
116
|
+
console.error(chalk.white(' ⢠Contact support if the problem persists'))
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Cluster errors
|
|
120
|
+
if (
|
|
121
|
+
errorCode?.includes('CLUSTERS') ||
|
|
122
|
+
errorDetails?.includes('cluster')
|
|
123
|
+
) {
|
|
124
|
+
console.error(chalk.yellow(' šļø Cluster issue detected:'))
|
|
125
|
+
console.error(chalk.white(' ⢠Clusters may be temporarily unavailable'))
|
|
126
|
+
console.error(chalk.white(' ⢠Try again later or contact support'))
|
|
127
|
+
console.error(chalk.white(' ⢠Check your cluster permissions'))
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Generic fallback
|
|
131
|
+
if (
|
|
132
|
+
!errorType?.includes('authentication') &&
|
|
133
|
+
!errorDetails?.includes('fetch failed') &&
|
|
134
|
+
!errorCode?.includes('API_KEY') &&
|
|
135
|
+
!errorCode?.includes('RATE_LIMIT') &&
|
|
136
|
+
!errorCode?.includes('SERVER_ERROR') &&
|
|
137
|
+
!errorCode?.includes('CLUSTERS')
|
|
138
|
+
) {
|
|
139
|
+
console.error(chalk.yellow(' ā General issue:'))
|
|
140
|
+
console.error(chalk.white(' ⢠Try running the command with --debug for more info'))
|
|
141
|
+
console.error(chalk.white(' ⢠Check your configuration with `berget auth whoami`'))
|
|
142
|
+
console.error(chalk.white(' ⢠Contact support if the problem persists'))
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
console.error(chalk.dim('\nNeed more help? Visit https://docs.berget.ai or contact support@berget.ai'))
|
|
49
146
|
}
|