berget 2.0.6 → 2.1.1

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 CHANGED
@@ -56,6 +56,10 @@ Functional, modular Koa + TypeScript services with schema-first approach and cod
56
56
 
57
57
  #### devops
58
58
 
59
+ # ⚠️ ABSOLUTE RULE: kubectl apply NEVER
60
+
61
+ **THIS RULE HAS NO EXCEPTIONS - APPLIES TO ALL ENVIRONMENTS: DEV, STAGING, PRODUCTION**
62
+
59
63
  Declarative GitOps infrastructure with FluxCD, Kustomize, Helm, and operators.
60
64
 
61
65
  **Use when:**
@@ -70,6 +74,159 @@ Declarative GitOps infrastructure with FluxCD, Kustomize, Helm, and operators.
70
74
  - Operator-first approach
71
75
  - SemVer with release candidates
72
76
 
77
+ ## 🚨 CRITICAL: WHY kubectl apply DESTROYS GITOPS
78
+
79
+ **kubectl apply is fundamentally incompatible with GitOps because it:**
80
+
81
+ 1. **Overwrites FluxCD metadata** - The `kubectl.kubernetes.io/last-applied-configuration` annotation gets replaced with kubectl's version, breaking FluxCD's tracking
82
+ 2. **Breaks the single source of truth** - Your cluster state diverges from Git state, making Git no longer authoritative
83
+ 3. **Creates synchronization conflicts** - FluxCD cannot reconcile differences between Git and cluster state
84
+ 4. **Makes debugging impossible** - Manual changes are invisible in Git history
85
+ 5. **Undermines the entire GitOps model** - The promise of "Git as source of truth" is broken
86
+
87
+ ## 📋 EXACTLY WHAT GETS DESTROYED
88
+
89
+ When you run `kubectl apply`, these critical metadata fields are corrupted:
90
+
91
+ ```yaml
92
+ # BEFORE: FluxCD-managed resource
93
+ metadata:
94
+ annotations:
95
+ kubectl.kubernetes.io/last-applied-configuration: |
96
+ {"apiVersion":"apps/v1","kind":"Deployment","metadata":{"annotations":{},"name":"app","namespace":"default"},"spec":{"template":{"spec":{"containers":[{"image":"nginx:1.21","name":"nginx"}]}}}}
97
+ kustomize.toolkit.fluxcd.io/checksum: a1b2c3d4e5f6
98
+ kustomize.toolkit.fluxcd.io/ssa: Merge
99
+
100
+ # AFTER: kubectl apply destroys this
101
+ metadata:
102
+ annotations:
103
+ kubectl.kubernetes.io/last-applied-configuration: |
104
+ {"apiVersion":"apps/v1","kind":"Deployment","metadata":{"annotations":{},"name":"app","namespace":"default"},"spec":{"template":{"spec":{"containers":[{"image":"nginx:1.22","name":"nginx"}]}}}}
105
+ # kustomize.toolkit.fluxcd.io/checksum: GONE!
106
+ # kustomize.toolkit.fluxcd.io/ssa: GONE!
107
+ ```
108
+
109
+ ## 🔥 CONSEQUENCES OF USING kubectl apply
110
+
111
+ **Immediate Impact:**
112
+ - FluxCD loses track of the resource
113
+ - Future Git commits may not apply correctly
114
+ - Resource becomes "orphaned" from GitOps control
115
+
116
+ **Long-term Damage:**
117
+ - Cluster drift becomes undetectable
118
+ - Rollback capabilities are compromised
119
+ - Audit trail is broken
120
+ - Team loses trust in GitOps process
121
+
122
+ **Recovery Required:**
123
+ - Manual intervention to restore FluxCD metadata
124
+ - Potential resource recreation
125
+ - Downtime during recovery
126
+ - Complete audit of affected resources
127
+
128
+ ## 🚨 KRITISKA REGLER FÖR FLUXCD-kluster
129
+
130
+ # ⚠️ ABSOLUT ALDRIG: kubectl apply
131
+
132
+ **DENNA REGLER HAR INGA UNDTAG - GÄLLER ALLTID: DEV, STAGING, PRODUCTION**
133
+
134
+ **ABSOLUT ALDRIG använd `kubectl apply` i FluxCD-hanterade kluster!**
135
+
136
+ ### ❌ FORBUDNA OPERATIONER
137
+
138
+ ```bash
139
+ # ❌ ALDRIG GÖR DETTA!
140
+ kubectl apply -f deployment.yaml
141
+ kubectl apply -f kustomization.yaml
142
+ kubectl apply -f flux-system/ # SPECIELT INTE FLUXCD-MANIFEST!
143
+ kubectl create -f ...
144
+ kubectl replace -f ...
145
+ kubectl edit deployment/...
146
+ kubectl patch deployment/...
147
+ ```
148
+
149
+ ### ✅ TILLÅTNA OPERATIONER (Read-Only)
150
+
151
+ ```bash
152
+ # ✅ SÄKERT FÖR DIAGNOSTIK
153
+ kubectl get pods
154
+ kubectl describe deployment/app
155
+ kubectl logs -f pod/name
156
+ kubectl get events
157
+ kubectl top nodes
158
+ ```
159
+
160
+ ### 🔄 RÄTT SÄTT ATT GÖRA ÄNDRINGAR
161
+
162
+ 1. **Git är sanningens källa** - alla ändringar måste gå via Git repository
163
+ 2. **FluxCD synkroniserar automatiskt** - ändra YAML-filer, inte klustret direkt
164
+ 3. **Använd PR workflow** - commit ändringar, skapa PR, låt FluxCD hantera deployment
165
+
166
+ ### 🚨 VAD HÄNDER OM DU ÄNDÅ ANVÄNDER kubectl apply?
167
+
168
+ **DET HÄNDER OM DU ANVÄNDER kubectl apply:**
169
+
170
+ - **Förstör FluxCD-metadata** - `kubectl.kubernetes.io/last-applied-configuration` skrivs över
171
+ - **Breakar GitOps-modellen** - klustret divergerar från Git-repository
172
+ - **FluxCD kan inte synkronisera** - konflikter mellan Git-state och kluster-state
173
+ - **Svår att diagnostisera** - manuella ändringar är osynliga i Git-historiken
174
+
175
+ **RESULTATET: FluxCD FÖRLORAR KONTROLLEN OCH KLUSTRET BLIR O-SYNKRONISERAT FRÅN GIT!**
176
+
177
+ ### 🆘 NÖDSITUATIONER
178
+
179
+ ```bash
180
+ # Pausa FluxCD temporärt
181
+ flux suspend kustomization app-name
182
+
183
+ # Gör nödvändiga ändringar i Git
184
+ git commit -m "emergency fix"
185
+ git push
186
+
187
+ # Återuppta FluxCD
188
+ flux resume kustomization app-name
189
+ ```
190
+
191
+ ### 💡 MINNESREGEL
192
+
193
+ > **"Git first, kubectl never"**
194
+ >
195
+ > Om du måste använda `kubectl apply` - gör det inte. Gör en ändring i Git istället.
196
+
197
+ ### 📋 CHECKLIST FÖR ÄNDRINGAR
198
+
199
+ - [ ] Ändring gjord i Git repository?
200
+ - [ ] PR skapad och granskad?
201
+ - [ ] FluxCD synkroniserar korrekt?
202
+ - [ ] Ingen `kubectl apply` använd?
203
+ - [ ] Kluster-state matchar Git-state?
204
+
205
+ **VIKTIGT:** Dessa regler gäller ALLTID, även i utvecklingsmiljöer och tester!
206
+
207
+ ### 💡 MINNESREGEL
208
+
209
+ > **"Git first, kubectl never"**
210
+ >
211
+ > Om du måste använda `kubectl apply` - gör det inte. Gör en ändring i Git istället.
212
+
213
+ ### 📋 CHECKLIST FÖR ÄNDRINGAR
214
+
215
+ - [ ] Ändring gjord i Git repository?
216
+ - [ ] PR skapad och granskad?
217
+ - [ ] FluxCD synkroniserar korrekt?
218
+ - [ ] Ingen `kubectl apply` använd?
219
+ - [ ] Kluster-state matchar Git-state?
220
+
221
+ **VIKTIGT:** Dessa regler gäller ALLTID, även i utvecklingsmiljöer och tester!
222
+
223
+ ---
224
+
225
+ ## ⚠️ ABSOLUT SLUTREGEL: INGA UNDTAG
226
+
227
+ **kubectl apply är FÖRBJUDET i ALLA FluxCD-kluster, ALLTID, utan undantag.**
228
+ **Detta inkluderar: dev, staging, production, testmiljöer, lokala kluster, ALLT.**
229
+
73
230
  **Helm Values Configuration Process:**
