berget 2.0.6 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +163 -2
- package/dist/package.json +1 -1
- package/dist/src/commands/chat.js +1 -2
- package/dist/src/commands/code.js +122 -25
- package/dist/src/services/chat-service.js +77 -5
- package/dist/src/utils/config-loader.js +83 -27
- package/dist/tests/commands/chat.test.js +2 -2
- package/dist/tests/commands/code.test.js +4 -4
- package/dist/tests/utils/config-loader.test.js +248 -163
- package/opencode.json +31 -71
- package/package.json +1 -1
- package/src/commands/chat.ts +68 -61
- package/src/commands/code.ts +283 -124
- package/src/services/chat-service.ts +86 -5
- package/src/utils/config-loader.ts +113 -38
- package/tests/commands/chat.test.ts +2 -2
- package/tests/commands/code.test.ts +4 -4
- package/tests/utils/config-loader.test.ts +320 -0
- package/blog-post.md +0 -176
package/src/commands/code.ts
CHANGED
|
@@ -11,12 +11,12 @@ import path from 'path'
|
|
|
11
11
|
import { spawn } from 'child_process'
|
|
12
12
|
import { updateEnvFile } from '../utils/env-manager'
|
|
13
13
|
import { createAuthenticatedClient } from '../client'
|
|
14
|
-
import {
|
|
15
|
-
getConfigLoader,
|
|
16
|
-
getModelConfig,
|
|
14
|
+
import {
|
|
15
|
+
getConfigLoader,
|
|
16
|
+
getModelConfig,
|
|
17
17
|
getProviderModels,
|
|
18
18
|
type OpenCodeConfig,
|
|
19
|
-
type AgentConfig
|
|
19
|
+
type AgentConfig,
|
|
20
20
|
} from '../utils/config-loader'
|
|
21
21
|
|
|
22
22
|
/**
|
|
@@ -35,11 +35,22 @@ function hasGit(): boolean {
|
|
|
35
35
|
*/
|
|
36
36
|
async function mergeConfigurations(
|
|
37
37
|
currentConfig: any,
|
|
38
|
-
latestConfig: any
|
|
38
|
+
latestConfig: any
|
|
39
39
|
): Promise<any> {
|
|
40
40
|
try {
|
|
41
41
|
const client = createAuthenticatedClient()
|
|
42
|
-
|
|
42
|
+
|
|
43
|
+
// Get model config with fallback for init scenario
|
|
44
|
+
let modelConfig: { primary: string; small: string }
|
|
45
|
+
try {
|
|
46
|
+
modelConfig = getModelConfig()
|
|
47
|
+
} catch (error) {
|
|
48
|
+
// Fallback to defaults when no config exists (init scenario)
|
|
49
|
+
modelConfig = {
|
|
50
|
+
primary: 'berget/glm-4.7',
|
|
51
|
+
small: 'berget/gpt-oss',
|
|
52
|
+
}
|
|
53
|
+
}
|
|
43
54
|
|
|
44
55
|
console.log(chalk.blue('🤖 Using AI to merge configurations...'))
|
|
45
56
|
|
|
@@ -91,7 +102,7 @@ Return ONLY the merged JSON configuration, no explanations.`
|
|
|
91
102
|
return mergedConfig
|
|
92
103
|
} catch (parseError) {
|
|
93
104
|
console.warn(
|
|
94
|
-
chalk.yellow('⚠️ AI response invalid, using fallback merge')
|
|
105
|
+
chalk.yellow('⚠️ AI response invalid, using fallback merge')
|
|
95
106
|
)
|
|
96
107
|
return fallbackMerge(currentConfig, latestConfig)
|
|
97
108
|
}
|
|
@@ -182,7 +193,7 @@ async function confirm(question: string, autoYes = false): Promise<boolean> {
|
|
|
182
193
|
resolve(
|
|
183
194
|
answer.toLowerCase() === 'y' ||
|
|
184
195
|
answer.toLowerCase() === 'yes' ||
|
|
185
|
-
answer === ''
|
|
196
|
+
answer === ''
|
|
186
197
|
)
|
|
187
198
|
})
|
|
188
199
|
})
|
|
@@ -194,7 +205,7 @@ async function confirm(question: string, autoYes = false): Promise<boolean> {
|
|
|
194
205
|
async function askChoice(
|
|
195
206
|
question: string,
|
|
196
207
|
options: string[],
|
|
197
|
-
defaultChoice?: string
|
|
208
|
+
defaultChoice?: string
|
|
198
209
|
): Promise<string> {
|
|
199
210
|
return new Promise((resolve) => {
|
|
200
211
|
const rl = readline.createInterface({
|
|
@@ -216,7 +227,7 @@ async function askChoice(
|
|
|
216
227
|
|
|
217
228
|
// Handle text input
|
|
218
229
|
const matchingOption = options.find((option) =>
|
|
219
|
-
option.toLowerCase().startsWith(trimmed)
|
|
230
|
+
option.toLowerCase().startsWith(trimmed)
|
|
220
231
|
)
|
|
221
232
|
|
|
222
233
|
if (matchingOption) {
|
|
@@ -236,7 +247,7 @@ async function askChoice(
|
|
|
236
247
|
async function getInput(
|
|
237
248
|
question: string,
|
|
238
249
|
defaultValue: string,
|
|
239
|
-
autoYes = false
|
|
250
|
+
autoYes = false
|
|
240
251
|
): Promise<string> {
|
|
241
252
|
if (autoYes) {
|
|
242
253
|
return defaultValue
|
|
@@ -273,17 +284,90 @@ function getProjectName(): string {
|
|
|
273
284
|
}
|
|
274
285
|
|
|
275
286
|
/**
|
|
276
|
-
* Load the latest agent configuration from
|
|
287
|
+
* Load the latest agent configuration from embedded config
|
|
277
288
|
*/
|
|
278
289
|
async function loadLatestAgentConfig(): Promise<any> {
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
290
|
+
// Return the latest agent configuration directly - no file reading needed
|
|
291
|
+
return {
|
|
292
|
+
fullstack: {
|
|
293
|
+
model: 'berget/glm-4.7',
|
|
294
|
+
temperature: 0.3,
|
|
295
|
+
top_p: 0.9,
|
|
296
|
+
mode: 'primary',
|
|
297
|
+
permission: { edit: 'allow', bash: 'allow', webfetch: 'allow' },
|
|
298
|
+
description:
|
|
299
|
+
'Router/coordinator agent for full-stack development with schema-driven architecture',
|
|
300
|
+
prompt:
|
|
301
|
+
"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.",
|
|
302
|
+
},
|
|
303
|
+
frontend: {
|
|
304
|
+
model: 'berget/glm-4.7',
|
|
305
|
+
temperature: 0.4,
|
|
306
|
+
top_p: 0.9,
|
|
307
|
+
mode: 'primary',
|
|
308
|
+
permission: { edit: 'allow', bash: 'deny', webfetch: 'allow' },
|
|
309
|
+
note: 'Bash access is denied for frontend persona to prevent shell command execution in UI environments. This restriction enforces security and architectural boundaries.',
|
|
310
|
+
description:
|
|
311
|
+
'Builds Scandinavian, type-safe UIs with React, Tailwind, Shadcn.',
|
|
312
|
+
prompt:
|
|
313
|
+
'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.',
|
|
314
|
+
},
|
|
315
|
+
backend: {
|
|
316
|
+
model: 'berget/glm-4.7',
|
|
317
|
+
temperature: 0.3,
|
|
318
|
+
top_p: 0.9,
|
|
319
|
+
mode: 'primary',
|
|
320
|
+
permission: { edit: 'allow', bash: 'allow', webfetch: 'allow' },
|
|
321
|
+
description:
|
|
322
|
+
'Functional, modular Koa + TypeScript services; schema-first with code quality focus.',
|
|
323
|
+
prompt:
|
|
324
|
+
"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.",
|
|
325
|
+
},
|
|
326
|
+
devops: {
|
|
327
|
+
model: 'berget/glm-4.7',
|
|
328
|
+
temperature: 0.3,
|
|
329
|
+
top_p: 0.8,
|
|
330
|
+
mode: 'primary',
|
|
331
|
+
permission: { edit: 'allow', bash: 'allow', webfetch: 'allow' },
|
|
332
|
+
description:
|
|
333
|
+
'Declarative GitOps infra with FluxCD, Kustomize, Helm, operators.',
|
|
334
|
+
prompt:
|
|
335
|
+
"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.",
|
|
336
|
+
},
|
|
337
|
+
app: {
|
|
338
|
+
model: 'berget/glm-4.7',
|
|
339
|
+
temperature: 0.4,
|
|
340
|
+
top_p: 0.9,
|
|
341
|
+
mode: 'primary',
|
|
342
|
+
permission: { edit: 'allow', bash: 'deny', webfetch: 'allow' },
|
|
343
|
+
note: 'Bash access is denied for app persona to prevent shell command execution in mobile/Expo environments. This restriction enforces security and architectural boundaries.',
|
|
344
|
+
description:
|
|
345
|
+
'Expo + React Native apps; props-first, offline-aware, shared tokens.',
|
|
346
|
+
prompt:
|
|
347
|
+
"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.",
|
|
348
|
+
},
|
|
349
|
+
security: {
|
|
350
|
+
model: 'berget/glm-4.7',
|
|
351
|
+
temperature: 0.2,
|
|
352
|
+
top_p: 0.8,
|
|
353
|
+
mode: 'subagent',
|
|
354
|
+
permission: { edit: 'deny', bash: 'allow', webfetch: 'allow' },
|
|
355
|
+
description:
|
|
356
|
+
'Security specialist for pentesting, OWASP compliance, and vulnerability assessments.',
|
|
357
|
+
prompt:
|
|
358
|
+
"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",
|
|
359
|
+
},
|
|
360
|
+
quality: {
|
|
361
|
+
model: 'berget/glm-4.7',
|
|
362
|
+
temperature: 0.1,
|
|
363
|
+
top_p: 0.9,
|
|
364
|
+
mode: 'subagent',
|
|
365
|
+
permission: { edit: 'allow', bash: 'allow', webfetch: 'allow' },
|
|
366
|
+
description:
|
|
367
|
+
'Quality assurance specialist for testing, building, and PR management.',
|
|
368
|
+
prompt:
|
|
369
|
+
"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.",
|
|
370
|
+
},
|
|
287
371
|
}
|
|
288
372
|
}
|
|
289
373
|
|
|
@@ -317,7 +401,6 @@ async function installOpencode(): Promise<boolean> {
|
|
|
317
401
|
await new Promise<void>((resolve, reject) => {
|
|
318
402
|
const install = spawn('npm', ['install', '-g', 'opencode-ai'], {
|
|
319
403
|
stdio: 'inherit',
|
|
320
|
-
shell: true,
|
|
321
404
|
})
|
|
322
405
|
|
|
323
406
|
install.on('close', (code) => {
|
|
@@ -336,12 +419,12 @@ async function installOpencode(): Promise<boolean> {
|
|
|
336
419
|
const opencodeInstalled = await checkOpencodeInstalled()
|
|
337
420
|
if (!opencodeInstalled) {
|
|
338
421
|
console.log(
|
|
339
|
-
chalk.yellow('Installation completed but opencode command not found.')
|
|
422
|
+
chalk.yellow('Installation completed but opencode command not found.')
|
|
340
423
|
)
|
|
341
424
|
console.log(
|
|
342
425
|
chalk.yellow(
|
|
343
|
-
'You may need to restart your terminal or check your PATH.'
|
|
344
|
-
)
|
|
426
|
+
'You may need to restart your terminal or check your PATH.'
|
|
427
|
+
)
|
|
345
428
|
)
|
|
346
429
|
return false
|
|
347
430
|
}
|
|
@@ -351,7 +434,7 @@ async function installOpencode(): Promise<boolean> {
|
|
|
351
434
|
console.error(chalk.red('Failed to install OpenCode:'))
|
|
352
435
|
console.error(error instanceof Error ? error.message : String(error))
|
|
353
436
|
console.log(chalk.blue('\nAlternative installation methods:'))
|
|
354
|
-
console.log(chalk.blue(' curl -fsSL https://opencode.ai/install |
|
|
437
|
+
console.log(chalk.blue(' curl -fsSL https://opencode.ai/install | sh'))
|
|
355
438
|
console.log(chalk.blue(' Or visit: https://opencode.ai/docs'))
|
|
356
439
|
return false
|
|
357
440
|
}
|
|
@@ -366,14 +449,14 @@ async function ensureOpencodeInstalled(autoYes = false): Promise<boolean> {
|
|
|
366
449
|
if (!autoYes) {
|
|
367
450
|
console.log(chalk.red('OpenCode is not installed.'))
|
|
368
451
|
console.log(
|
|
369
|
-
chalk.blue('OpenCode is required for the AI coding assistant.')
|
|
452
|
+
chalk.blue('OpenCode is required for the AI coding assistant.')
|
|
370
453
|
)
|
|
371
454
|
}
|
|
372
455
|
|
|
373
456
|
if (
|
|
374
457
|
await confirm(
|
|
375
458
|
'Would you like to install OpenCode automatically? (Y/n): ',
|
|
376
|
-
autoYes
|
|
459
|
+
autoYes
|
|
377
460
|
)
|
|
378
461
|
) {
|
|
379
462
|
opencodeInstalled = await installOpencode()
|
|
@@ -382,8 +465,8 @@ async function ensureOpencodeInstalled(autoYes = false): Promise<boolean> {
|
|
|
382
465
|
console.log(chalk.blue('\nInstallation cancelled.'))
|
|
383
466
|
console.log(
|
|
384
467
|
chalk.blue(
|
|
385
|
-
'To install manually: curl -fsSL https://opencode.ai/install | bash'
|
|
386
|
-
)
|
|
468
|
+
'To install manually: curl -fsSL https://opencode.ai/install | bash'
|
|
469
|
+
)
|
|
387
470
|
)
|
|
388
471
|
console.log(chalk.blue('Or visit: https://opencode.ai/docs'))
|
|
389
472
|
}
|
|
@@ -408,7 +491,7 @@ export function registerCodeCommands(program: Command): void {
|
|
|
408
491
|
.option('-f, --force', 'Overwrite existing configuration')
|
|
409
492
|
.option(
|
|
410
493
|
'-y, --yes',
|
|
411
|
-
'Automatically answer yes to all prompts (for automation)'
|
|
494
|
+
'Automatically answer yes to all prompts (for automation)'
|
|
412
495
|
)
|
|
413
496
|
.action(async (options) => {
|
|
414
497
|
try {
|
|
@@ -419,7 +502,7 @@ export function registerCodeCommands(program: Command): void {
|
|
|
419
502
|
if (fs.existsSync(configPath) && !options.force) {
|
|
420
503
|
if (!options.yes) {
|
|
421
504
|
console.log(
|
|
422
|
-
chalk.yellow('Project already initialized for OpenCode.')
|
|
505
|
+
chalk.yellow('Project already initialized for OpenCode.')
|
|
423
506
|
)
|
|
424
507
|
console.log(chalk.dim(`Config file: ${configPath}`))
|
|
425
508
|
}
|
|
@@ -440,7 +523,11 @@ export function registerCodeCommands(program: Command): void {
|
|
|
440
523
|
|
|
441
524
|
// Check if we have an API key in environment first
|
|
442
525
|
if (process.env.BERGET_API_KEY) {
|
|
443
|
-
console.log(
|
|
526
|
+
console.log(
|
|
527
|
+
chalk.blue(
|
|
528
|
+
'🔑 Using BERGET_API_KEY from environment - no authentication required'
|
|
529
|
+
)
|
|
530
|
+
)
|
|
444
531
|
} else {
|
|
445
532
|
// Only require authentication if we don't have an API key
|
|
446
533
|
try {
|
|
@@ -451,15 +538,29 @@ export function registerCodeCommands(program: Command): void {
|
|
|
451
538
|
console.log(chalk.red('❌ Not authenticated with Berget AI.'))
|
|
452
539
|
console.log(chalk.blue('To get started, you have two options:'))
|
|
453
540
|
console.log('')
|
|
454
|
-
console.log(
|
|
455
|
-
|
|
456
|
-
|
|
541
|
+
console.log(
|
|
542
|
+
chalk.yellow('Option 1: Use an existing API key (recommended)')
|
|
543
|
+
)
|
|
544
|
+
console.log(
|
|
545
|
+
chalk.cyan(' Set BERGET_API_KEY environment variable:')
|
|
546
|
+
)
|
|
547
|
+
console.log(
|
|
548
|
+
chalk.dim(' export BERGET_API_KEY=your_api_key_here')
|
|
549
|
+
)
|
|
457
550
|
console.log(chalk.cyan(' Or create a .env file in your project:'))
|
|
458
|
-
console.log(
|
|
551
|
+
console.log(
|
|
552
|
+
chalk.dim(' echo "BERGET_API_KEY=your_api_key_here" > .env')
|
|
553
|
+
)
|
|
459
554
|
console.log('')
|
|
460
|
-
console.log(
|
|
555
|
+
console.log(
|
|
556
|
+
chalk.yellow('Option 2: Login and create a new API key')
|
|
557
|
+
)
|
|
461
558
|
console.log(chalk.cyan(' berget auth login'))
|
|
462
|
-
console.log(
|
|
559
|
+
console.log(
|
|
560
|
+
chalk.cyan(
|
|
561
|
+
` berget ${COMMAND_GROUPS.CODE} ${SUBCOMMANDS.CODE.INIT}`
|
|
562
|
+
)
|
|
563
|
+
)
|
|
463
564
|
console.log('')
|
|
464
565
|
console.log(chalk.blue('Then try again.'))
|
|
465
566
|
return
|
|
@@ -467,7 +568,7 @@ export function registerCodeCommands(program: Command): void {
|
|
|
467
568
|
}
|
|
468
569
|
|
|
469
570
|
console.log(
|
|
470
|
-
chalk.cyan(`Initializing OpenCode for project: ${projectName}`)
|
|
571
|
+
chalk.cyan(`Initializing OpenCode for project: ${projectName}`)
|
|
471
572
|
)
|
|
472
573
|
|
|
473
574
|
// Handle API key selection or creation
|
|
@@ -494,23 +595,31 @@ export function registerCodeCommands(program: Command): void {
|
|
|
494
595
|
console.log(chalk.dim('─'.repeat(60)))
|
|
495
596
|
existingKeys.forEach((key, index) => {
|
|
496
597
|
console.log(
|
|
497
|
-
`${chalk.cyan((index + 1).toString())}. ${chalk.bold(
|
|
598
|
+
`${chalk.cyan((index + 1).toString())}. ${chalk.bold(
|
|
599
|
+
key.name
|
|
600
|
+
)} (${key.prefix}...)`
|
|
498
601
|
)
|
|
499
602
|
console.log(
|
|
500
603
|
chalk.dim(
|
|
501
|
-
` Created: ${new Date(key.created).toLocaleDateString(
|
|
502
|
-
|
|
604
|
+
` Created: ${new Date(key.created).toLocaleDateString(
|
|
605
|
+
'sv-SE'
|
|
606
|
+
)}`
|
|
607
|
+
)
|
|
503
608
|
)
|
|
504
609
|
console.log(
|
|
505
610
|
chalk.dim(
|
|
506
|
-
` Last used: ${
|
|
507
|
-
|
|
611
|
+
` Last used: ${
|
|
612
|
+
key.lastUsed
|
|
613
|
+
? new Date(key.lastUsed).toLocaleDateString('sv-SE')
|
|
614
|
+
: 'Never'
|
|
615
|
+
}`
|
|
616
|
+
)
|
|
508
617
|
)
|
|
509
618
|
if (index < existingKeys.length - 1) console.log()
|
|
510
619
|
})
|
|
511
620
|
console.log(chalk.dim('─'.repeat(60)))
|
|
512
621
|
console.log(
|
|
513
|
-
chalk.cyan(`${existingKeys.length + 1}. Create a new API key`)
|
|
622
|
+
chalk.cyan(`${existingKeys.length + 1}. Create a new API key`)
|
|
514
623
|
)
|
|
515
624
|
|
|
516
625
|
// Get user choice
|
|
@@ -521,14 +630,12 @@ export function registerCodeCommands(program: Command): void {
|
|
|
521
630
|
})
|
|
522
631
|
rl.question(
|
|
523
632
|
chalk.blue(
|
|
524
|
-
'\nSelect an option (1-' +
|
|
525
|
-
(existingKeys.length + 1) +
|
|
526
|
-
'): ',
|
|
633
|
+
'\nSelect an option (1-' + (existingKeys.length + 1) + '): '
|
|
527
634
|
),
|
|
528
635
|
(answer) => {
|
|
529
636
|
rl.close()
|
|
530
637
|
resolve(answer.trim())
|
|
531
|
-
}
|
|
638
|
+
}
|
|
532
639
|
)
|
|
533
640
|
})
|
|
534
641
|
|
|
@@ -542,28 +649,28 @@ export function registerCodeCommands(program: Command): void {
|
|
|
542
649
|
// We need to rotate the key to get the actual key value
|
|
543
650
|
console.log(
|
|
544
651
|
chalk.yellow(
|
|
545
|
-
`\n🔄 Rotating API key "${selectedKey.name}" to get the key value
|
|
546
|
-
)
|
|
652
|
+
`\n🔄 Rotating API key "${selectedKey.name}" to get the key value...`
|
|
653
|
+
)
|
|
547
654
|
)
|
|
548
655
|
|
|
549
656
|
if (
|
|
550
657
|
await confirm(
|
|
551
658
|
chalk.yellow(
|
|
552
|
-
'This will invalidate the current key. Continue? (Y/n): '
|
|
659
|
+
'This will invalidate the current key. Continue? (Y/n): '
|
|
553
660
|
),
|
|
554
|
-
options.yes
|
|
661
|
+
options.yes
|
|
555
662
|
)
|
|
556
663
|
) {
|
|
557
664
|
const rotatedKey = await apiKeyService.rotate(
|
|
558
|
-
selectedKey.id.toString()
|
|
665
|
+
selectedKey.id.toString()
|
|
559
666
|
)
|
|
560
667
|
apiKey = rotatedKey.key
|
|
561
668
|
console.log(chalk.green(`✓ API key rotated successfully`))
|
|
562
669
|
} else {
|
|
563
670
|
console.log(
|
|
564
671
|
chalk.yellow(
|
|
565
|
-
'Cancelled. Please select a different option or create a new key.'
|
|
566
|
-
)
|
|
672
|
+
'Cancelled. Please select a different option or create a new key.'
|
|
673
|
+
)
|
|
567
674
|
)
|
|
568
675
|
return
|
|
569
676
|
}
|
|
@@ -575,7 +682,7 @@ export function registerCodeCommands(program: Command): void {
|
|
|
575
682
|
const customName = await getInput(
|
|
576
683
|
chalk.blue(`Enter key name (default: ${defaultKeyName}): `),
|
|
577
684
|
defaultKeyName,
|
|
578
|
-
options.yes
|
|
685
|
+
options.yes
|
|
579
686
|
)
|
|
580
687
|
|
|
581
688
|
keyName = customName
|
|
@@ -598,7 +705,7 @@ export function registerCodeCommands(program: Command): void {
|
|
|
598
705
|
const customName = await getInput(
|
|
599
706
|
chalk.blue(`Enter key name (default: ${defaultKeyName}): `),
|
|
600
707
|
defaultKeyName,
|
|
601
|
-
options.yes
|
|
708
|
+
options.yes
|
|
602
709
|
)
|
|
603
710
|
|
|
604
711
|
keyName = customName
|
|
@@ -610,8 +717,14 @@ export function registerCodeCommands(program: Command): void {
|
|
|
610
717
|
}
|
|
611
718
|
} catch (error) {
|
|
612
719
|
if (process.env.BERGET_API_KEY) {
|
|
613
|
-
console.log(
|
|
614
|
-
|
|
720
|
+
console.log(
|
|
721
|
+
chalk.yellow(
|
|
722
|
+
'⚠️ Could not verify API key with Berget API, but continuing with environment key'
|
|
723
|
+
)
|
|
724
|
+
)
|
|
725
|
+
console.log(
|
|
726
|
+
chalk.dim('This might be due to network issues or an invalid key')
|
|
727
|
+
)
|
|
615
728
|
} else {
|
|
616
729
|
console.error(chalk.red('❌ Failed to handle API keys:'))
|
|
617
730
|
console.log(chalk.blue('This could be due to:'))
|
|
@@ -621,7 +734,11 @@ export function registerCodeCommands(program: Command): void {
|
|
|
621
734
|
console.log('')
|
|
622
735
|
console.log(chalk.blue('Try using an API key directly:'))
|
|
623
736
|
console.log(chalk.cyan(' export BERGET_API_KEY=your_api_key_here'))
|
|
624
|
-
console.log(
|
|
737
|
+
console.log(
|
|
738
|
+
chalk.cyan(
|
|
739
|
+
` berget ${COMMAND_GROUPS.CODE} ${SUBCOMMANDS.CODE.INIT} --yes`
|
|
740
|
+
)
|
|
741
|
+
)
|
|
625
742
|
handleError('API key operation failed', error)
|
|
626
743
|
}
|
|
627
744
|
return
|
|
@@ -630,9 +747,14 @@ export function registerCodeCommands(program: Command): void {
|
|
|
630
747
|
// Prepare .env file path for safe update
|
|
631
748
|
const envPath = path.join(process.cwd(), '.env')
|
|
632
749
|
|
|
633
|
-
// Load latest agent configuration
|
|
750
|
+
// Load latest agent configuration from our own codebase
|
|
634
751
|
const latestAgentConfig = await loadLatestAgentConfig()
|
|
635
|
-
|
|
752
|
+
|
|
753
|
+
// Use hardcoded defaults for init - never try to load from project
|
|
754
|
+
const modelConfig = {
|
|
755
|
+
primary: 'berget/glm-4.7',
|
|
756
|
+
small: 'berget/gpt-oss',
|
|
757
|
+
}
|
|
636
758
|
|
|
637
759
|
// Create opencode.json config with optimized agent-based format
|
|
638
760
|
const config = {
|
|
@@ -772,11 +894,25 @@ export function registerCodeCommands(program: Command): void {
|
|
|
772
894
|
berget: {
|
|
773
895
|
npm: '@ai-sdk/openai-compatible',
|
|
774
896
|
name: 'Berget AI',
|
|
775
|
-
options: {
|
|
897
|
+
options: {
|
|
776
898
|
baseURL: 'https://api.berget.ai/v1',
|
|
777
899
|
apiKey: '{env:BERGET_API_KEY}',
|
|
778
900
|
},
|
|
779
|
-
models:
|
|
901
|
+
models: {
|
|
902
|
+
'glm-4.7': {
|
|
903
|
+
name: 'GLM-4.7',
|
|
904
|
+
limit: { output: 4000, context: 90000 },
|
|
905
|
+
},
|
|
906
|
+
'gpt-oss': {
|
|
907
|
+
name: 'GPT-OSS',
|
|
908
|
+
limit: { output: 4000, context: 128000 },
|
|
909
|
+
modalities: ['text', 'image'],
|
|
910
|
+
},
|
|
911
|
+
'llama-8b': {
|
|
912
|
+
name: 'llama-3.1-8b',
|
|
913
|
+
limit: { output: 4000, context: 128000 },
|
|
914
|
+
},
|
|
915
|
+
},
|
|
780
916
|
},
|
|
781
917
|
},
|
|
782
918
|
}
|
|
@@ -788,33 +924,36 @@ export function registerCodeCommands(program: Command): void {
|
|
|
788
924
|
console.log(chalk.dim(`Environment: ${envPath}`))
|
|
789
925
|
console.log(
|
|
790
926
|
chalk.dim(
|
|
791
|
-
`Documentation: ${path.join(
|
|
792
|
-
|
|
927
|
+
`Documentation: ${path.join(
|
|
928
|
+
process.cwd(),
|
|
929
|
+
'AGENTS.md'
|
|
930
|
+
)} (if not exists)`
|
|
931
|
+
)
|
|
793
932
|
)
|
|
794
933
|
console.log(
|
|
795
934
|
chalk.dim(
|
|
796
|
-
`Environment: ${path.join(process.cwd(), '.env')} will be updated
|
|
797
|
-
)
|
|
935
|
+
`Environment: ${path.join(process.cwd(), '.env')} will be updated`
|
|
936
|
+
)
|
|
798
937
|
)
|
|
799
938
|
console.log(
|
|
800
|
-
chalk.dim('This will configure OpenCode to use Berget AI models.')
|
|
939
|
+
chalk.dim('This will configure OpenCode to use Berget AI models.')
|
|
801
940
|
)
|
|
802
941
|
console.log(chalk.cyan('\n💡 Benefits:'))
|
|
803
942
|
console.log(
|
|
804
943
|
chalk.cyan(
|
|
805
|
-
' • API key stored separately in .env file (not committed to Git)'
|
|
806
|
-
)
|
|
944
|
+
' • API key stored separately in .env file (not committed to Git)'
|
|
945
|
+
)
|
|
807
946
|
)
|
|
808
947
|
console.log(
|
|
809
|
-
chalk.cyan(' • Easy cost separation per project/customer')
|
|
948
|
+
chalk.cyan(' • Easy cost separation per project/customer')
|
|
810
949
|
)
|
|
811
950
|
console.log(
|
|
812
|
-
chalk.cyan(' • Secure key management with environment variables')
|
|
951
|
+
chalk.cyan(' • Secure key management with environment variables')
|
|
813
952
|
)
|
|
814
953
|
console.log(
|
|
815
954
|
chalk.cyan(
|
|
816
|
-
" • Project-specific agent documentation (won't overwrite existing)"
|
|
817
|
-
)
|
|
955
|
+
" • Project-specific agent documentation (won't overwrite existing)"
|
|
956
|
+
)
|
|
818
957
|
)
|
|
819
958
|
}
|
|
820
959
|
|
|
@@ -837,7 +976,7 @@ export function registerCodeCommands(program: Command): void {
|
|
|
837
976
|
console.log(chalk.dim(` Small Model: ${config.small_model}`))
|
|
838
977
|
console.log(chalk.dim(` Theme: ${config.theme}`))
|
|
839
978
|
console.log(
|
|
840
|
-
chalk.dim(` API Key: Stored in .env as BERGET_API_KEY`)
|
|
979
|
+
chalk.dim(` API Key: Stored in .env as BERGET_API_KEY`)
|
|
841
980
|
)
|
|
842
981
|
|
|
843
982
|
// Create AGENTS.md documentation only if it doesn't exist
|
|
@@ -1011,11 +1150,11 @@ All agents follow these principles:
|
|
|
1011
1150
|
await writeFile(agentsMdPath, agentsMdContent)
|
|
1012
1151
|
console.log(chalk.green(`✓ Created AGENTS.md`))
|
|
1013
1152
|
console.log(
|
|
1014
|
-
chalk.dim(` Documentation for available agents and usage`)
|
|
1153
|
+
chalk.dim(` Documentation for available agents and usage`)
|
|
1015
1154
|
)
|
|
1016
1155
|
} else {
|
|
1017
1156
|
console.log(
|
|
1018
|
-
chalk.yellow(`⚠ AGENTS.md already exists, skipping creation`)
|
|
1157
|
+
chalk.yellow(`⚠ AGENTS.md already exists, skipping creation`)
|
|
1019
1158
|
)
|
|
1020
1159
|
}
|
|
1021
1160
|
|
|
@@ -1046,7 +1185,7 @@ All agents follow these principles:
|
|
|
1046
1185
|
console.log(chalk.green('\n✅ Project initialized successfully!'))
|
|
1047
1186
|
console.log(chalk.blue('Next steps:'))
|
|
1048
1187
|
console.log(
|
|
1049
|
-
chalk.blue(` berget ${COMMAND_GROUPS.CODE} ${SUBCOMMANDS.CODE.RUN}`)
|
|
1188
|
+
chalk.blue(` berget ${COMMAND_GROUPS.CODE} ${SUBCOMMANDS.CODE.RUN}`)
|
|
1050
1189
|
)
|
|
1051
1190
|
console.log(chalk.blue(' Or run: opencode'))
|
|
1052
1191
|
} catch (error) {
|
|
@@ -1063,7 +1202,7 @@ All agents follow these principles:
|
|
|
1063
1202
|
.option('--no-config', 'Run without loading project config')
|
|
1064
1203
|
.option(
|
|
1065
1204
|
'-y, --yes',
|
|
1066
|
-
'Automatically answer yes to all prompts (for automation)'
|
|
1205
|
+
'Automatically answer yes to all prompts (for automation)'
|
|
1067
1206
|
)
|
|
1068
1207
|
.action(async (prompt: string, options: any) => {
|
|
1069
1208
|
try {
|
|
@@ -1080,12 +1219,12 @@ All agents follow these principles:
|
|
|
1080
1219
|
const configContent = await readFile(configPath, 'utf8')
|
|
1081
1220
|
config = JSON.parse(configContent)
|
|
1082
1221
|
console.log(
|
|
1083
|
-
chalk.dim(`Loaded config for project: ${config.projectName}`)
|
|
1222
|
+
chalk.dim(`Loaded config for project: ${config.projectName}`)
|
|
1084
1223
|
)
|
|
1085
1224
|
console.log(
|
|
1086
1225
|
chalk.dim(
|
|
1087
|
-
`Models: Analysis=${config.analysisModel}, Build=${config.buildModel}
|
|
1088
|
-
)
|
|
1226
|
+
`Models: Analysis=${config.analysisModel}, Build=${config.buildModel}`
|
|
1227
|
+
)
|
|
1089
1228
|
)
|
|
1090
1229
|
} catch (error) {
|
|
1091
1230
|
console.log(chalk.yellow('Warning: Failed to load opencode.json'))
|
|
@@ -1096,8 +1235,10 @@ All agents follow these principles:
|
|
|
1096
1235
|
console.log(chalk.yellow('No project configuration found.'))
|
|
1097
1236
|
console.log(
|
|
1098
1237
|
chalk.blue(
|
|
1099
|
-
`Run ${chalk.bold(
|
|
1100
|
-
|
|
1238
|
+
`Run ${chalk.bold(
|
|
1239
|
+
`berget ${COMMAND_GROUPS.CODE} ${SUBCOMMANDS.CODE.INIT}`
|
|
1240
|
+
)} first.`
|
|
1241
|
+
)
|
|
1101
1242
|
)
|
|
1102
1243
|
return
|
|
1103
1244
|
}
|
|
@@ -1150,10 +1291,13 @@ All agents follow these principles:
|
|
|
1150
1291
|
.command(SUBCOMMANDS.CODE.SERVE)
|
|
1151
1292
|
.description('Start OpenCode web server')
|
|
1152
1293
|
.option('-p, --port <port>', 'Port to run the server on (default: 3000)')
|
|
1153
|
-
.option(
|
|
1294
|
+
.option(
|
|
1295
|
+
'-h, --host <host>',
|
|
1296
|
+
'Host to bind the server to (default: localhost)'
|
|
1297
|
+
)
|
|
1154
1298
|
.option(
|
|
1155
1299
|
'-y, --yes',
|
|
1156
|
-
'Automatically answer yes to all prompts (for automation)'
|
|
1300
|
+
'Automatically answer yes to all prompts (for automation)'
|
|
1157
1301
|
)
|
|
1158
1302
|
.action(async (options) => {
|
|
1159
1303
|
try {
|
|
@@ -1202,7 +1346,7 @@ All agents follow these principles:
|
|
|
1202
1346
|
.option('-f, --force', 'Force update even if already latest')
|
|
1203
1347
|
.option(
|
|
1204
1348
|
'-y, --yes',
|
|
1205
|
-
'Automatically answer yes to all prompts (for automation)'
|
|
1349
|
+
'Automatically answer yes to all prompts (for automation)'
|
|
1206
1350
|
)
|
|
1207
1351
|
.action(async (options) => {
|
|
1208
1352
|
try {
|
|
@@ -1220,8 +1364,10 @@ All agents follow these principles:
|
|
|
1220
1364
|
console.log(chalk.red('❌ No OpenCode configuration found.'))
|
|
1221
1365
|
console.log(
|
|
1222
1366
|
chalk.blue(
|
|
1223
|
-
`Run ${chalk.bold(
|
|
1224
|
-
|
|
1367
|
+
`Run ${chalk.bold(
|
|
1368
|
+
`berget ${COMMAND_GROUPS.CODE} ${SUBCOMMANDS.CODE.INIT}`
|
|
1369
|
+
)} first.`
|
|
1370
|
+
)
|
|
1225
1371
|
)
|
|
1226
1372
|
return
|
|
1227
1373
|
}
|
|
@@ -1242,13 +1388,26 @@ All agents follow these principles:
|
|
|
1242
1388
|
console.log(chalk.dim(` Theme: ${currentConfig.theme}`))
|
|
1243
1389
|
console.log(
|
|
1244
1390
|
chalk.dim(
|
|
1245
|
-
` Agents: ${
|
|
1246
|
-
|
|
1391
|
+
` Agents: ${
|
|
1392
|
+
Object.keys(currentConfig.agent || {}).length
|
|
1393
|
+
} configured`
|
|
1394
|
+
)
|
|
1247
1395
|
)
|
|
1248
1396
|
|
|
1249
1397
|
// Load latest agent configuration to ensure consistency
|
|
1250
1398
|
const latestAgentConfig = await loadLatestAgentConfig()
|
|
1251
|
-
|
|
1399
|
+
|
|
1400
|
+
// Get model config with fallback for init scenario
|
|
1401
|
+
let modelConfig: { primary: string; small: string }
|
|
1402
|
+
try {
|
|
1403
|
+
modelConfig = getModelConfig()
|
|
1404
|
+
} catch (error) {
|
|
1405
|
+
// Fallback to defaults when no config exists (init scenario)
|
|
1406
|
+
modelConfig = {
|
|
1407
|
+
primary: 'berget/glm-4.7',
|
|
1408
|
+
small: 'berget/gpt-oss',
|
|
1409
|
+
}
|
|
1410
|
+
}
|
|
1252
1411
|
|
|
1253
1412
|
// Create latest configuration with all improvements
|
|
1254
1413
|
const latestConfig = {
|
|
@@ -1419,7 +1578,7 @@ All agents follow these principles:
|
|
|
1419
1578
|
const currentAgents = Object.keys(currentConfig.agent || {})
|
|
1420
1579
|
const latestAgents = Object.keys(latestConfig.agent)
|
|
1421
1580
|
const newAgents = latestAgents.filter(
|
|
1422
|
-
(agent) => !currentAgents.includes(agent)
|
|
1581
|
+
(agent) => !currentAgents.includes(agent)
|
|
1423
1582
|
)
|
|
1424
1583
|
|
|
1425
1584
|
if (newAgents.length > 0) {
|
|
@@ -1429,25 +1588,25 @@ All agents follow these principles:
|
|
|
1429
1588
|
// Check for quality agent specifically
|
|
1430
1589
|
if (!currentConfig.agent?.quality && latestConfig.agent.quality) {
|
|
1431
1590
|
console.log(
|
|
1432
|
-
chalk.cyan(' • Quality subagent for testing and PR management')
|
|
1591
|
+
chalk.cyan(' • Quality subagent for testing and PR management')
|
|
1433
1592
|
)
|
|
1434
1593
|
}
|
|
1435
1594
|
|
|
1436
1595
|
// Check for security subagent mode
|
|
1437
1596
|
if (currentConfig.agent?.security?.mode !== 'subagent') {
|
|
1438
1597
|
console.log(
|
|
1439
|
-
chalk.cyan(
|
|
1440
|
-
' • Security agent converted to subagent (read-only)',
|
|
1441
|
-
),
|
|
1598
|
+
chalk.cyan(' • Security agent converted to subagent (read-only)')
|
|
1442
1599
|
)
|
|
1443
1600
|
}
|
|
1444
1601
|
|
|
1445
|
-
// Check for GLM-4.
|
|
1602
|
+
// Check for GLM-4.7 optimizations
|
|
1446
1603
|
if (
|
|
1447
|
-
!currentConfig.provider?.berget?.models?.[
|
|
1604
|
+
!currentConfig.provider?.berget?.models?.[
|
|
1605
|
+
modelConfig.primary.replace('berget/', '')
|
|
1606
|
+
]?.limit?.context
|
|
1448
1607
|
) {
|
|
1449
1608
|
console.log(
|
|
1450
|
-
chalk.cyan(' • GLM-4.
|
|
1609
|
+
chalk.cyan(' • GLM-4.7 token limits and auto-compaction')
|
|
1451
1610
|
)
|
|
1452
1611
|
}
|
|
1453
1612
|
|
|
@@ -1461,8 +1620,8 @@ All agents follow these principles:
|
|
|
1461
1620
|
if (!options.yes) {
|
|
1462
1621
|
console.log(
|
|
1463
1622
|
chalk.blue(
|
|
1464
|
-
'\nThis will update your OpenCode configuration with the latest improvements.'
|
|
1465
|
-
)
|
|
1623
|
+
'\nThis will update your OpenCode configuration with the latest improvements.'
|
|
1624
|
+
)
|
|
1466
1625
|
)
|
|
1467
1626
|
|
|
1468
1627
|
// Check if user has git for backup
|
|
@@ -1470,12 +1629,12 @@ All agents follow these principles:
|
|
|
1470
1629
|
if (!hasGitRepo) {
|
|
1471
1630
|
console.log(
|
|
1472
1631
|
chalk.yellow(
|
|
1473
|
-
'⚠️ No .git repository detected - backup will be created'
|
|
1474
|
-
)
|
|
1632
|
+
'⚠️ No .git repository detected - backup will be created'
|
|
1633
|
+
)
|
|
1475
1634
|
)
|
|
1476
1635
|
} else {
|
|
1477
1636
|
console.log(
|
|
1478
|
-
chalk.green('✓ Git repository detected - changes are tracked')
|
|
1637
|
+
chalk.green('✓ Git repository detected - changes are tracked')
|
|
1479
1638
|
)
|
|
1480
1639
|
}
|
|
1481
1640
|
}
|
|
@@ -1484,13 +1643,13 @@ All agents follow these principles:
|
|
|
1484
1643
|
console.log(chalk.blue('\nChoose update strategy:'))
|
|
1485
1644
|
console.log(
|
|
1486
1645
|
chalk.cyan(
|
|
1487
|
-
'1) Replace - Use latest configuration (your customizations will be lost)'
|
|
1488
|
-
)
|
|
1646
|
+
'1) Replace - Use latest configuration (your customizations will be lost)'
|
|
1647
|
+
)
|
|
1489
1648
|
)
|
|
1490
1649
|
console.log(
|
|
1491
1650
|
chalk.cyan(
|
|
1492
|
-
'2) Merge - Combine latest updates with your customizations (recommended)'
|
|
1493
|
-
)
|
|
1651
|
+
'2) Merge - Combine latest updates with your customizations (recommended)'
|
|
1652
|
+
)
|
|
1494
1653
|
)
|
|
1495
1654
|
|
|
1496
1655
|
let mergeChoice: 'replace' | 'merge' = 'merge'
|
|
@@ -1499,7 +1658,7 @@ All agents follow these principles:
|
|
|
1499
1658
|
const choice = await askChoice(
|
|
1500
1659
|
'\nYour choice (1-2, default: 2): ',
|
|
1501
1660
|
['replace', 'merge'],
|
|
1502
|
-
'merge'
|
|
1661
|
+
'merge'
|
|
1503
1662
|
)
|
|
1504
1663
|
mergeChoice = choice as 'replace' | 'merge'
|
|
1505
1664
|
}
|
|
@@ -1516,12 +1675,12 @@ All agents follow these principles:
|
|
|
1516
1675
|
backupPath = `${configPath}.backup.${Date.now()}`
|
|
1517
1676
|
await writeFile(
|
|
1518
1677
|
backupPath,
|
|
1519
|
-
JSON.stringify(currentConfig, null, 2)
|
|
1678
|
+
JSON.stringify(currentConfig, null, 2)
|
|
1520
1679
|
)
|
|
1521
1680
|
console.log(
|
|
1522
1681
|
chalk.green(
|
|
1523
|
-
`✓ Backed up current config to ${path.basename(backupPath)}
|
|
1524
|
-
)
|
|
1682
|
+
`✓ Backed up current config to ${path.basename(backupPath)}`
|
|
1683
|
+
)
|
|
1525
1684
|
)
|
|
1526
1685
|
}
|
|
1527
1686
|
|
|
@@ -1529,10 +1688,10 @@ All agents follow these principles:
|
|
|
1529
1688
|
// Merge configurations
|
|
1530
1689
|
finalConfig = await mergeConfigurations(
|
|
1531
1690
|
currentConfig,
|
|
1532
|
-
latestConfig
|
|
1691
|
+
latestConfig
|
|
1533
1692
|
)
|
|
1534
1693
|
console.log(
|
|
1535
|
-
chalk.green('✓ Merged configurations with latest updates')
|
|
1694
|
+
chalk.green('✓ Merged configurations with latest updates')
|
|
1536
1695
|
)
|
|
1537
1696
|
} else {
|
|
1538
1697
|
// Replace with latest
|
|
@@ -1544,8 +1703,8 @@ All agents follow these principles:
|
|
|
1544
1703
|
await writeFile(configPath, JSON.stringify(finalConfig, null, 2))
|
|
1545
1704
|
console.log(
|
|
1546
1705
|
chalk.green(
|
|
1547
|
-
`✓ Updated opencode.json with ${mergeChoice} strategy
|
|
1548
|
-
)
|
|
1706
|
+
`✓ Updated opencode.json with ${mergeChoice} strategy`
|
|
1707
|
+
)
|
|
1549
1708
|
)
|
|
1550
1709
|
|
|
1551
1710
|
// Update AGENTS.md if it doesn't exist
|
|
@@ -1723,13 +1882,13 @@ All agents follow these principles:
|
|
|
1723
1882
|
console.log(chalk.green('\n✅ Update completed successfully!'))
|
|
1724
1883
|
console.log(chalk.blue('New features available:'))
|
|
1725
1884
|
console.log(
|
|
1726
|
-
chalk.cyan(' • @quality subagent for testing and PR management')
|
|
1885
|
+
chalk.cyan(' • @quality subagent for testing and PR management')
|
|
1727
1886
|
)
|
|
1728
1887
|
console.log(
|
|
1729
|
-
chalk.cyan(' • @security subagent for security reviews')
|
|
1888
|
+
chalk.cyan(' • @security subagent for security reviews')
|
|
1730
1889
|
)
|
|
1731
1890
|
console.log(chalk.cyan(' • Improved agent prompts and routing'))
|
|
1732
|
-
console.log(chalk.cyan(' • GLM-4.
|
|
1891
|
+
console.log(chalk.cyan(' • GLM-4.7 token optimizations'))
|
|
1733
1892
|
console.log(chalk.blue('\nTry these new commands:'))
|
|
1734
1893
|
console.log(chalk.cyan(' @quality run tests and create PR'))
|
|
1735
1894
|
console.log(chalk.cyan(' @security review this code'))
|
|
@@ -1741,10 +1900,10 @@ All agents follow these principles:
|
|
|
1741
1900
|
try {
|
|
1742
1901
|
await writeFile(
|
|
1743
1902
|
configPath,
|
|
1744
|
-
JSON.stringify(currentConfig, null, 2)
|
|
1903
|
+
JSON.stringify(currentConfig, null, 2)
|
|
1745
1904
|
)
|
|
1746
1905
|
console.log(
|
|
1747
|
-
chalk.yellow('📁 Restored original configuration from backup')
|
|
1906
|
+
chalk.yellow('📁 Restored original configuration from backup')
|
|
1748
1907
|
)
|
|
1749
1908
|
} catch (restoreError) {
|
|
1750
1909
|
console.error(chalk.red('Failed to restore backup:'))
|