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.
- package/dist/package.json +1 -1
- package/dist/src/commands/code/__tests__/setup-flow.test.js +47 -37
- package/dist/src/commands/code/auth-sync.js +3 -3
- package/dist/src/commands/code/{setup.js → init.js} +73 -87
- package/dist/src/commands/code.js +5 -553
- package/dist/src/constants/command-structure.js +1 -9
- package/dist/src/services/auth-service.js +1 -1
- package/dist/tests/commands/code.test.js +4 -415
- package/package.json +1 -1
- package/src/commands/code/__tests__/setup-flow.test.ts +49 -39
- package/src/commands/code/auth-sync.ts +3 -3
- package/src/commands/code/{setup.ts → init.ts} +82 -97
- package/src/commands/code/ports/prompter.ts +1 -0
- package/src/commands/code.ts +5 -608
- package/src/constants/command-structure.ts +1 -11
- package/src/services/auth-service.ts +1 -1
- package/tests/commands/code.test.ts +5 -483
- package/templates/agents/app.md +0 -23
- package/templates/agents/backend.md +0 -23
- package/templates/agents/devops.md +0 -30
- package/templates/agents/frontend.md +0 -25
- package/templates/agents/fullstack.md +0 -23
- package/templates/agents/quality.md +0 -69
- package/templates/agents/security.md +0 -21
|
@@ -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
|
|
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('
|
|
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('
|
|
129
|
+
prompter.outro('Initialization complete!');
|
|
125
130
|
}
|
|
126
131
|
|
|
127
132
|
// ─── OpenCode ────────────────────────────────────────────────────────────────
|
|
128
133
|
|
|
129
|
-
export async function
|
|
134
|
+
export async function runInitCommand(): Promise<void> {
|
|
130
135
|
try {
|
|
131
|
-
await
|
|
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
|
-
// ───
|
|
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(
|
|
372
|
+
prompter.note(`OpenCode config will be updated at:\n ${configPath}`, 'Config update');
|
|
385
373
|
} else {
|
|
386
|
-
prompter.note(`
|
|
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<
|
|
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
|
-
|
|
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
|
-
|
|
442
|
-
|
|
443
|
-
const
|
|
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
|
-
|
|
446
|
-
|
|
447
|
-
|
|
423
|
+
const selectedAgents = await prompter.multiselect({
|
|
424
|
+
message: 'Select agents to set up:',
|
|
425
|
+
options: agentOptions,
|
|
426
|
+
required: false,
|
|
427
|
+
});
|
|
448
428
|
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
`Changes to ${agentName} agent`,
|
|
453
|
-
);
|
|
454
|
-
}
|
|
429
|
+
if (selectedAgents.length === 0) {
|
|
430
|
+
return false;
|
|
431
|
+
}
|
|
455
432
|
|
|
456
|
-
|
|
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
|
-
|
|
461
|
-
|
|
462
|
-
|
|
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<
|
|
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
|
-
|
|
588
|
-
const newContent = toPiPrompt(agent);
|
|
559
|
+
prompter.note('Pi uses a single system prompt.', 'Agent Setup');
|
|
589
560
|
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
}
|
|
561
|
+
const setupAgent = await prompter.confirm({
|
|
562
|
+
initialValue: false,
|
|
563
|
+
message: 'Set up an agent for Pi?',
|
|
564
|
+
});
|
|
594
565
|
|
|
595
|
-
if (
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
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:
|
|
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,
|
|
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 {
|