berget 2.2.10 → 2.2.12

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.
@@ -1,3 +1,4 @@
1
+ import chalk from 'chalk';
1
2
  import { applyEdits, modify, parse } from 'jsonc-parser';
2
3
  import * as os from 'node:os';
3
4
 
@@ -15,7 +16,7 @@ import { SpawnCommandRunner } from './adapters/spawn-command-runner.js';
15
16
  import { configureAuth } from './auth-sync.js';
16
17
  import { CancelledError, CommandFailedError, PrerequisiteError } from './errors';
17
18
 
18
- const OPENCODE_PLUGIN = '@bergetai/opencode-auth';
19
+ const OPENCODE_PLUGIN = '@bergetai/opencode-auth@1.0.21';
19
20
  const PI_PROVIDER = 'npm:@bergetai/pi-provider';
20
21
  const OPENCODE_PLUGIN_NAME = '@bergetai/opencode-auth';
21
22
  const PI_PROVIDER_NAME = '@bergetai/pi-provider';
@@ -30,10 +31,14 @@ export interface WizardDeps {
30
31
  prompter: Prompter;
31
32
  }
32
33
 
33
- export async function runSetup(deps: WizardDeps): Promise<void> {
34
+ export async function runInit(deps: WizardDeps): Promise<void> {
34
35
  const { apiKeyService, authService, commands, cwd, files, homeDir, prompter } = deps;
35
36
 
36
- prompter.intro('\uD83D\uDD27 Berget Code Setup');
37
+ prompter.intro(`${chalk.bgGreen.black(' berget code ')}`);
38
+ prompter.note(
39
+ `Ask questions and report bugs on our GitHub repository:\n\n${chalk.cyan.underline('https://github.com/berget-ai/cli')}`,
40
+ 'Need help?',
41
+ );
37
42
 
38
43
  const ocState = await getOpencodeState(files, homeDir, cwd);
39
44
  const piState = await getPiState(files, homeDir, cwd);
@@ -121,14 +126,14 @@ export async function runSetup(deps: WizardDeps): Promise<void> {
121
126
  }
122
127
  }
123
128
 
124
- prompter.outro('Setup complete!');
129
+ prompter.outro('Initialization complete!');
125
130
  }
126
131
 
127
132
  // ─── OpenCode ────────────────────────────────────────────────────────────────
128
133
 
