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.
Files changed (145) hide show
  1. package/.github/workflows/publish.yml +2 -2
  2. package/.github/workflows/test.yml +10 -4
  3. package/.husky/pre-commit +1 -0
  4. package/.prettierignore +15 -0
  5. package/.prettierrc +7 -3
  6. package/CONTRIBUTING.md +38 -0
  7. package/README.md +2 -148
  8. package/dist/index.js +10 -11
  9. package/dist/package.json +30 -2
  10. package/dist/src/agents/app.js +28 -0
  11. package/dist/src/agents/backend.js +25 -0
  12. package/dist/src/agents/devops.js +34 -0
  13. package/dist/src/agents/frontend.js +25 -0
  14. package/dist/src/agents/fullstack.js +25 -0
  15. package/dist/src/agents/index.js +61 -0
  16. package/dist/src/agents/quality.js +70 -0
  17. package/dist/src/agents/security.js +26 -0
  18. package/dist/src/agents/types.js +2 -0
  19. package/dist/src/client.js +97 -117
  20. package/dist/src/commands/api-keys.js +75 -90
  21. package/dist/src/commands/auth.js +7 -16
  22. package/dist/src/commands/autocomplete.js +1 -1
  23. package/dist/src/commands/billing.js +6 -17
  24. package/dist/src/commands/chat.js +68 -101
  25. package/dist/src/commands/clusters.js +9 -18
  26. package/dist/src/commands/code/__tests__/auth-sync.test.js +351 -0
  27. package/dist/src/commands/code/__tests__/fake-api-key-service.js +13 -0
  28. package/dist/src/commands/code/__tests__/fake-auth-service.js +47 -0
  29. package/dist/src/commands/code/__tests__/fake-command-runner.js +21 -34
  30. package/dist/src/commands/code/__tests__/fake-file-store.js +20 -33
  31. package/dist/src/commands/code/__tests__/fake-prompter.js +83 -57
  32. package/dist/src/commands/code/__tests__/setup-flow.test.js +359 -92
  33. package/dist/src/commands/code/adapters/clack-prompter.js +15 -22
  34. package/dist/src/commands/code/adapters/fs-file-store.js +26 -40
  35. package/dist/src/commands/code/adapters/spawn-command-runner.js +27 -37
  36. package/dist/src/commands/code/auth-sync.js +270 -0
  37. package/dist/src/commands/code/errors.js +12 -9
  38. package/dist/src/commands/code/ports/auth-services.js +2 -0
  39. package/dist/src/commands/code/setup.js +387 -281
  40. package/dist/src/commands/code.js +205 -332
  41. package/dist/src/commands/index.js +5 -5
  42. package/dist/src/commands/models.js +6 -17
  43. package/dist/src/commands/users.js +5 -16
  44. package/dist/src/constants/command-structure.js +104 -104
  45. package/dist/src/services/api-key-service.js +132 -157
  46. package/dist/src/services/auth-service.js +89 -342
  47. package/dist/src/services/browser-auth.js +268 -0
  48. package/dist/src/services/chat-service.js +371 -401
  49. package/dist/src/services/cluster-service.js +47 -62
  50. package/dist/src/services/collaborator-service.js +10 -25
  51. package/dist/src/services/flux-service.js +14 -29
  52. package/dist/src/services/helm-service.js +10 -25
  53. package/dist/src/services/kubectl-service.js +16 -33
  54. package/dist/src/utils/config-checker.js +3 -3
  55. package/dist/src/utils/config-loader.js +95 -95
  56. package/dist/src/utils/default-api-key.js +124 -134
  57. package/dist/src/utils/env-manager.js +55 -66
  58. package/dist/src/utils/error-handler.js +20 -21
  59. package/dist/src/utils/logger.js +72 -65
  60. package/dist/src/utils/markdown-renderer.js +27 -27
  61. package/dist/src/utils/opencode-validator.js +63 -68
  62. package/dist/src/utils/token-manager.js +74 -45
  63. package/dist/tests/commands/chat.test.js +16 -25
  64. package/dist/tests/commands/code.test.js +95 -104
  65. package/dist/tests/utils/config-loader.test.js +48 -48
  66. package/dist/tests/utils/env-manager.test.js +43 -52
  67. package/dist/tests/utils/opencode-validator.test.js +22 -21
  68. package/dist/vitest.config.js +1 -1
  69. package/eslint.config.mjs +67 -0
  70. package/index.ts +35 -42
  71. package/package.json +30 -2
  72. package/src/agents/app.ts +27 -0
  73. package/src/agents/backend.ts +24 -0
  74. package/src/agents/devops.ts +33 -0
  75. package/src/agents/frontend.ts +24 -0
  76. package/src/agents/fullstack.ts +24 -0
  77. package/src/agents/index.ts +73 -0
  78. package/src/agents/quality.ts +69 -0
  79. package/src/agents/security.ts +26 -0
  80. package/src/agents/types.ts +17 -0
  81. package/src/client.ts +118 -152
  82. package/src/commands/api-keys.ts +241 -333
  83. package/src/commands/auth.ts +22 -27
  84. package/src/commands/autocomplete.ts +9 -9
  85. package/src/commands/billing.ts +20 -24
  86. package/src/commands/chat.ts +248 -338
  87. package/src/commands/clusters.ts +27 -26
  88. package/src/commands/code/__tests__/auth-sync.test.ts +482 -0
  89. package/src/commands/code/__tests__/fake-api-key-service.ts +13 -0
  90. package/src/commands/code/__tests__/fake-auth-service.ts +50 -0
  91. package/src/commands/code/__tests__/fake-command-runner.ts +45 -42
  92. package/src/commands/code/__tests__/fake-file-store.ts +32 -23
  93. package/src/commands/code/__tests__/fake-prompter.ts +116 -77
  94. package/src/commands/code/__tests__/setup-flow.test.ts +624 -268
  95. package/src/commands/code/adapters/clack-prompter.ts +53 -39
  96. package/src/commands/code/adapters/fs-file-store.ts +32 -27
  97. package/src/commands/code/adapters/spawn-command-runner.ts +38 -29
  98. package/src/commands/code/auth-sync.ts +329 -0
  99. package/src/commands/code/errors.ts +18 -18
  100. package/src/commands/code/ports/auth-services.ts +14 -0
  101. package/src/commands/code/ports/command-runner.ts +8 -4
  102. package/src/commands/code/ports/file-store.ts +5 -4
  103. package/src/commands/code/ports/prompter.ts +24 -18
  104. package/src/commands/code/setup.ts +570 -340
  105. package/src/commands/code.ts +338 -539
  106. package/src/commands/index.ts +20 -19
  107. package/src/commands/models.ts +28 -32
  108. package/src/commands/users.ts +15 -21
  109. package/src/constants/command-structure.ts +134 -157
  110. package/src/services/api-key-service.ts +105 -122
  111. package/src/services/auth-service.ts +99 -345
  112. package/src/services/browser-auth.ts +296 -0
  113. package/src/services/chat-service.ts +265 -299
  114. package/src/services/cluster-service.ts +42 -45
  115. package/src/services/collaborator-service.ts +14 -19
  116. package/src/services/flux-service.ts +23 -25
  117. package/src/services/helm-service.ts +19 -21
  118. package/src/services/kubectl-service.ts +17 -19
  119. package/src/types/api.d.ts +1905 -1907
  120. package/src/types/json.d.ts +2 -2
  121. package/src/utils/config-checker.ts +10 -10
  122. package/src/utils/config-loader.ts +162 -178
  123. package/src/utils/default-api-key.ts +114 -125
  124. package/src/utils/env-manager.ts +53 -57
  125. package/src/utils/error-handler.ts +61 -56
  126. package/src/utils/logger.ts +79 -73
  127. package/src/utils/markdown-renderer.ts +31 -31
  128. package/src/utils/opencode-validator.ts +85 -89
  129. package/src/utils/token-manager.ts +108 -87
  130. package/templates/agents/app.md +1 -0
  131. package/templates/agents/backend.md +1 -0
  132. package/templates/agents/devops.md +2 -0
  133. package/templates/agents/frontend.md +1 -0
  134. package/templates/agents/fullstack.md +1 -0
  135. package/templates/agents/quality.md +45 -40
  136. package/templates/agents/security.md +1 -0
  137. package/tests/commands/chat.test.ts +53 -62
  138. package/tests/commands/code.test.ts +265 -310
  139. package/tests/utils/config-loader.test.ts +189 -188
  140. package/tests/utils/env-manager.test.ts +110 -113
  141. package/tests/utils/opencode-validator.test.ts +52 -56
  142. package/tsconfig.json +4 -3
  143. package/vitest.config.ts +3 -3
  144. package/AGENTS.md +0 -374
  145. package/TODO.md +0 -19
