Skip to content

Commit 0fdf189

Browse files
authored
Remove agent selection from Pi init flow (#79)
- Stop prompting users to select/configure an agent during berget code init for Pi - Pi init now only installs the provider and sets defaultProvider = 'berget' - Delete initPiAgent function and its imports (getAllAgents, toPiPrompt) - Remove toPiPrompt export from src/agents/index.ts (was only used by initPiAgent) - Update tests: remove agent-selection prompts from Pi tests, delete obsolete Pi agent tests
1 parent 2c1d764 commit 0fdf189

5 files changed

Lines changed: 57 additions & 187 deletions

File tree

PLAN.md

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# Remove Agent Selection from Pi in the Init Command
2+
3+
## Goal
4+
5+
Stop prompting users to select and configure an agent during `berget code init` when they choose Pi. The Pi init flow should only install the provider and set `defaultProvider = 'berget'`.
6+
7+
## Background
8+
9+
Pi uses a single system prompt (`SYSTEM.md`), so the init wizard currently asks:
10+
11+
1. "Set up an agent for Pi?"
12+
2. Choose an agent from a list
13+
3. Write/replace `SYSTEM.md`
14+
15+
This adds friction. Pi users can configure agents manually; the init command should focus on auth + provider setup only.
16+
17+
OpenCode will keep its multi-agent selection flow (agents are stored as separate `.md` files).
18+
19+
## Files to Change
20+
21+
### 1. `src/commands/code/init.ts`
22+
23+
- Remove `initPiAgent` from the import from `./pi.js`
24+
- In `configureTool()`, remove the `await initPiAgent({ cwd, files, homeDir, prompter, scope })` call
25+
26+
### 2. `src/commands/code/pi.ts`
27+
28+
- Delete the entire `initPiAgent` function
29+
- Remove unused imports: `getAllAgents`, `toPiPrompt`
30+
- `getPiAgentDir` is still used for auth/settings paths → **keep**
31+
32+
### 3. `src/agents/index.ts`
33+
34+
- Remove the `toPiPrompt` export (only used by `initPiAgent`)
35+
36+
### 4. `src/commands/code/__tests__/init.test.ts`
37+
38+
Update Pi-related tests to no longer include agent-selection prompts or assert `SYSTEM.md` creation.
39+
40+
| Action | Test(s) |
41+
| ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
42+
| **Remove agent prompts** | `sets up pi project with fresh install`, `preserves existing Pi settings when setting defaultProvider`, `creates api key for pi when no seat`, `login failure shows manual auth instructions` |
43+
| **Delete** | `skips agent selection for pi project` (rename or repurpose), `sets up agent for pi project`, `sets up agent for pi globally`, `overwrites pi SYSTEM.md when content differs`, `throws CancelledError when user cancels at agent write confirmation (pi)` |
44+
45+
## Verification
46+
47+
- [ ] `npm run test:run` passes
48+
- [ ] `npm run typecheck` passes
49+
- [ ] `npm run lint` passes

src/agents/index.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,4 @@ export function toMarkdown(agent: Agent): string {
6666
return `${frontmatter}---\n\n${systemPrompt}`;
6767
}
6868

69-
export function toPiPrompt(agent: Agent): string {
70-
return agent.systemPrompt;
71-
}
72-
7369
export { type Agent, type AgentConfig } from './types.js';

src/commands/code/__tests__/init.test.ts

Lines changed: 5 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -131,13 +131,7 @@ describe('runInit', () => {
131131
commands: new FakeCommandRunner()
132132
.handle('pi --version', 'mocked') // For checkInstalled
133133
.handle('pi install', ''), // For actual install
134-
prompter: new FakePrompter([
135-
select('pi'),
136-
select('project'),
137-
confirm(true, 'Set up an agent for Pi?'),
138-
select('fullstack'), // Agent selection
139-
confirm(true, 'Create'),
140-
]),
134+
prompter: new FakePrompter([select('pi'), select('project')]),
141135
});
142136

143137
await runInit(deps);
@@ -148,26 +142,15 @@ describe('runInit', () => {
148142
expect(installCall?.args).toContain('npm:@bergetai/pi-provider');
149143
});
150144

151-
it('skips agent selection for pi project', async () => {
145+
it('completes pi init without agent prompts', async () => {
152146
const deps = makeDeps({
153147
commands: new FakeCommandRunner()
154148
.handle('pi --version', 'mocked') // For checkInstalled
155149
.handle('pi install', ''), // For actual install
156-
prompter: new FakePrompter([
157-
select('pi'),
158-
select('project'),
159-
confirm(false, 'Set up an agent for Pi?'),
160-
]),
150+
prompter: new FakePrompter([select('pi'), select('project')]),
161151
});
162152

163-
await runInit(deps);
164-
165-
const files = deps.files as FakeFileStore;
166-
const written = files.getWrittenFiles();
167-
// Should not create any agent files
168-
for (const path of written.keys()) {
169-
expect(path).not.toContain('SYSTEM.md');
170-
}
153+
await expect(runInit(deps)).resolves.not.toThrow();
171154
});
172155
});
173156

@@ -331,21 +314,6 @@ describe('runInit', () => {
331314

332315
await expect(runInit(deps)).rejects.toBeInstanceOf(CancelledError);
333316
});
334-
335-
it('throws CancelledError when user cancels at agent write confirmation (pi)', async () => {
336-
const deps = makeDeps({
337-
commands: new FakeCommandRunner().handle('pi --version', 'mocked').handle('pi install', ''),
338-
prompter: new FakePrompter([
339-
select('pi'),
340-
select('project'),
341-
confirm(true, 'Set up an agent for Pi?'),
342-
select('fullstack'),
343-
confirm(false, /Create|Overwrite/),
344-
]),
345-
});
346-
347-
await expect(runInit(deps)).rejects.toBeInstanceOf(CancelledError);
348-
});
349317
});
350318