74
231
 
75
232
  1. **Documentation First Approach:**
@@ -206,8 +363,12 @@ BERGET_API_KEY=your_api_key_here
206
363
 
207
364
  All agents follow these principles:
208
365
 
209
- - Never work directly in main branch
366
+ - **NEVER work directly in main branch** - ALWAYS use pull requests
367
+ - **NEVER use 'git add .'** - ALWAYS add specific files with 'git add path/to/file'
368
+ - **ALWAYS clean up test files, documentation files, and temporary artifacts before committing**
369
+ - **ALWAYS ensure git history maintains production quality** - no test commits, no debugging code
370
+ - **ALWAYS create descriptive commit messages following project conventions**
371
+ - **ALWAYS run tests and build before creating PR**
210
372
  - Follow branch strategy and commit conventions
211
373
  - Create PRs for new functionality
212
- - Run tests before committing
213
374
  - Address reviewer feedback promptly
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "berget",
3
- "version": "2.0.6",
3
+ "version": "2.1.1",
4
4
  "main": "dist/index.js",
5
5
  "bin": {
6
6
  "berget": "dist/index.js"
@@ -57,8 +57,7 @@ function registerChatCommands(program) {
57
57
  .command(command_structure_1.SUBCOMMANDS.CHAT.RUN)
58
58
  .description('Run a chat session with a specified model')
59
59
  .argument('[message]', 'Message to send directly (skips interactive mode)')
60
- .option('-m, --model <model>', 'Model to use (default: deepseek-r1)')
61
- .option('--no-reasoning', 'Disable reasoning mode (adds </think> to messages)')
60
+ .option('-m, --model <model>', 'Model to use (default: glm-4.7)')
62
61
  .option('-t, --temperature <temp>', 'Temperature (0-1)', parseFloat)
63
62
  .option('--max-tokens <tokens>', 'Maximum tokens to generate', parseInt)
64
63
  .option('-k, --api-key <key>', 'API key to use for this chat session')
@@ -68,7 +68,18 @@ function mergeConfigurations(currentConfig, latestConfig) {
68
68
  return __awaiter(this, void 0, void 0, function* () {
69
69
  try {
70
70
  const client = (0, client_1.createAuthenticatedClient)();
71
- const modelConfig = (0, config_loader_1.getModelConfig)();
71
+ // Get model config with fallback for init scenario
72
+ let modelConfig;
73
+ try {
74
+ modelConfig = (0, config_loader_1.getModelConfig)();
75
+ }
76
+ catch (error) {
77
+ // Fallback to defaults when no config exists (init scenario)
78
+ modelConfig = {
79
+ primary: 'berget/glm-4.7',
80
+ small: 'berget/gpt-oss',
81
+ };
82
+ }
72
83
  console.log(chalk_1.default.blue('🤖 Using AI to merge configurations...'));
73
84
  const mergePrompt = `You are a configuration merge specialist. Merge these two OpenCode configurations:
74
85
 
@@ -267,20 +278,78 @@ function getProjectName() {
267
278
  return path_1.default.basename(process.cwd());
268
279
  }
269
280
  /**
270
- * Load the latest agent configuration from opencode.json
281
+ * Load the latest agent configuration from embedded config
271
282
  */
272
283
  function loadLatestAgentConfig() {
273
284
  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
- }
285
+ // Return the latest agent configuration directly - no file reading needed
286
+ return {
287
+ fullstack: {
288
+ model: 'berget/glm-4.7',
289
+ temperature: 0.3,
290
+ top_p: 0.9,
291
+ mode: 'primary',
292
+ permission: { edit: 'allow', bash: 'allow', webfetch: 'allow' },
293
+ description: 'Router/coordinator agent for full-stack development with schema-driven architecture',
294
+ 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.\n\nGIT WORKFLOW RULES (CRITICAL):\n- NEVER push directly to main branch - ALWAYS use pull requests\n- NEVER use 'git add .' - ALWAYS add specific files with 'git add path/to/file'\n- ALWAYS clean up test files, documentation files, and temporary artifacts before committing\n- ALWAYS ensure git history maintains production quality - no test commits, no debugging code\n- ALWAYS create descriptive commit messages following project conventions\n- ALWAYS run tests and build before creating PR\n\nCRITICAL: 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.",
295
+ },
296
+ frontend: {
297
+ model: 'berget/glm-4.7',
298
+ temperature: 0.4,
299
+ top_p: 0.9,
300
+ mode: 'primary',
301
+ permission: { edit: 'allow', bash: 'deny', webfetch: 'allow' },
302
+ note: 'Bash access is denied for frontend persona to prevent shell command execution in UI environments. This restriction enforces security and architectural boundaries.',
303
+ description: 'Builds Scandinavian, type-safe UIs with React, Tailwind, Shadcn.',
304
+ 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.\n\nIMPORTANT: You have NO bash access and cannot run git commands. When your frontend implementation tasks are complete, inform the user that changes are ready and suggest using /pr command to create a pull request with proper testing and quality checks.\n\nCODE QUALITY RULES:\n- Write clean, production-ready code\n- Follow React and TypeScript best practices\n- Ensure accessibility and responsive design\n- Use semantic tokens from design system\n- Test your components manually when possible\n- Document any complex logic with comments\n\nCRITICAL: When frontend implementation is complete, ALWAYS inform the user to use "/pr" command to handle testing, building, and pull request creation.',
305
+ },
306
+ backend: {
307
+ model: 'berget/glm-4.7',
308
+ temperature: 0.3,
309
+ top_p: 0.9,
310
+ mode: 'primary',
311
+ permission: { edit: 'allow', bash: 'allow', webfetch: 'allow' },
312
+ description: 'Functional, modular Koa + TypeScript services; schema-first with code quality focus.',
313
+ 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.\n\nGIT WORKFLOW RULES (CRITICAL):\n- NEVER push directly to main branch - ALWAYS use pull requests\n- NEVER use 'git add .' - ALWAYS add specific files with 'git add path/to/file'\n- ALWAYS clean up test files, documentation files, and temporary artifacts before committing\n- ALWAYS ensure git history maintains production quality - no test commits, no debugging code\n- ALWAYS create descriptive commit messages following project conventions\n- ALWAYS run tests and build before creating PR\n\nCRITICAL: 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.",
314
+ },
315
+ devops: {
316
+ model: 'berget/glm-4.7',
317
+ temperature: 0.3,
318
+ top_p: 0.8,
319
+ mode: 'primary',
320
+ permission: { edit: 'allow', bash: 'allow', webfetch: 'allow' },
321
+ description: 'Declarative GitOps infra with FluxCD, Kustomize, Helm, operators.',
322
+ 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.\n\nGIT WORKFLOW RULES (CRITICAL):\n- NEVER push directly to main branch - ALWAYS use pull requests\n- NEVER use 'git add .' - ALWAYS add specific files with 'git add path/to/file'\n- ALWAYS clean up test files, documentation files, and temporary artifacts before committing\n- ALWAYS ensure git history maintains production quality - no test commits, no debugging code\n- ALWAYS create descriptive commit messages following project conventions\n- ALWAYS run tests and build before creating PR\n\nHelm Values Configuration Process:\n1. 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.\n2. 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.\n3. 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.\n4. 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.",
323
+ },
324
+ app: {
325
+ model: 'berget/glm-4.7',
326
+ temperature: 0.4,
327
+ top_p: 0.9,
328
+ mode: 'primary',
329
+ permission: { edit: 'allow', bash: 'deny', webfetch: 'allow' },
330
+ note: 'Bash access is denied for app persona to prevent shell command execution in mobile/Expo environments. This restriction enforces security and architectural boundaries.',
331
+ description: 'Expo + React Native apps; props-first, offline-aware, shared tokens.',
332
+ 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.\n\nGIT WORKFLOW RULES (CRITICAL):\n- NEVER push directly to main branch - ALWAYS use pull requests\n- NEVER use 'git add .' - ALWAYS add specific files with 'git add path/to/file'\n- ALWAYS clean up test files, documentation files, and temporary artifacts before committing\n- ALWAYS ensure git history maintains production quality - no test commits, no debugging code\n- ALWAYS create descriptive commit messages following project conventions\n- ALWAYS run tests and build before creating PR\n\nCRITICAL: When all app implementation tasks are complete and ready for merge, ALWAYS invoke @quality subagent to handle testing, building, and complete PR management including URL provision.",
333
+ },
334
+ security: {
335
+ model: 'berget/glm-4.7',
336
+ temperature: 0.2,
337
+ top_p: 0.8,
338
+ mode: 'subagent',
339
+ permission: { edit: 'deny', bash: 'allow', webfetch: 'allow' },
340
+ description: 'Security specialist for pentesting, OWASP compliance, and vulnerability assessments.',
341
+ 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.\n\nGIT WORKFLOW RULES (CRITICAL):\n- NEVER push directly to main branch - ALWAYS use pull requests\n- NEVER use 'git add .' - ALWAYS add specific files with 'git add path/to/file'\n- ALWAYS clean up test files, documentation files, and temporary artifacts before committing\n- ALWAYS ensure git history maintains production quality - no test commits, no debugging code\n- ALWAYS create descriptive commit messages following project conventions\n- ALWAYS run tests and build before creating PR",
342
+ },
343
+ quality: {
344
+ model: 'berget/glm-4.7',
345
+ temperature: 0.1,
346
+ top_p: 0.9,
347
+ mode: 'subagent',
348
+ permission: { edit: 'allow', bash: 'allow', webfetch: 'allow' },
349
+ description: 'Quality assurance specialist for testing, building, and PR management.',
350
+ prompt: "Voice: Scandinavian calm—precise, concise, confident. You are Berget Code Quality agent. Specialist in code quality assurance, testing, building, and pull request management.\\n\\nCore responsibilities:\\n - Run comprehensive test suites (npm test, npm run test, jest, vitest)\\n - Execute build processes (npm run build, webpack, vite, tsc)\\n - Create and manage pull requests with proper descriptions\\n - Monitor GitHub for Copilot/reviewer comments\\n - Ensure code quality standards are met\\n - Validate linting and formatting (npm run lint, prettier)\\n - Check test coverage and performance benchmarks\\n - Handle CI/CD pipeline validation\\n\\nGIT WORKFLOW RULES (CRITICAL - ENFORCE STRICTLY):\\n - NEVER push directly to main branch - ALWAYS use pull requests\\n - NEVER use 'git add .' - ALWAYS add specific files with 'git add path/to/file'\\n - ALWAYS clean up test files, documentation files, and temporary artifacts before committing\\n - ALWAYS ensure git history maintains production quality - no test commits, no debugging code\\n - ALWAYS create descriptive commit messages following project conventions\\n - ALWAYS run tests and build before creating PR\\n\\nCommon CLI commands:\\n - npm test or npm run test (run test suite)\\n - npm run build (build project)\\n - npm run lint (run linting)\\n - npm run format (format code)\\n - npm run test:coverage (check coverage)\\n - gh pr create (create pull request)\\n - gh pr view --comments (check PR comments)\\n - git add specific/files && git commit -m \\\"message\\\" && git push (NEVER use git add .)\\n\\nPR Workflow:\\n 1. Ensure all tests pass: npm test\\n 2. Build successfully: npm run build\\n 3. Create/update PR with clear description\\n 4. Monitor for reviewer comments\\n 5. Address feedback promptly\\n 6. Update PR with fixes\\n 7. Ensure CI checks pass\\n\\nAlways provide specific command examples and wait for processes to complete before proceeding.",
351
+ },
352
+ };
284
353
  });
285
354
  }
286
355
  /**
@@ -288,9 +357,8 @@ function loadLatestAgentConfig() {
288
357
  */
289
358
  function checkOpencodeInstalled() {
290
359
  return new Promise((resolve) => {
291
- const child = (0, child_process_1.spawn)('opencode', ['--version'], {
360
+ const child = (0, child_process_1.spawn)('which', ['opencode'], {
292
361
  stdio: 'pipe',
293
- shell: true,
294
362
  });
295
363
  child.on('close', (code) => {
296
364
  resolve(code === 0);
@@ -310,7 +378,6 @@ function installOpencode() {
310
378
  yield new Promise((resolve, reject) => {
311
379
  const install = (0, child_process_1.spawn)('npm', ['install', '-g', 'opencode-ai'], {
312
380
  stdio: 'inherit',
313
- shell: true,
314
381
  });
315
382
  install.on('close', (code) => {
316
383
  if (code === 0) {
@@ -336,7 +403,7 @@ function installOpencode() {
336
403
  console.error(chalk_1.default.red('Failed to install OpenCode:'));
337
404
  console.error(error instanceof Error ? error.message : String(error));
338
405
  console.log(chalk_1.default.blue('\nAlternative installation methods:'));
339
- console.log(chalk_1.default.blue(' curl -fsSL https://opencode.ai/install | bash'));
406
+ console.log(chalk_1.default.blue(' curl -fsSL https://opencode.ai/install | sh'));
340
407
  console.log(chalk_1.default.blue(' Or visit: https://opencode.ai/docs'));
341
408
  return false;
342
409
  }
@@ -407,12 +474,9 @@ function registerCodeCommands(program) {
407
474
  }
408
475
  else {
409
476
  // Only require authentication if we don't have an API key
410
- try {
411
- const authService = auth_service_1.AuthService.getInstance();
412
- // This will throw if not authenticated
413
- yield authService.whoami();
414
- }
415
- catch (error) {
477
+ const authService = auth_service_1.AuthService.getInstance();
478
+ const profile = yield authService.whoami();
479
+ if (!profile) {
416
480
  console.log(chalk_1.default.red('❌ Not authenticated with Berget AI.'));
417
481
  console.log(chalk_1.default.blue('To get started, you have two options:'));
418
482
  console.log('');
@@ -436,62 +500,35 @@ function registerCodeCommands(program) {
436
500
  let keyName;
437
501
  try {
438
502
  const apiKeyService = api_key_service_1.ApiKeyService.getInstance();
439
- // Check for environment variable first (regardless of automation mode)
440
503
  if (process.env.BERGET_API_KEY) {
441
- console.log(chalk_1.default.blue('🔑 Using BERGET_API_KEY from environment'));
442
- apiKey = process.env.BERGET_API_KEY;
443
- keyName = `env-key-${projectName}`;
444
- }
445
- else {
446
- // List existing API keys
447
- if (!options.yes) {
448
- console.log(chalk_1.default.blue('\n📋 Checking existing API keys...'));
504
+ if (options.yes) {
505
+ console.log(chalk_1.default.blue('🔑 Using BERGET_API_KEY from environment'));
506
+ apiKey = process.env.BERGET_API_KEY;
507
+ keyName = `env-key-${projectName}`;
449
508
  }
450
- const existingKeys = yield apiKeyService.list();
451
- if (existingKeys.length > 0 && !options.yes) {
452
- console.log(chalk_1.default.blue('Found existing API keys:'));
509
+ else {
510
+ console.log(chalk_1.default.blue('\n📋 API key setup:'));
453
511
  console.log(chalk_1.default.dim('─'.repeat(60)));
454
- existingKeys.forEach((key, index) => {
455
- console.log(`${chalk_1.default.cyan((index + 1).toString())}. ${chalk_1.default.bold(key.name)} (${key.prefix}...)`);
456
- console.log(chalk_1.default.dim(` Created: ${new Date(key.created).toLocaleDateString('sv-SE')}`));
457
- console.log(chalk_1.default.dim(` Last used: ${key.lastUsed ? new Date(key.lastUsed).toLocaleDateString('sv-SE') : 'Never'}`));
458
- if (index < existingKeys.length - 1)
459
- console.log();
460
- });
512
+ console.log(`${chalk_1.default.cyan('1')} ${chalk_1.default.bold('Use existing API key')}`);
513
+ console.log(chalk_1.default.dim(' Uses BERGET_API_KEY from environment'));
514
+ console.log(`${chalk_1.default.cyan('2')} ${chalk_1.default.bold('Create a new API key')}`);
461
515
  console.log(chalk_1.default.dim('─'.repeat(60)));
462
- console.log(chalk_1.default.cyan(`${existingKeys.length + 1}. Create a new API key`));
463
- // Get user choice
464
516
  const choice = yield new Promise((resolve) => {
465
517
  const rl = readline_1.default.createInterface({
466
518
  input: process.stdin,
467
519
  output: process.stdout,
468
520
  });
469
- rl.question(chalk_1.default.blue('\nSelect an option (1-' +
470
- (existingKeys.length + 1) +
471
- '): '), (answer) => {
521
+ rl.question(chalk_1.default.blue('\nSelect an option (1-2, default: 1): '), (answer) => {
472
522
  rl.close();
473
- resolve(answer.trim());
523
+ resolve(answer.trim() || '1');
474
524
  });
475
525
  });
476
- const choiceIndex = parseInt(choice) - 1;
477
- if (choiceIndex >= 0 && choiceIndex < existingKeys.length) {
478
- // Use existing key
479
- const selectedKey = existingKeys[choiceIndex];
480
- keyName = selectedKey.name;
481
- // We need to rotate the key to get the actual key value
482
- console.log(chalk_1.default.yellow(`\n🔄 Rotating API key "${selectedKey.name}" to get the key value...`));
483
- if (yield confirm(chalk_1.default.yellow('This will invalidate the current key. Continue? (Y/n): '), options.yes)) {
484
- const rotatedKey = yield apiKeyService.rotate(selectedKey.id.toString());
485
- apiKey = rotatedKey.key;
486
- console.log(chalk_1.default.green(`✓ API key rotated successfully`));
487
- }
488
- else {
489
- console.log(chalk_1.default.yellow('Cancelled. Please select a different option or create a new key.'));
490
- return;
491
- }
526
+ if (choice === '1') {
527
+ console.log(chalk_1.default.blue('🔑 Using BERGET_API_KEY from environment'));
528
+ apiKey = process.env.BERGET_API_KEY;
529
+ keyName = `env-key-${projectName}`;
492
530
  }
493
- else if (choiceIndex === existingKeys.length) {
494
- // Create new key
531
+ else if (choice === '2') {
495
532
  console.log(chalk_1.default.blue('\n🔑 Creating new API key...'));
496
533
  const defaultKeyName = `opencode-${projectName}-${Date.now()}`;
497
534
  const customName = yield getInput(chalk_1.default.blue(`Enter key name (default: ${defaultKeyName}): `), defaultKeyName, options.yes);
@@ -506,20 +543,21 @@ function registerCodeCommands(program) {
506
543
  return;
507
544
  }
508
545
  }
509
- else {
510
- // No existing keys or automation mode - create new one
511
- if (!options.yes) {
512
- console.log(chalk_1.default.yellow('No existing API keys found.'));
513
- console.log(chalk_1.default.blue('Creating a new API key...'));
514
- }
515
- const defaultKeyName = `opencode-${projectName}-${Date.now()}`;
516
- const customName = yield getInput(chalk_1.default.blue(`Enter key name (default: ${defaultKeyName}): `), defaultKeyName, options.yes);
517
- keyName = customName;
518
- const createOptions = { name: keyName };
519
- const keyData = yield apiKeyService.create(createOptions);
520
- apiKey = keyData.key;
521
- console.log(chalk_1.default.green(`✓ Created new API key: ${keyName}`));
546
+ }
547
+ else {
548
+ if (!options.yes) {
549
+ console.log(chalk_1.default.yellow('No BERGET_API_KEY environment variable found.'));
550
+ console.log(chalk_1.default.blue('Creating a new API key...'));
551
+ console.log(chalk_1.default.dim('\n💡 Tip: Set BERGET_API_KEY environment variable to reuse an existing key:'));
552
+ console.log(chalk_1.default.dim(' export BERGET_API_KEY=your_api_key_here'));
522
553
  }
554
+ const defaultKeyName = `opencode-${projectName}-${Date.now()}`;
555
+ const customName = yield getInput(chalk_1.default.blue(`Enter key name (default: ${defaultKeyName}): `), defaultKeyName, options.yes);
556
+ keyName = customName;
557
+ const createOptions = { name: keyName };
558
+ const keyData = yield apiKeyService.create(createOptions);
559
+ apiKey = keyData.key;
560
+ console.log(chalk_1.default.green(`✓ Created new API key: ${keyName}`));
523
561
  }
524
562
  }
525
563
  catch (error) {
@@ -543,9 +581,13 @@ function registerCodeCommands(program) {
543
581
  }
544
582
  // Prepare .env file path for safe update
545
583
  const envPath = path_1.default.join(process.cwd(), '.env');
546
- // Load latest agent configuration to ensure consistency
584
+ // Load latest agent configuration from our own codebase
547
585
  const latestAgentConfig = yield loadLatestAgentConfig();
548
- const modelConfig = (0, config_loader_1.getModelConfig)();
586
+ // Use hardcoded defaults for init - never try to load from project
587
+ const modelConfig = {
588
+ primary: 'berget/glm-4.7',
589
+ small: 'berget/gpt-oss',
590
+ };
549
591
  // Create opencode.json config with optimized agent-based format
550
592
  const config = {
551
593
  $schema: 'https://opencode.ai/config.json',
@@ -672,7 +714,21 @@ function registerCodeCommands(program) {
672
714
  baseURL: 'https://api.berget.ai/v1',
673
715
  apiKey: '{env:BERGET_API_KEY}',
674
716
  },
675
- models: (0, config_loader_1.getProviderModels)(),
717
+ models: {
718
+ 'glm-4.7': {
719
+ name: 'GLM-4.7',
720
+ limit: { output: 4000, context: 90000 },
721
+ },
722
+ 'gpt-oss': {
723
+ name: 'GPT-OSS',
724
+ limit: { output: 4000, context: 128000 },
725
+ modalities: ['text', 'image'],
726
+ },
727
+ 'llama-8b': {
728
+ name: 'llama-3.1-8b',
729
+ limit: { output: 4000, context: 128000 },
730
+ },
731
+ },
676
732
  },
677
733
  },
678
734
  };
@@ -964,7 +1020,6 @@ All agents follow these principles:
964
1020
  const opencode = (0, child_process_1.spawn)('opencode', opencodeArgs, {
965
1021
  stdio: 'inherit',
966
1022
  env: env,
967
- shell: true,
968
1023
  });
969
1024
  opencode.on('close', (code) => {
970
1025
  if (code !== 0) {
@@ -1004,7 +1059,6 @@ All agents follow these principles:
1004
1059
  // Spawn opencode serve process
1005
1060
  const opencode = (0, child_process_1.spawn)('opencode', serveArgs, {
1006
1061
  stdio: 'inherit',
1007
- shell: true,
1008
1062
  });
1009
1063
  opencode.on('close', (code) => {
1010
1064
  if (code !== 0) {
@@ -1057,7 +1111,18 @@ All agents follow these principles:
1057
1111
  console.log(chalk_1.default.dim(` Agents: ${Object.keys(currentConfig.agent || {}).length} configured`));
1058
1112
  // Load latest agent configuration to ensure consistency
1059
1113
  const latestAgentConfig = yield loadLatestAgentConfig();
1060
- const modelConfig = (0, config_loader_1.getModelConfig)();
1114
+ // Get model config with fallback for init scenario
1115
+ let modelConfig;
1116
+ try {
1117
+ modelConfig = (0, config_loader_1.getModelConfig)();
1118
+ }
1119
+ catch (error) {
1120
+ // Fallback to defaults when no config exists (init scenario)
1121
+ modelConfig = {
1122
+ primary: 'berget/glm-4.7',
1123
+ small: 'berget/gpt-oss',
1124
+ };
1125
+ }
1061
1126
  // Create latest configuration with all improvements
1062
1127
  const latestConfig = {
1063
1128
  $schema: 'https://opencode.ai/config.json',
@@ -1216,9 +1281,9 @@ All agents follow these principles:
1216
1281
  if (((_c = (_b = currentConfig.agent) === null || _b === void 0 ? void 0 : _b.security) === null || _c === void 0 ? void 0 : _c.mode) !== 'subagent') {
1217
1282
  console.log(chalk_1.default.cyan(' • Security agent converted to subagent (read-only)'));
1218
1283
  }
1219
- // Check for GLM-4.6 optimizations
1284
+ // Check for GLM-4.7 optimizations
1220
1285
  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)) {
1221
- console.log(chalk_1.default.cyan(' • GLM-4.6 token limits and auto-compaction'));
1286
+ console.log(chalk_1.default.cyan(' • GLM-4.7 token limits and auto-compaction'));
1222
1287
  }
1223
1288
  console.log(chalk_1.default.cyan(' • Latest agent prompts and improvements'));
1224
1289
  }
@@ -1443,7 +1508,7 @@ All agents follow these principles:
1443
1508
  console.log(chalk_1.default.cyan(' • @quality subagent for testing and PR management'));
1444
1509
  console.log(chalk_1.default.cyan(' • @security subagent for security reviews'));
1445
1510
  console.log(chalk_1.default.cyan(' • Improved agent prompts and routing'));
1446
- console.log(chalk_1.default.cyan(' • GLM-4.6 token optimizations'));
1511
+ console.log(chalk_1.default.cyan(' • GLM-4.7 token optimizations'));
1447
1512
  console.log(chalk_1.default.blue('\nTry these new commands:'));
1448
1513
  console.log(chalk_1.default.cyan(' @quality run tests and create PR'));
1449
1514
  console.log(chalk_1.default.cyan(' @security review this code'));
@@ -60,12 +60,11 @@ class AuthService {
60
60
  try {
61
61
  const { data: profile, error } = yield this.client.GET('/v1/users/me');
62
62
  if (error) {
63
- throw new Error(error ? JSON.stringify(error) : 'Failed to get user profile');
63
+ return null;
64
64
  }
65
65
  return profile;
66
66
  }
67
67
  catch (error) {
68
- (0, error_handler_1.handleError)('Failed to get user profile', error);
69
68
  return null;
70
69
  }
71
70
  });