berget 2.0.3 → 2.0.5
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/AGENTS.md +29 -0
- package/dist/index.js +2 -0
- package/dist/package.json +1 -1
- package/dist/src/commands/api-keys.js +119 -24
- package/dist/src/commands/chat.js +6 -6
- package/dist/src/commands/code.js +103 -57
- package/dist/src/constants/command-structure.js +2 -0
- package/dist/src/services/api-key-service.js +64 -1
- package/dist/src/utils/config-loader.js +217 -0
- package/dist/src/utils/error-handler.js +98 -22
- package/dist/tests/utils/config-loader.test.js +182 -0
- package/index.ts +19 -19
- package/opencode.json +1 -1
- package/package.json +1 -1
- package/src/commands/api-keys.ts +156 -28
- package/src/commands/chat.ts +6 -6
- package/src/commands/code.ts +119 -58
- package/src/constants/command-structure.ts +2 -0
- package/src/services/api-key-service.ts +100 -2
- package/src/utils/config-loader.ts +261 -0
- package/src/utils/error-handler.ts +120 -23
package/AGENTS.md
CHANGED
|
@@ -70,6 +70,35 @@ Declarative GitOps infrastructure with FluxCD, Kustomize, Helm, and operators.
|
|
|
70
70
|
- Operator-first approach
|
|
71
71
|
- SemVer with release candidates
|
|
72
72
|
|
|
73
|
+
**Helm Values Configuration Process:**
|
|
74
|
+
|
|
75
|
+
1. **Documentation First Approach:**
|
|
76
|
+
- Always fetch official documentation for the specific chart version before writing values
|
|
77
|
+
- Search Artifact Hub for the exact chart version documentation
|
|
78
|
+
- Check the chart's GitHub repository for official docs and examples
|
|
79
|
+
- Verify the exact version being used in the deployment
|
|
80
|
+
|
|
81
|
+
2. **Validation Requirements:**
|
|
82
|
+
- Check for available validation schemas before committing YAML files
|
|
83
|
+
- Use Helm's built-in validation tools (`helm lint`, `helm template`)
|
|
84
|
+
- Validate against JSON schema if available for the chart
|
|
85
|
+
- Ensure YAML syntax correctness with linters
|
|
86
|
+
|
|
87
|
+
3. **Standard Workflow:**
|
|
88
|
+
- Identify chart name and exact version
|
|
89
|
+
- Fetch official documentation from Artifact Hub/GitHub
|
|
90
|
+
- Check for available schemas and validation tools
|
|
91
|
+
- Write values according to official documentation
|
|
92
|
+
- Validate against schema (if available)
|
|
93
|
+
- Test with `helm template` or `helm lint`
|
|
94
|
+
- Commit validated YAML files
|
|
95
|
+
|
|
96
|
+
4. **Quality Assurance:**
|
|
97
|
+
- Never commit unvalidated Helm values
|
|
98
|
+
- Use `helm dependency update` when adding new charts
|
|
99
|
+
- Test rendering with `helm template --dry-run` before deployment
|
|
100
|
+
- Document any custom values with comments referencing official docs
|
|
101
|
+
|
|
73
102
|
#### app
|
|
74
103
|
|
|
75
104
|
Expo + React Native applications with props-first architecture and offline awareness.
|
package/dist/index.js
CHANGED
|
@@ -9,6 +9,8 @@ const commands_1 = require("./src/commands");
|
|
|
9
9
|
const config_checker_1 = require("./src/utils/config-checker");
|
|
10
10
|
const chalk_1 = __importDefault(require("chalk"));
|
|
11
11
|
const package_json_1 = require("./package.json");
|
|
12
|
+
process.env.DOTENV_CONFIG_OVERRIDE = 'true';
|
|
13
|
+
require("dotenv/config");
|
|
12
14
|
// Set version and description
|
|
13
15
|
commander_1.program
|
|
14
16
|
.name('berget')
|
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,32 +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
|
-
//
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
key.
|
|
96
|
+
// Show only first 8 characters of ID for easier reading
|
|
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) +
|
|
64
113
|
lastUsed);
|
|
65
114
|
});
|
|
66
115
|
console.log('');
|
|
@@ -118,13 +167,59 @@ function registerApiKeyCommands(program) {
|
|
|
118
167
|
apiKey
|
|
119
168
|
.command(api_key_service_1.ApiKeyService.COMMANDS.DELETE)
|
|
120
169
|
.description('Delete an API key')
|
|
121
|
-
.argument('<
|
|
122
|
-
.action((
|
|
170
|
+
.argument('<identifier>', 'ID (first 8 chars), full ID, or name of the API key to delete')
|
|
171
|
+
.action((identifier) => __awaiter(this, void 0, void 0, function* () {
|
|
123
172
|
try {
|
|
124
|
-
console.log(chalk_1.default.blue(`Deleting API key ${id}...`));
|
|
125
173
|
const apiKeyService = api_key_service_1.ApiKeyService.getInstance();
|
|
126
|
-
|
|
127
|
-
|
|
174
|
+
// First, get all API keys to find the matching one
|
|
175
|
+
const keys = yield apiKeyService.list();
|
|
176
|
+
// Try to find the key by:
|
|
177
|
+
// 1. Full ID match
|
|
178
|
+
// 2. Short ID (first 8 chars) match
|
|
179
|
+
// 3. Exact name match
|
|
180
|
+
// 4. Partial name match
|
|
181
|
+
// Check for exact matches first (full ID or exact name)
|
|
182
|
+
let exactMatches = keys.filter((key) => String(key.id) === identifier || key.name === identifier);
|
|
183
|
+
// If no exact matches, check for short ID matches
|
|
184
|
+
if (exactMatches.length === 0) {
|
|
185
|
+
exactMatches = keys.filter((key) => String(key.id).substring(0, 8) === identifier);
|
|
186
|
+
}
|
|
187
|
+
// If still no matches, check for partial name matches
|
|
188
|
+
if (exactMatches.length === 0) {
|
|
189
|
+
exactMatches = keys.filter((key) => key.name.toLowerCase().includes(identifier.toLowerCase()));
|
|
190
|
+
}
|
|
191
|
+
// Handle multiple matches
|
|
192
|
+
if (exactMatches.length > 1) {
|
|
193
|
+
console.error(chalk_1.default.red(`Error: Multiple API keys found matching "${identifier}"`));
|
|
194
|
+
console.log('');
|
|
195
|
+
console.log('Please be more specific. Matching keys:');
|
|
196
|
+
exactMatches.forEach((key) => {
|
|
197
|
+
const shortId = String(key.id).substring(0, 8);
|
|
198
|
+
console.log(` ${shortId.padEnd(8)} ${key.name}`);
|
|
199
|
+
});
|
|
200
|
+
console.log('');
|
|
201
|
+
console.log('Use the first 8 characters of the ID to specify which key to delete.');
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
// Handle no matches
|
|
205
|
+
if (exactMatches.length === 0) {
|
|
206
|
+
console.error(chalk_1.default.red(`Error: No API key found matching "${identifier}"`));
|
|
207
|
+
console.log('');
|
|
208
|
+
console.log('Available API keys:');
|
|
209
|
+
keys.forEach((key) => {
|
|
210
|
+
const shortId = String(key.id).substring(0, 8);
|
|
211
|
+
console.log(` ${shortId.padEnd(8)} ${key.name}`);
|
|
212
|
+
});
|
|
213
|
+
console.log('');
|
|
214
|
+
console.log('Use the first 8 characters of the ID, full ID, or name to delete.');
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
const matchingKey = exactMatches[0];
|
|
218
|
+
const keyId = String(matchingKey.id);
|
|
219
|
+
const shortId = keyId.substring(0, 8);
|
|
220
|
+
console.log(chalk_1.default.blue(`Deleting API key ${shortId} (${matchingKey.name})...`));
|
|
221
|
+
yield apiKeyService.delete(keyId);
|
|
222
|
+
console.log(chalk_1.default.green(`✓ API key ${shortId} (${matchingKey.name}) has been deleted`));
|
|
128
223
|
console.log('');
|
|
129
224
|
console.log(chalk_1.default.dim('Applications using this key will no longer be able to authenticate.'));
|
|
130
225
|
console.log(chalk_1.default.dim('Use `berget api-key list` to see your remaining API keys.'));
|
|
@@ -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,
|
|
@@ -48,38 +48,7 @@ const path_1 = __importDefault(require("path"));
|
|
|
48
48
|
const child_process_1 = require("child_process");
|
|
49
49
|
const env_manager_1 = require("../utils/env-manager");
|
|
50
50
|
const client_1 = require("../client");
|
|
51
|
-
|
|
52
|
-
const MODEL_CONFIG = {
|
|
53
|
-
// Model names used in agent configurations (with provider prefix)
|
|
54
|
-
AGENT_MODELS: {
|
|
55
|
-
primary: 'berget/deepseek-r1',
|
|
56
|
-
small: 'berget/gpt-oss',
|
|
57
|
-
},
|
|
58
|
-
// Model definitions in provider configuration (without prefix)
|
|
59
|
-
PROVIDER_MODELS: {
|
|
60
|
-
'deepseek-r1': {
|
|
61
|
-
name: 'GLM-4.6',
|
|
62
|
-
limit: {
|
|
63
|
-
output: 4000,
|
|
64
|
-
context: 90000,
|
|
65
|
-
},
|
|
66
|
-
},
|
|
67
|
-
'gpt-oss': {
|
|
68
|
-
name: 'GPT-OSS',
|
|
69
|
-
limit: {
|
|
70
|
-
output: 4000,
|
|
71
|
-
context: 128000,
|
|
72
|
-
},
|
|
73
|
-
},
|
|
74
|
-
'llama-8b': {
|
|
75
|
-
name: 'llama-3.1-8b',
|
|
76
|
-
limit: {
|
|
77
|
-
output: 4000,
|
|
78
|
-
context: 128000,
|
|
79
|
-
},
|
|
80
|
-
},
|
|
81
|
-
},
|
|
82
|
-
};
|
|
51
|
+
const config_loader_1 = require("../utils/config-loader");
|
|
83
52
|
/**
|
|
84
53
|
* Check if current directory has git
|
|
85
54
|
*/
|
|
@@ -99,6 +68,7 @@ function mergeConfigurations(currentConfig, latestConfig) {
|
|
|
99
68
|
return __awaiter(this, void 0, void 0, function* () {
|
|
100
69
|
try {
|
|
101
70
|
const client = (0, client_1.createAuthenticatedClient)();
|
|
71
|
+
const modelConfig = (0, config_loader_1.getModelConfig)();
|
|
102
72
|
console.log(chalk_1.default.blue('🤖 Using AI to merge configurations...'));
|
|
103
73
|
const mergePrompt = `You are a configuration merge specialist. Merge these two OpenCode configurations:
|
|
104
74
|
|
|
@@ -118,7 +88,7 @@ Merge rules:
|
|
|
118
88
|
Return ONLY the merged JSON configuration, no explanations.`;
|
|
119
89
|
const response = yield client.POST('/v1/chat/completions', {
|
|
120
90
|
body: {
|
|
121
|
-
model:
|
|
91
|
+
model: modelConfig.primary,
|
|
122
92
|
messages: [
|
|
123
93
|
{
|
|
124
94
|
role: 'user',
|
|
@@ -296,6 +266,23 @@ function getProjectName() {
|
|
|
296
266
|
}
|
|
297
267
|
return path_1.default.basename(process.cwd());
|
|
298
268
|
}
|
|
269
|
+
/**
|
|
270
|
+
* Load the latest agent configuration from opencode.json
|
|
271
|
+
*/
|
|
272
|
+
function loadLatestAgentConfig() {
|
|
273
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
274
|
+
try {
|
|
275
|
+
const configPath = path_1.default.join(__dirname, '../../opencode.json');
|
|
276
|
+
const configContent = yield (0, promises_1.readFile)(configPath, 'utf8');
|
|
277
|
+
const config = JSON.parse(configContent);
|
|
278
|
+
return config.agent || {};
|
|
279
|
+
}
|
|
280
|
+
catch (error) {
|
|
281
|
+
console.warn(chalk_1.default.yellow('⚠️ Could not load latest agent config, using fallback'));
|
|
282
|
+
return {};
|
|
283
|
+
}
|
|
284
|
+
});
|
|
285
|
+
}
|
|
299
286
|
/**
|
|
300
287
|
* Check if opencode is installed
|
|
301
288
|
*/
|
|
@@ -556,6 +543,9 @@ function registerCodeCommands(program) {
|
|
|
556
543
|
}
|
|
557
544
|
// Prepare .env file path for safe update
|
|
558
545
|
const envPath = path_1.default.join(process.cwd(), '.env');
|
|
546
|
+
// Load latest agent configuration to ensure consistency
|
|
547
|
+
const latestAgentConfig = yield loadLatestAgentConfig();
|
|
548
|
+
const modelConfig = (0, config_loader_1.getModelConfig)();
|
|
559
549
|
// Create opencode.json config with optimized agent-based format
|
|
560
550
|
const config = {
|
|
561
551
|
$schema: 'https://opencode.ai/config.json',
|
|
@@ -563,11 +553,11 @@ function registerCodeCommands(program) {
|
|
|
563
553
|
theme: 'berget-dark',
|
|
564
554
|
share: 'manual',
|
|
565
555
|
autoupdate: true,
|
|
566
|
-
model:
|
|
567
|
-
small_model:
|
|
556
|
+
model: modelConfig.primary,
|
|
557
|
+
small_model: modelConfig.small,
|
|
568
558
|
agent: {
|
|
569
559
|
fullstack: {
|
|
570
|
-
model:
|
|
560
|
+
model: modelConfig.primary,
|
|
571
561
|
temperature: 0.3,
|
|
572
562
|
top_p: 0.9,
|
|
573
563
|
mode: 'primary',
|
|
@@ -576,7 +566,7 @@ function registerCodeCommands(program) {
|
|
|
576
566
|
prompt: 'Voice: Scandinavian calm—precise, concise, confident; no fluff. You are Berget Code Fullstack agent. Act as a router and coordinator in a monorepo. Bottom-up schema: database → OpenAPI → generated types. Top-down types: API → UI → components. Use openapi-fetch and Zod at every boundary; compile-time errors are desired when contracts change. Routing rules: if task/paths match /apps/frontend or React (.tsx) → use frontend; if /apps/app or Expo/React Native → app; if /infra, /k8s, flux-system, kustomization.yaml, Helm values → devops; if /services, Koa routers, services/adapters/domain → backend. If ambiguous, remain fullstack and outline the end-to-end plan, then delegate subtasks to the right persona. Security: validate inputs; secrets via FluxCD SOPS/Sealed Secrets. Documentation is generated from code—never duplicated. CRITICAL: When all implementation tasks are complete and ready for merge, ALWAYS invoke @quality subagent to handle testing, building, and complete PR management including URL provision.',
|
|
577
567
|
},
|
|
578
568
|
frontend: {
|
|
579
|
-
model:
|
|
569
|
+
model: modelConfig.primary,
|
|
580
570
|
temperature: 0.4,
|
|
581
571
|
top_p: 0.9,
|
|
582
572
|
mode: 'primary',
|
|
@@ -586,7 +576,7 @@ function registerCodeCommands(program) {
|
|
|
586
576
|
prompt: 'You are Berget Code Frontend agent. Voice: Scandinavian calm—precise, concise, confident. React 18 + TypeScript. Tailwind + Shadcn UI only via the design system (index.css, tailwind.config.ts). Use semantic tokens for color/spacing/typography/motion; never ad-hoc classes or inline colors. Components are pure and responsive; props-first data; minimal global state (Zustand/Jotai). Accessibility and keyboard navigation mandatory. Mock data only at init under /data via typed hooks (e.g., useProducts() reading /data/products.json). Design: minimal, balanced, quiet motion. CRITICAL: When all frontend implementation tasks are complete and ready for merge, ALWAYS invoke @quality subagent to handle testing, building, and complete PR management including URL provision.',
|
|
587
577
|
},
|
|
588
578
|
backend: {
|
|
589
|
-
model:
|
|
579
|
+
model: modelConfig.primary,
|
|
590
580
|
temperature: 0.3,
|
|
591
581
|
top_p: 0.9,
|
|
592
582
|
mode: 'primary',
|
|
@@ -594,8 +584,9 @@ function registerCodeCommands(program) {
|
|
|
594
584
|
description: 'Functional, modular Koa + TypeScript services; schema-first with code quality focus.',
|
|
595
585
|
prompt: 'You are Berget Code Backend agent. Voice: Scandinavian calm—precise, concise, confident. TypeScript + Koa. Prefer many small pure functions; avoid big try/catch blocks. Routes thin; logic in services/adapters/domain. Validate with Zod; auto-generate OpenAPI. Adapters isolate external systems; domain never depends on framework. Test with supertest; idempotent and stateless by default. Each microservice emits an OpenAPI contract; changes propagate upward to types. Code Quality & Refactoring Principles: Apply Single Responsibility Principle, fail fast with explicit errors, eliminate code duplication, remove nested complexity, use descriptive error codes, keep functions under 30 lines. Always leave code cleaner and more readable than you found it. CRITICAL: When all backend implementation tasks are complete and ready for merge, ALWAYS invoke @quality subagent to handle testing, building, and complete PR management including URL provision.',
|
|
596
586
|
},
|
|
597
|
-
devops
|
|
598
|
-
|
|
587
|
+
// Use centralized devops configuration with Helm guidelines
|
|
588
|
+
devops: latestAgentConfig.devops || {
|
|
589
|
+
model: modelConfig.primary,
|
|
599
590
|
temperature: 0.3,
|
|
600
591
|
top_p: 0.8,
|
|
601
592
|
mode: 'primary',
|
|
@@ -604,7 +595,7 @@ function registerCodeCommands(program) {
|
|
|
604
595
|
prompt: 'You are Berget Code DevOps agent. Voice: Scandinavian calm—precise, concise, confident. Start simple: k8s/{deployment,service,ingress}. Add FluxCD sync to repo and image automation. Use Kustomize bases/overlays (staging, production). Add dependencies via Helm from upstream sources; prefer native operators when available (CloudNativePG, cert-manager, external-dns). SemVer with -rc tags keeps CI environments current. Observability with Prometheus/Grafana. No manual kubectl in production—Git is the source of truth.',
|
|
605
596
|
},
|
|
606
597
|
app: {
|
|
607
|
-
model:
|
|
598
|
+
model: modelConfig.primary,
|
|
608
599
|
temperature: 0.4,
|
|
609
600
|
top_p: 0.9,
|
|
610
601
|
mode: 'primary',
|
|
@@ -614,7 +605,7 @@ function registerCodeCommands(program) {
|
|
|
614
605
|
prompt: 'You are Berget Code App agent. Voice: Scandinavian calm—precise, concise, confident. Expo + React Native + TypeScript. Structure by components/hooks/services/navigation. Components are pure; data via props; refactor shared logic into hooks/stores. Share tokens with frontend. Mock data in /data via typed hooks; later replace with live APIs. Offline via SQLite/MMKV; notifications via Expo. Request permissions only when needed. Subtle, meaningful motion; light/dark parity.',
|
|
615
606
|
},
|
|
616
607
|
security: {
|
|
617
|
-
model:
|
|
608
|
+
model: modelConfig.primary,
|
|
618
609
|
temperature: 0.2,
|
|
619
610
|
top_p: 0.8,
|
|
620
611
|
mode: 'subagent',
|
|
@@ -623,7 +614,7 @@ function registerCodeCommands(program) {
|
|
|
623
614
|
prompt: '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.',
|
|
624
615
|
},
|
|
625
616
|
quality: {
|
|
626
|
-
model:
|
|
617
|
+
model: modelConfig.primary,
|
|
627
618
|
temperature: 0.1,
|
|
628
619
|
top_p: 0.9,
|
|
629
620
|
mode: 'subagent',
|
|
@@ -681,7 +672,7 @@ function registerCodeCommands(program) {
|
|
|
681
672
|
baseURL: 'https://api.berget.ai/v1',
|
|
682
673
|
apiKey: '{env:BERGET_API_KEY}',
|
|
683
674
|
},
|
|
684
|
-
models:
|
|
675
|
+
models: (0, config_loader_1.getProviderModels)(),
|
|
685
676
|
},
|
|
686
677
|
},
|
|
687
678
|
};
|
|
@@ -778,6 +769,12 @@ Declarative GitOps infrastructure with FluxCD, Kustomize, Helm, and operators.
|
|
|
778
769
|
- Operator-first approach
|
|
779
770
|
- SemVer with release candidates
|
|
780
771
|
|
|
772
|
+
**Helm Values Configuration Process:**
|
|
773
|
+
1. Documentation First Approach: Always fetch official documentation from Artifact Hub/GitHub for the specific chart version before writing values. Search Artifact Hub for exact chart version documentation, check the chart's GitHub repository for official docs and examples, verify the exact version being used in the deployment.
|
|
774
|
+
2. Validation Requirements: Check for available validation schemas before committing YAML files. Use Helm's built-in validation tools (helm lint, helm template). Validate against JSON schema if available for the chart. Ensure YAML syntax correctness with linters.
|
|
775
|
+
3. Standard Workflow: Identify chart name and exact version. Fetch official documentation from Artifact Hub/GitHub. Check for available schemas and validation tools. Write values according to official documentation. Validate against schema (if available). Test with helm template or helm lint. Commit validated YAML files.
|
|
776
|
+
4. Quality Assurance: Never commit unvalidated Helm values. Use helm dependency update when adding new charts. Test rendering with helm template --dry-run before deployment. Document any custom values with comments referencing official docs.
|
|
777
|
+
|
|
781
778
|
#### app
|
|
782
779
|
Expo + React Native applications with props-first architecture and offline awareness.
|
|
783
780
|
|
|
@@ -949,7 +946,6 @@ All agents follow these principles:
|
|
|
949
946
|
}
|
|
950
947
|
// Set environment variables for opencode
|
|
951
948
|
const env = Object.assign({}, process.env);
|
|
952
|
-
env.OPENCODE_API_KEY = config.apiKey;
|
|
953
949
|
// Prepare opencode command
|
|
954
950
|
const opencodeArgs = [];
|
|
955
951
|
if (prompt) {
|
|
@@ -984,6 +980,46 @@ All agents follow these principles:
|
|
|
984
980
|
(0, error_handler_1.handleError)('Failed to run OpenCode', error);
|
|
985
981
|
}
|
|
986
982
|
}));
|
|
983
|
+
code
|
|
984
|
+
.command(command_structure_1.SUBCOMMANDS.CODE.SERVE)
|
|
985
|
+
.description('Start OpenCode web server')
|
|
986
|
+
.option('-p, --port <port>', 'Port to run the server on (default: 3000)')
|
|
987
|
+
.option('-h, --host <host>', 'Host to bind the server to (default: localhost)')
|
|
988
|
+
.option('-y, --yes', 'Automatically answer yes to all prompts (for automation)')
|
|
989
|
+
.action((options) => __awaiter(this, void 0, void 0, function* () {
|
|
990
|
+
try {
|
|
991
|
+
// Ensure opencode is installed
|
|
992
|
+
if (!(yield ensureOpencodeInstalled(options.yes))) {
|
|
993
|
+
return;
|
|
994
|
+
}
|
|
995
|
+
console.log(chalk_1.default.cyan('🚀 Starting OpenCode web server...'));
|
|
996
|
+
// Prepare opencode serve command
|
|
997
|
+
const serveArgs = ['serve'];
|
|
998
|
+
if (options.port) {
|
|
999
|
+
serveArgs.push('--port', options.port);
|
|
1000
|
+
}
|
|
1001
|
+
if (options.host) {
|
|
1002
|
+
serveArgs.push('--host', options.host);
|
|
1003
|
+
}
|
|
1004
|
+
// Spawn opencode serve process
|
|
1005
|
+
const opencode = (0, child_process_1.spawn)('opencode', serveArgs, {
|
|
1006
|
+
stdio: 'inherit',
|
|
1007
|
+
shell: true,
|
|
1008
|
+
});
|
|
1009
|
+
opencode.on('close', (code) => {
|
|
1010
|
+
if (code !== 0) {
|
|
1011
|
+
console.log(chalk_1.default.red(`OpenCode server exited with code ${code}`));
|
|
1012
|
+
}
|
|
1013
|
+
});
|
|
1014
|
+
opencode.on('error', (error) => {
|
|
1015
|
+
console.error(chalk_1.default.red('Failed to start OpenCode server:'));
|
|
1016
|
+
console.error(error.message);
|
|
1017
|
+
});
|
|
1018
|
+
}
|
|
1019
|
+
catch (error) {
|
|
1020
|
+
(0, error_handler_1.handleError)('Failed to start OpenCode server', error);
|
|
1021
|
+
}
|
|
1022
|
+
}));
|
|
987
1023
|
code
|
|
988
1024
|
.command(command_structure_1.SUBCOMMANDS.CODE.UPDATE)
|
|
989
1025
|
.description('Update OpenCode and agents to latest versions')
|
|
@@ -1019,6 +1055,9 @@ All agents follow these principles:
|
|
|
1019
1055
|
console.log(chalk_1.default.dim(` Model: ${currentConfig.model}`));
|
|
1020
1056
|
console.log(chalk_1.default.dim(` Theme: ${currentConfig.theme}`));
|
|
1021
1057
|
console.log(chalk_1.default.dim(` Agents: ${Object.keys(currentConfig.agent || {}).length} configured`));
|
|
1058
|
+
// Load latest agent configuration to ensure consistency
|
|
1059
|
+
const latestAgentConfig = yield loadLatestAgentConfig();
|
|
1060
|
+
const modelConfig = (0, config_loader_1.getModelConfig)();
|
|
1022
1061
|
// Create latest configuration with all improvements
|
|
1023
1062
|
const latestConfig = {
|
|
1024
1063
|
$schema: 'https://opencode.ai/config.json',
|
|
@@ -1026,11 +1065,11 @@ All agents follow these principles:
|
|
|
1026
1065
|
theme: 'berget-dark',
|
|
1027
1066
|
share: 'manual',
|
|
1028
1067
|
autoupdate: true,
|
|
1029
|
-
model:
|
|
1030
|
-
small_model:
|
|
1068
|
+
model: modelConfig.primary,
|
|
1069
|
+
small_model: modelConfig.small,
|
|
1031
1070
|
agent: {
|
|
1032
1071
|
fullstack: {
|
|
1033
|
-
model:
|
|
1072
|
+
model: modelConfig.primary,
|
|
1034
1073
|
temperature: 0.3,
|
|
1035
1074
|
top_p: 0.9,
|
|
1036
1075
|
mode: 'primary',
|
|
@@ -1039,7 +1078,7 @@ All agents follow these principles:
|
|
|
1039
1078
|
prompt: 'Voice: Scandinavian calm—precise, concise, confident; no fluff. You are Berget Code Fullstack agent. Act as a router and coordinator in a monorepo. Bottom-up schema: database → OpenAPI → generated types. Top-down types: API → UI → components. Use openapi-fetch and Zod at every boundary; compile-time errors are desired when contracts change. Routing rules: if task/paths match /apps/frontend or React (.tsx) → use frontend; if /apps/app or Expo/React Native → app; if /infra, /k8s, flux-system, kustomization.yaml, Helm values → devops; if /services, Koa routers, services/adapters/domain → backend. If ambiguous, remain fullstack and outline the end-to-end plan, then delegate subtasks to the right persona. Security: validate inputs; secrets via FluxCD SOPS/Sealed Secrets. Documentation is generated from code—never duplicated. CRITICAL: When all implementation tasks are complete and ready for merge, ALWAYS invoke @quality subagent to handle testing, building, and complete PR management including URL provision.',
|
|
1040
1079
|
},
|
|
1041
1080
|
frontend: {
|
|
1042
|
-
model:
|
|
1081
|
+
model: modelConfig.primary,
|
|
1043
1082
|
temperature: 0.4,
|
|
1044
1083
|
top_p: 0.9,
|
|
1045
1084
|
mode: 'primary',
|
|
@@ -1049,7 +1088,7 @@ All agents follow these principles:
|
|
|
1049
1088
|
prompt: 'You are Berget Code Frontend agent. Voice: Scandinavian calm—precise, concise, confident. React 18 + TypeScript. Tailwind + Shadcn UI only via the design system (index.css, tailwind.config.ts). Use semantic tokens for color/spacing/typography/motion; never ad-hoc classes or inline colors. Components are pure and responsive; props-first data; minimal global state (Zustand/Jotai). Accessibility and keyboard navigation mandatory. Mock data only at init under /data via typed hooks (e.g., useProducts() reading /data/products.json). Design: minimal, balanced, quiet motion. CRITICAL: When all frontend implementation tasks are complete and ready for merge, ALWAYS invoke @quality subagent to handle testing, building, and complete PR management including URL provision.',
|
|
1050
1089
|
},
|
|
1051
1090
|
backend: {
|
|
1052
|
-
model:
|
|
1091
|
+
model: modelConfig.primary,
|
|
1053
1092
|
temperature: 0.3,
|
|
1054
1093
|
top_p: 0.9,
|
|
1055
1094
|
mode: 'primary',
|
|
@@ -1057,8 +1096,9 @@ All agents follow these principles:
|
|
|
1057
1096
|
description: 'Functional, modular Koa + TypeScript services; schema-first with code quality focus.',
|
|
1058
1097
|
prompt: 'You are Berget Code Backend agent. Voice: Scandinavian calm—precise, concise, confident. TypeScript + Koa. Prefer many small pure functions; avoid big try/catch blocks. Routes thin; logic in services/adapters/domain. Validate with Zod; auto-generate OpenAPI. Adapters isolate external systems; domain never depends on framework. Test with supertest; idempotent and stateless by default. Each microservice emits an OpenAPI contract; changes propagate upward to types. Code Quality & Refactoring Principles: Apply Single Responsibility Principle, fail fast with explicit errors, eliminate code duplication, remove nested complexity, use descriptive error codes, keep functions under 30 lines. Always leave code cleaner and more readable than you found it. CRITICAL: When all backend implementation tasks are complete and ready for merge, ALWAYS invoke @quality subagent to handle testing, building, and complete PR management including URL provision.',
|
|
1059
1098
|
},
|
|
1060
|
-
devops
|
|
1061
|
-
|
|
1099
|
+
// Use centralized devops configuration with Helm guidelines
|
|
1100
|
+
devops: latestAgentConfig.devops || {
|
|
1101
|
+
model: modelConfig.primary,
|
|
1062
1102
|
temperature: 0.3,
|
|
1063
1103
|
top_p: 0.8,
|
|
1064
1104
|
mode: 'primary',
|
|
@@ -1067,7 +1107,7 @@ All agents follow these principles:
|
|
|
1067
1107
|
prompt: 'You are Berget Code DevOps agent. Voice: Scandinavian calm—precise, concise, confident. Start simple: k8s/{deployment,service,ingress}. Add FluxCD sync to repo and image automation. Use Kustomize bases/overlays (staging, production). Add dependencies via Helm from upstream sources; prefer native operators when available (CloudNativePG, cert-manager, external-dns). SemVer with -rc tags keeps CI environments current. Observability with Prometheus/Grafana. No manual kubectl in production—Git is the source of truth. For testing, building, and PR management, use @quality subagent.',
|
|
1068
1108
|
},
|
|
1069
1109
|
app: {
|
|
1070
|
-
model:
|
|
1110
|
+
model: modelConfig.primary,
|
|
1071
1111
|
temperature: 0.4,
|
|
1072
1112
|
top_p: 0.9,
|
|
1073
1113
|
mode: 'primary',
|
|
@@ -1077,7 +1117,7 @@ All agents follow these principles:
|
|
|
1077
1117
|
prompt: 'You are Berget Code App agent. Voice: Scandinavian calm—precise, concise, confident. Expo + React Native + TypeScript. Structure by components/hooks/services/navigation. Components are pure; data via props; refactor shared logic into hooks/stores. Share tokens with frontend. Mock data in /data via typed hooks; later replace with live APIs. Offline via SQLite/MMKV; notifications via Expo. Request permissions only when needed. Subtle, meaningful motion; light/dark parity. For testing, building, and PR management, use @quality subagent.',
|
|
1078
1118
|
},
|
|
1079
1119
|
security: {
|
|
1080
|
-
model:
|
|
1120
|
+
model: modelConfig.primary,
|
|
1081
1121
|
temperature: 0.2,
|
|
1082
1122
|
top_p: 0.8,
|
|
1083
1123
|
mode: 'subagent',
|
|
@@ -1086,7 +1126,7 @@ All agents follow these principles:
|
|
|
1086
1126
|
prompt: '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. Workflow: Always follow branch_strategy and commit_convention from workflow section. Never work directly in main. Agent awareness: Review code from all personas (frontend, backend, app, devops). If implementation changes are needed, suggest <tab> to switch to appropriate persona after security assessment.',
|
|
1087
1127
|
},
|
|
1088
1128
|
quality: {
|
|
1089
|
-
model:
|
|
1129
|
+
model: modelConfig.primary,
|
|
1090
1130
|
temperature: 0.1,
|
|
1091
1131
|
top_p: 0.9,
|
|
1092
1132
|
mode: 'subagent',
|
|
@@ -1149,7 +1189,7 @@ All agents follow these principles:
|
|
|
1149
1189
|
baseURL: 'https://api.berget.ai/v1',
|
|
1150
1190
|
apiKey: '{env:BERGET_API_KEY}',
|
|
1151
1191
|
},
|
|
1152
|
-
models:
|
|
1192
|
+
models: (0, config_loader_1.getProviderModels)(),
|
|
1153
1193
|
},
|
|
1154
1194
|
},
|
|
1155
1195
|
};
|
|
@@ -1177,7 +1217,7 @@ All agents follow these principles:
|
|
|
1177
1217
|
console.log(chalk_1.default.cyan(' • Security agent converted to subagent (read-only)'));
|
|
1178
1218
|
}
|
|
1179
1219
|
// Check for GLM-4.6 optimizations
|
|
1180
|
-
if (!((_h = (_g = (_f = (_e = (_d = currentConfig.provider) === null || _d === void 0 ? void 0 : _d.berget) === null || _e === void 0 ? void 0 : _e.models) === null || _f === void 0 ? void 0 : _f[
|
|
1220
|
+
if (!((_h = (_g = (_f = (_e = (_d = currentConfig.provider) === null || _d === void 0 ? void 0 : _d.berget) === null || _e === void 0 ? void 0 : _e.models) === null || _f === void 0 ? void 0 : _f[modelConfig.primary.replace('berget/', '')]) === null || _g === void 0 ? void 0 : _g.limit) === null || _h === void 0 ? void 0 : _h.context)) {
|
|
1181
1221
|
console.log(chalk_1.default.cyan(' • GLM-4.6 token limits and auto-compaction'));
|
|
1182
1222
|
}
|
|
1183
1223
|
console.log(chalk_1.default.cyan(' • Latest agent prompts and improvements'));
|
|
@@ -1291,6 +1331,12 @@ Declarative GitOps infrastructure with FluxCD, Kustomize, Helm, and operators.
|
|
|
1291
1331
|
- Operator-first approach
|
|
1292
1332
|
- SemVer with release candidates
|
|
1293
1333
|
|
|
1334
|
+
**Helm Values Configuration Process:**
|
|
1335
|
+
1. Documentation First Approach: Always fetch official documentation from Artifact Hub/GitHub for the specific chart version before writing values. Search Artifact Hub for exact chart version documentation, check the chart's GitHub repository for official docs and examples, verify the exact version being used in the deployment.
|
|
1336
|
+
2. Validation Requirements: Check for available validation schemas before committing YAML files. Use Helm's built-in validation tools (helm lint, helm template). Validate against JSON schema if available for the chart. Ensure YAML syntax correctness with linters.
|
|
1337
|
+
3. Standard Workflow: Identify chart name and exact version. Fetch official documentation from Artifact Hub/GitHub. Check for available schemas and validation tools. Write values according to official documentation. Validate against schema (if available). Test with helm template or helm lint. Commit validated YAML files.
|
|
1338
|
+
4. Quality Assurance: Never commit unvalidated Helm values. Use helm dependency update when adding new charts. Test rendering with helm template --dry-run before deployment. Document any custom values with comments referencing official docs.
|
|
1339
|
+
|
|
1294
1340
|
#### app
|
|
1295
1341
|
Expo + React Native applications with props-first architecture and offline awareness.
|
|
1296
1342
|
|
|
@@ -38,6 +38,7 @@ exports.SUBCOMMANDS = {
|
|
|
38
38
|
INIT: 'init',
|
|
39
39
|
RUN: 'run',
|
|
40
40
|
UPDATE: 'update',
|
|
41
|
+
SERVE: 'serve',
|
|
41
42
|
},
|
|
42
43
|
// API Keys commands
|
|
43
44
|
API_KEYS: {
|
|
@@ -172,5 +173,6 @@ exports.COMMAND_DESCRIPTIONS = {
|
|
|
172
173
|
[exports.COMMAND_GROUPS.CODE]: 'AI-powered coding assistant with OpenCode',
|
|
173
174
|
[`${exports.COMMAND_GROUPS.CODE} ${exports.SUBCOMMANDS.CODE.INIT}`]: 'Initialize project for AI coding assistant',
|
|
174
175
|
[`${exports.COMMAND_GROUPS.CODE} ${exports.SUBCOMMANDS.CODE.RUN}`]: 'Run AI coding assistant',
|
|
176
|
+
[`${exports.COMMAND_GROUPS.CODE} ${exports.SUBCOMMANDS.CODE.SERVE}`]: 'Start OpenCode web server',
|
|
175
177
|
[`${exports.COMMAND_GROUPS.CODE} ${exports.SUBCOMMANDS.CODE.UPDATE}`]: 'Update OpenCode and agents to latest versions',
|
|
176
178
|
};
|