129
- export async function runSetupCommand(): Promise<void> {
134
+ export async function runInitCommand(): Promise<void> {
130
135
  try {
131
- await runSetup({
136
+ await runInit({
132
137
  apiKeyService: ApiKeyService.getInstance(),
133
138
  authService: AuthService.getInstance(),
134
139
  commands: new SpawnCommandRunner(),
@@ -154,24 +159,7 @@ export async function runSetupCommand(): Promise<void> {
154
159
  }
155
160
  }
156
161
 
157
- // ─── Pi ────────────────────────────────────────────────────────────────────────
158
-
159
- function generateDiff(oldText: string, newText: string, filePath: string): string {
160
- const oldLines = oldText.split('\n');
161
- const newLines = newText.split('\n');
162
- let result = `--- ${filePath}\n+++ ${filePath}\n`;
163
-
164
- const maxLength = Math.max(oldLines.length, newLines.length);
165
- for (let index = 0; index < maxLength; index++) {
166
- const oldLine = oldLines[index];
167
- const newLine = newLines[index];
168
- if (oldLine !== newLine) {
169
- if (oldLine !== undefined) result += `- ${oldLine}\n`;
170
- if (newLine !== undefined) result += `+ ${newLine}\n`;
171
- }
172
- }
173
- return result.trimEnd();
174
- }
162
+ // ─── OpenCode Config Helpers ──────────────────────────────────────────────────
175
163
 
176
164
  function generateModifiedContent(existingContent: null | string, configPath: string): string {
177
165
  if (configPath.endsWith('.jsonc')) {
@@ -381,9 +369,9 @@ async function setupOpenCode(deps: {
381
369
  }
382
370
 
383
371
  if (existingContent) {
384
- prompter.note(generateDiff(existingContent, newContent, configPath), 'Changes to be written');
372
+ prompter.note(`OpenCode config will be updated at:\n ${configPath}`, 'Config update');
385
373
  } else {
386
- prompter.note(`New config at ${configPath}:\n\n${newContent}`, 'Config preview');
374
+ prompter.note(`OpenCode config will be created at:\n ${configPath}`, 'Config update');
387
375
  }
388
376
 
389
377
  const shouldWrite = await prompter.confirm({
@@ -404,26 +392,13 @@ async function setupOpenCodeAgents(deps: {
404
392
  homeDir: string;
405
393
  prompter: Prompter;
406
394
  scope: 'global' | 'project';
407
- }): Promise<void> {
395
+ }): Promise<boolean> {
408
396
  const { cwd, files, homeDir, prompter, scope } = deps;
409
397
 
410
398
  const agents = getAllAgents().filter((a) => a.config.mode === 'primary');
411
399
 
412
400
  if (agents.length === 0) {
413
- return;
414
- }
415
-
416
- const selectedAgents = await prompter.multiselect({
417
- message: 'Select agents to set up (optional - press enter to skip):',
418
- options: agents.map((agent) => ({
419
- hint: agent.config.description,
420
- label: agent.config.name,
421
- value: agent.config.name,
422
- })),
423
- });
424
-
425
- if (selectedAgents.length === 0) {
426
- return;
401
+ return false;
427
402
  }
428
403
 
429
404
  const agentsDir =
@@ -431,35 +406,48 @@ async function setupOpenCodeAgents(deps: {
431
406
  ? pathJoin(cwd, '.opencode', 'agents')
432
407
  : pathJoin(homeDir, '.config', 'opencode', 'agents');
433
408
 
434
- await files.mkdir(agentsDir);
435
-
436
- const hasChanges = await Promise.all(
437
- selectedAgents.map(async (agentName) => {
438
- const agent = agents.find((a) => a.config.name === agentName);
439
- if (!agent) return false;
409
+ prompter.note('Space to toggle, Enter to confirm.', 'Agent Setup');
440
410
 
441
- const agentPath = pathJoin(agentsDir, `${agentName}.md`);
442
- const existing = await files.readFile(agentPath);
443
- const newContent = toMarkdown(agent);
411
+ const agentOptions = await Promise.all(
412
+ agents.map(async (agent) => {
413
+ const agentPath = pathJoin(agentsDir, `${agent.config.name}.md`);
414
+ const exists = await files.exists(agentPath);
415
+ return {
416
+ hint: exists ? 'already configured' : agent.config.description,
417
+ label: agent.config.name,
418
+ value: agent.config.name,
419
+ };
420
+ }),
421
+ );
444
422
 
445
- if (existing === newContent) {
446
- return false;
447
- }
423
+ const selectedAgents = await prompter.multiselect({
424
+ message: 'Select agents to set up:',
425
+ options: agentOptions,
426
+ required: false,
427
+ });
448
428
 
449
- if (existing) {
450
- prompter.note(
451
- generateDiff(existing, newContent, agentPath),
452
- `Changes to ${agentName} agent`,
453
- );
454
- }
429
+ if (selectedAgents.length === 0) {
430
+ return false;
431
+ }
455
432
 
456
- return true;
433
+ const newAgents: string[] = [];
434
+ const existingAgents: string[] = [];
435
+ await Promise.all(
436
+ selectedAgents.map(async (agentName) => {
437
+ const agentPath = pathJoin(agentsDir, `${agentName}.md`);
438
+ const exists = await files.exists(agentPath);
439
+ (exists ? existingAgents : newAgents).push(agentName);
457
440
  }),
458
441
  );
459
442
 
460
- if (!hasChanges.some(Boolean)) {
461
- prompter.note('Agent files are already up to date.', 'No changes needed');
462
- return;
443
+ const summaryParts: string[] = [];
444
+ if (newAgents.length > 0) summaryParts.push(`New: ${newAgents.join(', ')}`);
445
+ if (existingAgents.length > 0) summaryParts.push(`Replaced: ${existingAgents.join(', ')}`);
446
+ if (summaryParts.length > 0) {
447
+ prompter.note(
448
+ ` Agent Setup Summary:\n${summaryParts.map((part) => ` ${part}`).join('\n')}`,
449
+ 'Agent Setup',
450
+ );
463
451
  }
464
452
 
465
453
  const shouldWrite = await prompter.confirm({
@@ -471,6 +459,8 @@ async function setupOpenCodeAgents(deps: {
471
459
  throw new CancelledError();
472
460
  }
473
461
 
462
+ await files.mkdir(agentsDir);
463
+
474
464
  const s = prompter.spinner();
475
465
  s.start('Writing agent configurations...');
476
466
 
@@ -484,6 +474,7 @@ async function setupOpenCodeAgents(deps: {
484
474
  }
485
475
 
486
476
  s.stop(`Wrote ${selectedAgents.length} agent(s) to ${agentsDir}`);
477
+ return true;
487
478
  }
488
479
 
489
480
  async function setupPi(deps: {
@@ -551,56 +542,49 @@ async function setupPiAgent(deps: {
551
542
  homeDir: string;
552
543
  prompter: Prompter;
553
544
  scope: 'global' | 'project';
554
- }): Promise<void> {
545
+ }): Promise<boolean> {
555
546
  const { cwd, files, homeDir, prompter, scope } = deps;
556
547
 
557
548
  const agents = getAllAgents().filter((a) => a.config.mode === 'primary');
558
549
 
559
550
  if (agents.length === 0) {
560
- return;
561
- }
562
-
563
- const selectedAgentName = await prompter.select({
564
- message: 'Select an agent (optional - press enter to skip):',
565
- options: [
566
- { label: 'Skip agent setup', value: '__skip__' },
567
- ...agents.map((agent) => ({
568
- hint: agent.config.description,
569
- label: agent.config.name,
570
- value: agent.config.name,
571
- })),
572
- ],
573
- });
574
-
575
- if (selectedAgentName === '__skip__') {
576
- return;
551
+ return false;
577
552
  }
578
553
 
579
- const agent = agents.find((a) => a.config.name === selectedAgentName);
580
- if (!agent) return;
581
-
582
554
  const systemPath =
583
555
  scope === 'project'
584
556
  ? pathJoin(cwd, '.pi', 'SYSTEM.md')
585
557
  : pathJoin(homeDir, '.pi', 'agent', 'SYSTEM.md');
586
558
 
587
- const existing = await files.readFile(systemPath);
588
- const newContent = toPiPrompt(agent);
559
+ prompter.note('Pi uses a single system prompt.', 'Agent Setup');
589
560
 
590
- if (existing === newContent) {
591
- prompter.note('Agent configuration is already up to date.', 'No changes needed');
592
- return;
593
- }
561
+ const setupAgent = await prompter.confirm({
562
+ initialValue: false,
563
+ message: 'Set up an agent for Pi?',
564
+ });
594
565
 
595
- if (existing) {
596
- prompter.note(generateDiff(existing, newContent, systemPath), 'Changes to agent configuration');
597
- } else {
598
- prompter.note(newContent, 'New agent configuration');
599
- }
566
+ if (!setupAgent) return false;
567
+
568
+ const selectedAgentName = await prompter.select({
569
+ message: 'Choose an agent:',
570
+ options: agents.map((agent) => ({
571
+ hint: agent.config.description,
572
+ label: agent.config.name,
573
+ value: agent.config.name,
574
+ })),
575
+ });
576
+
577
+ const agent = agents.find((a) => a.config.name === selectedAgentName);
578
+ if (!agent) return false;
579
+
580
+ const systemExists = await files.exists(systemPath);
581
+ const confirmMsg = systemExists
582
+ ? `SYSTEM.md already exists. Replace with ${agent.config.name}?`
583
+ : 'Create agent configuration?';
600
584
 
601
585
  const shouldWrite = await prompter.confirm({
602
586
  initialValue: true,
603
- message: existing ? 'Overwrite existing agent configuration?' : 'Create agent configuration?',
587
+ message: confirmMsg,
604
588
  });
605
589
 
606
590
  if (!shouldWrite) {
@@ -612,9 +596,10 @@ async function setupPiAgent(deps: {
612
596
 
613
597
  const systemDir = scope === 'project' ? pathJoin(cwd, '.pi') : pathJoin(homeDir, '.pi', 'agent');
614
598
  await files.mkdir(systemDir);
615
- await files.writeFile(systemPath, newContent);
599
+ await files.writeFile(systemPath, toPiPrompt(agent));
616
600
 
617
601
  s.stop(`Wrote agent configuration to ${systemPath}`);
602
+ return true;
618
603
  }
619
604
 
620
605
  function stripJsoncComments(content: string): string {
@@ -8,6 +8,7 @@ export interface Prompter {
8
8
  label: string;
9
9
  value: T;
10
10
  }>;
11
+ required?: boolean;
11
12
  }): Promise<T[]>;
12
13
  note(message: string, title?: string): void;
13
14
  outro(message: string): void;