351319
describe('file operations', () => {
@@ -440,13 +408,7 @@ describe('runInit', () => {
440408
it('preserves existing Pi settings when setting defaultProvider', async () => {
441409
const deps = makeDeps({
442410
commands: new FakeCommandRunner().handle('pi --version', 'mocked').handle('pi install', ''),
443-
prompter: new FakePrompter([
444-
select('pi'),
445-
select('project'),
446-
confirm(true, 'Set up an agent for Pi?'),
447-
select('fullstack'),
448-
confirm(true, 'Create'),
449-
]),
411+
prompter: new FakePrompter([select('pi'), select('project')]),
450412
});
451413

452414
const files = deps.files as FakeFileStore;
@@ -581,9 +543,6 @@ describe('runInit', () => {
581543
select('pi'),
582544
select('project'),
583545
confirm(true), // API key creation prompt
584-
confirm(true, 'Set up an agent for Pi?'),
585-
select('fullstack'),
586-
confirm(true, 'Create'),
587546
]),
588547
});
589548

@@ -683,44 +642,6 @@ describe('runInit', () => {
683642
expect(written.has('/home/user/.config/opencode/agents/fullstack.md')).toBe(true);
684643
});
685644

686-
it('sets up agent for pi project', async () => {
687-
const deps = makeDeps({
688-
commands: new FakeCommandRunner().handle('pi --version', 'mocked').handle('pi install', ''),
689-
prompter: new FakePrompter([
690-
select('pi'),
691-
select('project'),
692-
confirm(true, 'Set up an agent for Pi?'),
693-
select('fullstack'),
694-
confirm(true, 'Create'),
695-
]),
696-
});
697-
698-
await runInit(deps);
699-
700-
const files = deps.files as FakeFileStore;
701-
const written = files.getWrittenFiles();
702-
expect(written.has('/home/user/project/.pi/SYSTEM.md')).toBe(true);
703-
});
704-
705-
it('sets up agent for pi globally', async () => {
706-
const deps = makeDeps({
707-
commands: new FakeCommandRunner().handle('pi --version', 'mocked').handle('pi install', ''),
708-
prompter: new FakePrompter([
709-
select('pi'),
710-
select('global'),
711-
confirm(true, 'Set up an agent for Pi?'),
712-
select('backend'),
713-
confirm(true, 'Create'),
714-
]),
715-
});
716-
717-
await runInit(deps);
718-
719-
const files = deps.files as FakeFileStore;
720-
const written = files.getWrittenFiles();
721-
expect(written.has('/home/user/.pi/agent/SYSTEM.md')).toBe(true);
722-
});
723-
724645
it('skips writing identical opencode agent files', async () => {
725646
const deps = makeDeps({
726647
prompter: new FakePrompter([
@@ -764,31 +685,6 @@ describe('runInit', () => {
764685
firstFrontend,
765686
);
766687
});
767-
768-
it('overwrites pi SYSTEM.md when content differs', async () => {
769-
const files = new FakeFileStore();
770-
files.seed('/home/user/project/.pi/SYSTEM.md', 'old agent content');
771-
772-
const deps = makeDeps({
773-
commands: new FakeCommandRunner().handle('pi --version', 'mocked').handle('pi install', ''),
774-
files,
775-
prompter: new FakePrompter([
776-
select('pi'),
777-
select('project'),
778-
confirm(true, 'Set up an agent for Pi?'),
779-
select('fullstack'),
780-
confirm(true, 'SYSTEM.md already exists'),
781-
]),
782-
});
783-
784-
await runInit(deps);
785-
786-
const written = files.getWrittenFiles();
787-
const content = written.get('/home/user/project/.pi/SYSTEM.md');
788-
expect(content).not.toBe('old agent content');
789-
// Pi doesn't use front matter, so check for system prompt content
790-
expect(content).toContain('Fullstack Agent');
791-
});
792688
});
793689

794690
describe('nextSteps branching', () => {

src/commands/code/init.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import {
1919
initOpenCode,
2020
initOpenCodeAgents,
2121
} from './opencode.js';
22-
import { getPiLabel, getPiState, initPi, initPiAgent } from './pi.js';
22+
import { getPiLabel, getPiState, initPi } from './pi.js';
2323
import { checkTool, promptForMissingTool } from './tool-check.js';
2424

2525
export interface InitCommandResult {
@@ -207,7 +207,6 @@ async function configureTool(
207207
await initOpenCodeAgents({ cwd, files, homeDir, prompter, scope });
208208
} else {
209209
await initPi({ commands, cwd, files, homeDir, prompter, scope });
210-
await initPiAgent({ cwd, files, homeDir, prompter, scope });
211210
}
212211
}
213212

src/commands/code/pi.ts

Lines changed: 2 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,9 @@ import type { CommandRunner } from './ports/command-runner.js';
44
import type { FileStore } from './ports/file-store.js';
55
import type { Prompter } from './ports/prompter.js';
66

7-
import { getAllAgents, toPiPrompt } from '../../agents/index.js';
8-
import { CancelledError, CommandFailedError } from './errors.js';
7+
import { CommandFailedError } from './errors.js';
98
import { readJsonMaybe, writeJsonFile } from './utils.js';
10-
import { getPiAgentDir, getPiSettingsPath } from './xdg-paths.js';
9+
import { getPiSettingsPath } from './xdg-paths.js';
1110

1211
const PI_PROVIDER = 'npm:@bergetai/pi-provider';
1312
const PI_PROVIDER_NAME = '@bergetai/pi-provider';
@@ -92,75 +91,6 @@ export async function initPi(deps: InitPiDeps): Promise<void> {
9291
}
9392
}
9493

95-
export async function initPiAgent(deps: {
96-
cwd: string;
97-
files: FileStore;
98-
homeDir: string;
99-
prompter: Prompter;
100-
scope: 'global' | 'project';
101-
}): Promise<boolean> {
102-
const { cwd, files, homeDir, prompter, scope } = deps;
103-
104-
const agents = getAllAgents().filter((a) => a.config.mode === 'primary');
105-
106-
if (agents.length === 0) {
107-
return false;
108-
}
109-
110-
const systemPath =
111-
scope === 'project'
112-
? path.join(cwd, '.pi', 'SYSTEM.md')
113-
: path.join(getPiAgentDir(homeDir), 'SYSTEM.md');
114-
115-
prompter.note('Pi uses a single system prompt.', 'Agent Setup');
116-
117-
const shouldInitAgent = await prompter.confirm({
118-
initialValue: false,
119-
message: 'Set up an agent for Pi?',
120-
});
121-
122-
if (!shouldInitAgent) return false;
123-
124-
const selectedAgentName = await prompter.select({
125-
message: 'Choose an agent:',
126-
options: agents.map((agent) => ({
127-
hint: agent.config.description,
128-
label: agent.config.name,
129-
value: agent.config.name,
130-
})),
131-
});
132-
133-
const agent = agents.find((a) => a.config.name === selectedAgentName);
134-
if (!agent) return false;
135-
136-
const systemExists = await files.exists(systemPath);
137-
const confirmMsg = systemExists
138-
? `SYSTEM.md already exists. Replace with ${agent.config.name}?`
139-
: 'Create agent configuration?';
140-
141-
const shouldWrite = await prompter.confirm({
142-
initialValue: true,
143-
message: confirmMsg,
144-
});
145-
146-
if (!shouldWrite) {
147-
throw new CancelledError();
148-
}
149-
150-
const s = prompter.spinner();
151-
s.start('Writing agent configuration...');
152-
try {
153-
const systemDir = scope === 'project' ? path.join(cwd, '.pi') : getPiAgentDir(homeDir);
154-
await files.mkdir(systemDir);
155-
await files.writeFile(systemPath, toPiPrompt(agent));
156-
s.stop(`Wrote agent configuration to ${systemPath}`);
157-
} catch (error) {
158-
s.stop('Failed to write agent configuration.');
159-
throw error;
160-
}
161-
return true;
162-
}
163-
16494
function hasPiProviderInSettings(settings: unknown): boolean {
16595
if (!settings || typeof settings !== 'object') return false;
16696
const packages = (settings as Record<string, unknown>).packages;

0 commit comments

Comments
 (0)