@@ -3,28 +3,28 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.fixOpenCodeConfig = exports.validateOpenCodeConfig = void 0;
6
+ exports.validateOpenCodeConfig = exports.fixOpenCodeConfig = void 0;
7
7
  const ajv_1 = __importDefault(require("ajv"));
8
8
  const ajv_formats_1 = __importDefault(require("ajv-formats"));
9
- const fs_1 = require("fs");
10
- const path_1 = require("path");
11
- const path_2 = require("path");
9
+ const node_fs_1 = require("node:fs");
10
+ const node_path_1 = require("node:path");
11
+ const node_path_2 = require("node:path");
12
12
  // Load the official OpenCode JSON Schema
13
- const __dirname = (0, path_2.dirname)(__filename);
14
- const schemaPath = (0, path_1.join)(__dirname, '..', 'schemas', 'opencode-schema.json');
13
+ const __dirname = (0, node_path_2.dirname)(__filename);
14
+ const schemaPath = (0, node_path_1.join)(__dirname, '..', 'schemas', 'opencode-schema.json');
15
15
  let ajv;
16
16
  let openCodeSchema;
17
17
  let validateFunction;
18
18
  try {
19
- const schemaContent = (0, fs_1.readFileSync)(schemaPath, 'utf-8');
19
+ const schemaContent = (0, node_fs_1.readFileSync)(schemaPath, 'utf-8');
20
20
  openCodeSchema = JSON.parse(schemaContent);
21
21
  // Initialize AJV with formats and options
22
22
  ajv = new ajv_1.default({
23
23
  allErrors: true,
24
- verbose: true,
25
- strict: false,
26
24
  allowUnionTypes: true,
27
25
  removeAdditional: false,
26
+ strict: false,
27
+ verbose: true,
28
28
  });
29
29
  // Add JSON Schema formats
30
30
  (0, ajv_formats_1.default)(ajv);
@@ -35,39 +35,11 @@ catch (error) {
35
35
  console.error('Failed to load OpenCode schema:', error);
36
36
  throw new Error('Could not initialize OpenCode validator');
37
37
  }
38
- /**
39
- * Validate OpenCode configuration against the official JSON Schema
40
- */
41
- function validateOpenCodeConfig(config) {
42
- var _a;
43
- try {
44
- if (!validateFunction) {
45
- return { valid: false, errors: ['Schema validator not initialized'] };
46
- }
47
- const isValid = validateFunction(config);
48
- if (isValid) {
49
- return { valid: true };
50
- }
51
- else {
52
- const errors = ((_a = validateFunction.errors) === null || _a === void 0 ? void 0 : _a.map((err) => {
53
- const path = err.instancePath || err.schemaPath || 'root';
54
- const message = err.message || 'Unknown error';
55
- return `${path}: ${message}`;
56
- })) || ['Unknown validation error'];
57
- return { valid: false, errors };
58
- }
59
- }
60
- catch (error) {
61
- console.error('Validation error:', error);
62
- return { valid: false, errors: ['Validation process failed'] };
63
- }
64
- }
65
- exports.validateOpenCodeConfig = validateOpenCodeConfig;
66
38
  /**
67
39
  * Fix common OpenCode configuration issues
68
40
  */
69
41
  function fixOpenCodeConfig(config) {
70
- const fixed = Object.assign({}, config);
42
+ const fixed = { ...config };
71
43
  // Fix tools.compact - should be boolean, not object
72
44
  if (fixed.tools && typeof fixed.tools.compact === 'object') {
73
45
  console.warn('⚠️ Converting tools.compact from object to boolean');
@@ -75,43 +47,39 @@ function fixOpenCodeConfig(config) {
75
47
  fixed.tools.compact = true;
76
48
  }
77
49
  // Remove invalid properties
78
- const invalidProps = ['maxTokens', 'contextWindow'];
79
- invalidProps.forEach((prop) => {
80
- if (fixed[prop] !== undefined) {
81
- console.warn(`⚠️ Removing invalid property: ${prop}`);
82
- delete fixed[prop];
50
+ const invalidProperties = ['maxTokens', 'contextWindow'];
51
+ for (const property of invalidProperties) {
52
+ if (fixed[property] !== undefined) {
53
+ console.warn(`⚠️ Removing invalid property: ${property}`);
54
+ delete fixed[property];
83
55
  }
84
- });
56
+ }
85
57
  // Fix provider models with invalid properties
86
58
  if (fixed.provider) {
87
59
  Object.values(fixed.provider).forEach((provider) => {
88
- if (provider === null || provider === void 0 ? void 0 : provider.models) {
60
+ if (provider?.models) {
89
61
  Object.values(provider.models).forEach((model) => {
90
- if (model && typeof model === 'object') {
91
- // Move maxTokens/contextWindow to proper structure if needed
92
- if (model.maxTokens || model.contextWindow) {
93
- if (!model.limit)
94
- model.limit = {};
95
- // Use the larger of maxTokens/contextWindow for context
96
- const contextValues = [
97
- model.maxTokens,
98
- model.contextWindow,
99
- ].filter(Boolean);
100
- if (contextValues.length > 0) {
101
- const newContext = Math.max(...contextValues);
102
- if (!model.limit.context || newContext > model.limit.context) {
103
- model.limit.context = newContext;
104
- }
105
- }
106
- // Set a reasonable default for output if not present
107
- // (typically 1/4 to 1/8 of context window)
108
- if (!model.limit.output && model.limit.context) {
109
- model.limit.output = Math.floor(model.limit.context / 4);
62
+ if (model &&
63
+ typeof model === 'object' && // Move maxTokens/contextWindow to proper structure if needed
64
+ (model.maxTokens || model.contextWindow)) {
65
+ if (!model.limit)
66
+ model.limit = {};
67
+ // Use the larger of maxTokens/contextWindow for context
68
+ const contextValues = [model.maxTokens, model.contextWindow].filter(Boolean);
69
+ if (contextValues.length > 0) {
70
+ const newContext = Math.max(...contextValues);
71
+ if (!model.limit.context || newContext > model.limit.context) {
72
+ model.limit.context = newContext;
110
73
  }
111
- delete model.maxTokens;
112
- delete model.contextWindow;
113
- console.warn('⚠️ Moved maxTokens/contextWindow to limit.context/output');
114
74
  }
75
+ // Set a reasonable default for output if not present
76
+ // (typically 1/4 to 1/8 of context window)
77
+ if (!model.limit.output && model.limit.context) {
78
+ model.limit.output = Math.floor(model.limit.context / 4);
79
+ }
80
+ delete model.maxTokens;
81
+ delete model.contextWindow;
82
+ console.warn('⚠️ Moved maxTokens/contextWindow to limit.context/output');
115
83
  }
116
84
  });
117
85
  }
@@ -120,3 +88,30 @@ function fixOpenCodeConfig(config) {
120
88
  return fixed;
121
89
  }
122
90
  exports.fixOpenCodeConfig = fixOpenCodeConfig;
91
+ /**
92
+ * Validate OpenCode configuration against the official JSON Schema
93
+ */
94
+ function validateOpenCodeConfig(config) {
95
+ try {
96
+ if (!validateFunction) {
97
+ return { errors: ['Schema validator not initialized'], valid: false };
98
+ }
99
+ const isValid = validateFunction(config);
100
+ if (isValid) {
101
+ return { valid: true };
102
+ }
103
+ else {
104
+ const errors = validateFunction.errors?.map((error) => {
105
+ const path = error.instancePath || error.schemaPath || 'root';
106
+ const message = error.message || 'Unknown error';
107
+ return `${path}: ${message}`;
108
+ }) || ['Unknown validation error'];
109
+ return { errors, valid: false };
110
+ }
111
+ }
112
+ catch (error) {
113
+ console.error('Validation error:', error);
114
+ return { errors: ['Validation process failed'], valid: false };
115
+ }
116
+ }
117
+ exports.validateOpenCodeConfig = validateOpenCodeConfig;
@@ -24,16 +24,18 @@ var __importStar = (this && this.__importStar) || function (mod) {
24
24
  };
25
25
  Object.defineProperty(exports, "__esModule", { value: true });
26
26
  exports.TokenManager = void 0;
27
- const fs = __importStar(require("fs"));
28
- const path = __importStar(require("path"));
29
- const os = __importStar(require("os"));
27
+ const fs = __importStar(require("node:fs"));
28
+ const os = __importStar(require("node:os"));
29
+ const path = __importStar(require("node:path"));
30
30
  const logger_1 = require("./logger");
31
31
  /**
32
32
  * Manages authentication tokens including refresh functionality
33
33
  */
34
34
  class TokenManager {
35
+ static instance;
36
+ tokenData = null;
37
+ tokenFilePath;
35
38
  constructor() {
36
- this.tokenData = null;
37
39
  // Set up token file path in user's home directory
38
40
  const bergetDir = path.join(os.homedir(), '.berget');
39
41
  if (!fs.existsSync(bergetDir)) {
@@ -49,40 +51,11 @@ class TokenManager {
49
51
  return TokenManager.instance;
50
52
  }
51
53
  /**
52
- * Load token data from file
53
- */
54
- loadToken() {
55
- try {
56
- if (fs.existsSync(this.tokenFilePath)) {
57
- const data = fs.readFileSync(this.tokenFilePath, 'utf8');
58
- this.tokenData = JSON.parse(data);
59
- }
60
- }
61
- catch (error) {
62
- logger_1.logger.error('Failed to load authentication token');
63
- this.tokenData = null;
64
- }
65
- }
66
- /**
67
- * Save token data to file
54
+ * Clear all token data
68
55
  */
69
- saveToken() {
70
- try {
71
- if (this.tokenData) {
72
- fs.writeFileSync(this.tokenFilePath, JSON.stringify(this.tokenData, null, 2));
73
- // Set file permissions to be readable only by the owner
74
- fs.chmodSync(this.tokenFilePath, 0o600);
75
- }
76
- else {
77
- // If token data is null, remove the file
78
- if (fs.existsSync(this.tokenFilePath)) {
79
- fs.unlinkSync(this.tokenFilePath);
80
- }
81
- }
82
- }
83
- catch (error) {
84
- logger_1.logger.error('Failed to save authentication token');
85
- }
56
+ clearTokens() {
57
+ this.tokenData = null;
58
+ this.saveToken();
86
59
  }
87
60
  /**
88
61
  * Get the current access token
@@ -134,34 +107,90 @@ class TokenManager {
134
107
  * Set new token data
135
108
  * @param accessToken The new access token
136
109
  * @param refreshToken The new refresh token
137
- * @param expiresIn Expiration time in seconds
110
+ * @param expiresIn Expiration time in seconds (fallback if JWT parsing fails)
138
111
  */
139
112
  setTokens(accessToken, refreshToken, expiresIn) {
113
+ // Extract the actual expiry time from the JWT token
114
+ const jwtExpiresAt = extractJwtExpiresAt(accessToken);
115
+ const expiresAt = jwtExpiresAt > 0 ? jwtExpiresAt : Date.now() + expiresIn * 1000;
140
116
  this.tokenData = {
141
117
  access_token: accessToken,
118
+ expires_at: expiresAt,
142
119
  refresh_token: refreshToken,
143
- expires_at: Date.now() + expiresIn * 1000,
144
120
  };
145
121
  this.saveToken();
146
122
  }
147
123
  /**
148
124
  * Update just the access token and its expiration
149
125
  * @param accessToken The new access token
150
- * @param expiresIn Expiration time in seconds
126
+ * @param expiresIn Expiration time in seconds (fallback if JWT parsing fails)
151
127
  */
152
128
  updateAccessToken(accessToken, expiresIn) {
153
129
  if (!this.tokenData)
154
130
  return;
131
+ // Extract the actual expiry time from the JWT token
132
+ const jwtExpiresAt = extractJwtExpiresAt(accessToken);
133
+ const expiresAt = jwtExpiresAt > 0 ? jwtExpiresAt : Date.now() + expiresIn * 1000;
155
134
  this.tokenData.access_token = accessToken;
156
- this.tokenData.expires_at = Date.now() + expiresIn * 1000;
135
+ this.tokenData.expires_at = expiresAt;
157
136
  this.saveToken();
158
137
  }
159
138
  /**
160
- * Clear all token data
139
+ * Load token data from file
161
140
  */
162
- clearTokens() {
163
- this.tokenData = null;
164
- this.saveToken();
141
+ loadToken() {
142
+ try {
143
+ if (fs.existsSync(this.tokenFilePath)) {
144
+ const data = fs.readFileSync(this.tokenFilePath, 'utf8');
145
+ this.tokenData = JSON.parse(data);
146
+ }
147
+ }
148
+ catch {
149
+ logger_1.logger.error('Failed to load authentication token');
150
+ this.tokenData = null;
151
+ }
152
+ }
153
+ /**
154
+ * Save token data to file
155
+ */
156
+ saveToken() {
157
+ try {
158
+ if (this.tokenData) {
159
+ fs.writeFileSync(this.tokenFilePath, JSON.stringify(this.tokenData, null, 2));
160
+ // Set file permissions to be readable only by the owner
161
+ fs.chmodSync(this.tokenFilePath, 0o600);
162
+ }
163
+ else {
164
+ // If token data is null, remove the file
165
+ if (fs.existsSync(this.tokenFilePath)) {
166
+ fs.unlinkSync(this.tokenFilePath);
167
+ }
168
+ }
169
+ }
170
+ catch {
171
+ logger_1.logger.error('Failed to save authentication token');
172
+ }
165
173
  }
166
174
  }
167
175
  exports.TokenManager = TokenManager;
176
+ /**
177
+ * Extract the expiration time from a JWT token
178
+ * @param accessToken The JWT access token
179
+ * @returns The expiration timestamp in milliseconds, or 0 if invalid
180
+ */
181
+ function extractJwtExpiresAt(accessToken) {
182
+ try {
183
+ const parts = accessToken.split('.');
184
+ if (parts.length !== 3)
185
+ return 0;
186
+ const payload = Buffer.from(parts[1], 'base64url').toString('utf8');
187
+ const decoded = JSON.parse(payload);
188
+ if (typeof decoded.exp === 'number') {
189
+ return decoded.exp * 1000; // JWT exp is in seconds, convert to milliseconds
190
+ }
191
+ }
192
+ catch {
193
+ // If decoding fails, return 0 (treated as expired)
194
+ }
195
+ return 0;
196
+ }
@@ -1,16 +1,7 @@
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
  Object.defineProperty(exports, "__esModule", { value: true });
12
- const vitest_1 = require("vitest");
13
3
  const commander_1 = require("commander");
4
+ const vitest_1 = require("vitest");
14
5
  const chat_1 = require("../../src/commands/chat");
15
6
  const chat_service_1 = require("../../src/services/chat-service");
16
7
  const default_api_key_1 = require("../../src/utils/default-api-key");
@@ -19,8 +10,8 @@ vitest_1.vi.mock('../../src/services/chat-service');
19
10
  vitest_1.vi.mock('../../src/utils/default-api-key');
20
11
  vitest_1.vi.mock('readline', () => ({
21
12
  createInterface: vitest_1.vi.fn(() => ({
22
- question: vitest_1.vi.fn(),
23
13
  close: vitest_1.vi.fn(),
14
+ question: vitest_1.vi.fn(),
24
15
  })),
25
16
  }));
26
17
  (0, vitest_1.describe)('Chat Commands', () => {
@@ -49,22 +40,22 @@ vitest_1.vi.mock('readline', () => ({
49
40
  (0, vitest_1.describe)('chat run command', () => {
50
41
  (0, vitest_1.it)('should use berget/glm-4.7 as default model', () => {
51
42
  const chatCommand = program.commands.find((cmd) => cmd.name() === 'chat');
52
- const runCommand = chatCommand === null || chatCommand === void 0 ? void 0 : chatCommand.commands.find((cmd) => cmd.name() === 'run');
43
+ const runCommand = chatCommand?.commands.find((cmd) => cmd.name() === 'run');
53
44
  (0, vitest_1.expect)(runCommand).toBeDefined();
54
45
  // Check the help text which contains the default model
55
- const helpText = runCommand === null || runCommand === void 0 ? void 0 : runCommand.helpInformation();
46
+ const helpText = runCommand?.helpInformation();
56
47
  (0, vitest_1.expect)(helpText).toContain('glm-4.7');
57
48
  });
58
49
  (0, vitest_1.it)('should have streaming enabled by default', () => {
59
50
  const chatCommand = program.commands.find((cmd) => cmd.name() === 'chat');
60
- const runCommand = chatCommand === null || chatCommand === void 0 ? void 0 : chatCommand.commands.find((cmd) => cmd.name() === 'run');
51
+ const runCommand = chatCommand?.commands.find((cmd) => cmd.name() === 'run');
61
52
  (0, vitest_1.expect)(runCommand).toBeDefined();
62
53
  // Check that the option is --no-stream (meaning streaming is default)
63
- const streamOption = runCommand === null || runCommand === void 0 ? void 0 : runCommand.options.find((opt) => opt.long === '--no-stream');
54
+ const streamOption = runCommand?.options.find((opt) => opt.long === '--no-stream');
64
55
  (0, vitest_1.expect)(streamOption).toBeDefined();
65
- (0, vitest_1.expect)(streamOption === null || streamOption === void 0 ? void 0 : streamOption.description).toContain('Disable streaming');
56
+ (0, vitest_1.expect)(streamOption?.description).toContain('Disable streaming');
66
57
  });
67
- (0, vitest_1.it)('should create completion with correct default options', () => __awaiter(void 0, void 0, void 0, function* () {
58
+ (0, vitest_1.it)('should create completion with correct default options', async () => {
68
59
  // Mock API key
69
60
  process.env.BERGET_API_KEY = 'test-key';
70
61
  // Mock successful completion
@@ -81,29 +72,29 @@ vitest_1.vi.mock('readline', () => ({
81
72
  (0, vitest_1.expect)(mockChatService.createCompletion).not.toHaveBeenCalled();
82
73
  // Clean up
83
74
  delete process.env.BERGET_API_KEY;
84
- }));
75
+ });
85
76
  });
86
77
  (0, vitest_1.describe)('chat list command', () => {
87
- (0, vitest_1.it)('should list available models', () => __awaiter(void 0, void 0, void 0, function* () {
78
+ (0, vitest_1.it)('should list available models', async () => {
88
79
  const mockModels = {
89
80
  data: [
90
81
  {
91
- id: 'gpt-oss',
92
- owned_by: 'openai',
93
82
  active: true,
94
83
  capabilities: {
95
- vision: false,
96
84
  function_calling: true,
97
85
  json_mode: true,
86
+ vision: false,
98
87
  },
88
+ id: 'gpt-oss',
89
+ owned_by: 'openai',
99
90
  },
100
91
  ],
101
92
  };
102
93
  mockChatService.listModels.mockResolvedValue(mockModels);
103
94
  const chatCommand = program.commands.find((cmd) => cmd.name() === 'chat');
104
- const listCommand = chatCommand === null || chatCommand === void 0 ? void 0 : chatCommand.commands.find((cmd) => cmd.name() === 'list');
95
+ const listCommand = chatCommand?.commands.find((cmd) => cmd.name() === 'list');
105
96
  (0, vitest_1.expect)(listCommand).toBeDefined();
106
- (0, vitest_1.expect)(listCommand === null || listCommand === void 0 ? void 0 : listCommand.description()).toBe('List available chat models');
107
- }));
97
+ (0, vitest_1.expect)(listCommand?.description()).toBe('List available chat models');
98
+ });
108
99
  });
109
100
  });