From 8c209bd55e30819849cdf31cf063140782985f9b Mon Sep 17 00:00:00 2001 From: Marcus Olsson <8396880+marcusolsson@users.noreply.github.com> Date: Mon, 15 Jun 2026 08:50:40 +0200 Subject: [PATCH] Remove agent selection from Pi init flow - 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 --- PLAN.md | 49 ++++++++++ src/agents/index.ts | 4 - src/commands/code/__tests__/init.test.ts | 114 +---------------------- src/commands/code/init.ts | 3 +- src/commands/code/pi.ts | 74 +-------------- 5 files changed, 57 insertions(+), 187 deletions(-) create mode 100644 PLAN.md diff --git a/PLAN.md b/PLAN.md new file mode 100644 index 0000000..85c5741 --- /dev/null +++ b/PLAN.md @@ -0,0 +1,49 @@ +# Remove Agent Selection from Pi in the Init Command + +## Goal + +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'`. + +## Background + +Pi uses a single system prompt (`SYSTEM.md`), so the init wizard currently asks: + +1. "Set up an agent for Pi?" +2. Choose an agent from a list +3. Write/replace `SYSTEM.md` + +This adds friction. Pi users can configure agents manually; the init command should focus on auth + provider setup only. + +OpenCode will keep its multi-agent selection flow (agents are stored as separate `.md` files). + +## Files to Change + +### 1. `src/commands/code/init.ts` + +- Remove `initPiAgent` from the import from `./pi.js` +- In `configureTool()`, remove the `await initPiAgent({ cwd, files, homeDir, prompter, scope })` call + +### 2. `src/commands/code/pi.ts` + +- Delete the entire `initPiAgent` function +- Remove unused imports: `getAllAgents`, `toPiPrompt` +- `getPiAgentDir` is still used for auth/settings paths → **keep** + +### 3. `src/agents/index.ts` + +- Remove the `toPiPrompt` export (only used by `initPiAgent`) + +### 4. `src/commands/code/__tests__/init.test.ts` + +Update Pi-related tests to no longer include agent-selection prompts or assert `SYSTEM.md` creation. + +| Action | Test(s) | +| ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **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` | +| **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)` | + +## Verification + +- [ ] `npm run test:run` passes +- [ ] `npm run typecheck` passes +- [ ] `npm run lint` passes diff --git a/src/agents/index.ts b/src/agents/index.ts index cf4dd20..bdf0e76 100644 --- a/src/agents/index.ts +++ b/src/agents/index.ts @@ -66,8 +66,4 @@ export function toMarkdown(agent: Agent): string { return `${frontmatter}---\n\n${systemPrompt}`; } -export function toPiPrompt(agent: Agent): string { - return agent.systemPrompt; -} - export { type Agent, type AgentConfig } from './types.js'; diff --git a/src/commands/code/__tests__/init.test.ts b/src/commands/code/__tests__/init.test.ts index dea07d4..d0a33a2 100644 --- a/src/commands/code/__tests__/init.test.ts +++ b/src/commands/code/__tests__/init.test.ts @@ -131,13 +131,7 @@ describe('runInit', () => { commands: new FakeCommandRunner() .handle('pi --version', 'mocked') // For checkInstalled .handle('pi install', ''), // For actual install - prompter: new FakePrompter([ - select('pi'), - select('project'), - confirm(true, 'Set up an agent for Pi?'), - select('fullstack'), // Agent selection - confirm(true, 'Create'), - ]), + prompter: new FakePrompter([select('pi'), select('project')]), }); await runInit(deps); @@ -148,26 +142,15 @@ describe('runInit', () => { expect(installCall?.args).toContain('npm:@bergetai/pi-provider'); }); - it('skips agent selection for pi project', async () => { + it('completes pi init without agent prompts', async () => { const deps = makeDeps({ commands: new FakeCommandRunner() .handle('pi --version', 'mocked') // For checkInstalled .handle('pi install', ''), // For actual install - prompter: new FakePrompter([ - select('pi'), - select('project'), - confirm(false, 'Set up an agent for Pi?'), - ]), + prompter: new FakePrompter([select('pi'), select('project')]), }); - await runInit(deps); - - const files = deps.files as FakeFileStore; - const written = files.getWrittenFiles(); - // Should not create any agent files - for (const path of written.keys()) { - expect(path).not.toContain('SYSTEM.md'); - } + await expect(runInit(deps)).resolves.not.toThrow(); }); }); @@ -331,21 +314,6 @@ describe('runInit', () => { await expect(runInit(deps)).rejects.toBeInstanceOf(CancelledError); }); - - it('throws CancelledError when user cancels at agent write confirmation (pi)', async () => { - const deps = makeDeps({ - commands: new FakeCommandRunner().handle('pi --version', 'mocked').handle('pi install', ''), - prompter: new FakePrompter([ - select('pi'), - select('project'), - confirm(true, 'Set up an agent for Pi?'), - select('fullstack'), - confirm(false, /Create|Overwrite/), - ]), - }); - - await expect(runInit(deps)).rejects.toBeInstanceOf(CancelledError); - }); }); describe('file operations', () => { @@ -440,13 +408,7 @@ describe('runInit', () => { it('preserves existing Pi settings when setting defaultProvider', async () => { const deps = makeDeps({ commands: new FakeCommandRunner().handle('pi --version', 'mocked').handle('pi install', ''), - prompter: new FakePrompter([ - select('pi'), - select('project'), - confirm(true, 'Set up an agent for Pi?'), - select('fullstack'), - confirm(true, 'Create'), - ]), + prompter: new FakePrompter([select('pi'), select('project')]), }); const files = deps.files as FakeFileStore; @@ -581,9 +543,6 @@ describe('runInit', () => { select('pi'), select('project'), confirm(true), // API key creation prompt - confirm(true, 'Set up an agent for Pi?'), - select('fullstack'), - confirm(true, 'Create'), ]), }); @@ -683,44 +642,6 @@ describe('runInit', () => { expect(written.has('/home/user/.config/opencode/agents/fullstack.md')).toBe(true); }); - it('sets up agent for pi project', async () => { - const deps = makeDeps({ - commands: new FakeCommandRunner().handle('pi --version', 'mocked').handle('pi install', ''), - prompter: new FakePrompter([ - select('pi'), - select('project'), - confirm(true, 'Set up an agent for Pi?'), - select('fullstack'), - confirm(true, 'Create'), - ]), - }); - - await runInit(deps); - - const files = deps.files as FakeFileStore; - const written = files.getWrittenFiles(); - expect(written.has('/home/user/project/.pi/SYSTEM.md')).toBe(true); - }); - - it('sets up agent for pi globally', async () => { - const deps = makeDeps({ - commands: new FakeCommandRunner().handle('pi --version', 'mocked').handle('pi install', ''), - prompter: new FakePrompter([ - select('pi'), - select('global'), - confirm(true, 'Set up an agent for Pi?'), - select('backend'), - confirm(true, 'Create'), - ]), - }); - - await runInit(deps); - - const files = deps.files as FakeFileStore; - const written = files.getWrittenFiles(); - expect(written.has('/home/user/.pi/agent/SYSTEM.md')).toBe(true); - }); - it('skips writing identical opencode agent files', async () => { const deps = makeDeps({ prompter: new FakePrompter([ @@ -764,31 +685,6 @@ describe('runInit', () => { firstFrontend, ); }); - - it('overwrites pi SYSTEM.md when content differs', async () => { - const files = new FakeFileStore(); - files.seed('/home/user/project/.pi/SYSTEM.md', 'old agent content'); - - const deps = makeDeps({ - commands: new FakeCommandRunner().handle('pi --version', 'mocked').handle('pi install', ''), - files, - prompter: new FakePrompter([ - select('pi'), - select('project'), - confirm(true, 'Set up an agent for Pi?'), - select('fullstack'), - confirm(true, 'SYSTEM.md already exists'), - ]), - }); - - await runInit(deps); - - const written = files.getWrittenFiles(); - const content = written.get('/home/user/project/.pi/SYSTEM.md'); - expect(content).not.toBe('old agent content'); - // Pi doesn't use front matter, so check for system prompt content - expect(content).toContain('Fullstack Agent'); - }); }); describe('nextSteps branching', () => { diff --git a/src/commands/code/init.ts b/src/commands/code/init.ts index 44b93c3..2f8fb1b 100644 --- a/src/commands/code/init.ts +++ b/src/commands/code/init.ts @@ -19,7 +19,7 @@ import { initOpenCode, initOpenCodeAgents, } from './opencode.js'; -import { getPiLabel, getPiState, initPi, initPiAgent } from './pi.js'; +import { getPiLabel, getPiState, initPi } from './pi.js'; import { checkTool, promptForMissingTool } from './tool-check.js'; export interface InitCommandResult { @@ -207,7 +207,6 @@ async function configureTool( await initOpenCodeAgents({ cwd, files, homeDir, prompter, scope }); } else { await initPi({ commands, cwd, files, homeDir, prompter, scope }); - await initPiAgent({ cwd, files, homeDir, prompter, scope }); } } diff --git a/src/commands/code/pi.ts b/src/commands/code/pi.ts index 527b7c5..0797301 100644 --- a/src/commands/code/pi.ts +++ b/src/commands/code/pi.ts @@ -4,10 +4,9 @@ import type { CommandRunner } from './ports/command-runner.js'; import type { FileStore } from './ports/file-store.js'; import type { Prompter } from './ports/prompter.js'; -import { getAllAgents, toPiPrompt } from '../../agents/index.js'; -import { CancelledError, CommandFailedError } from './errors.js'; +import { CommandFailedError } from './errors.js'; import { readJsonMaybe, writeJsonFile } from './utils.js'; -import { getPiAgentDir, getPiSettingsPath } from './xdg-paths.js'; +import { getPiSettingsPath } from './xdg-paths.js'; const PI_PROVIDER = 'npm:@bergetai/pi-provider'; const PI_PROVIDER_NAME = '@bergetai/pi-provider'; @@ -92,75 +91,6 @@ export async function initPi(deps: InitPiDeps): Promise { } } -export async function initPiAgent(deps: { - cwd: string; - files: FileStore; - homeDir: string; - prompter: Prompter; - scope: 'global' | 'project'; -}): Promise { - const { cwd, files, homeDir, prompter, scope } = deps; - - const agents = getAllAgents().filter((a) => a.config.mode === 'primary'); - - if (agents.length === 0) { - return false; - } - - const systemPath = - scope === 'project' - ? path.join(cwd, '.pi', 'SYSTEM.md') - : path.join(getPiAgentDir(homeDir), 'SYSTEM.md'); - - prompter.note('Pi uses a single system prompt.', 'Agent Setup'); - - const shouldInitAgent = await prompter.confirm({ - initialValue: false, - message: 'Set up an agent for Pi?', - }); - - if (!shouldInitAgent) return false; - - const selectedAgentName = await prompter.select({ - message: 'Choose an agent:', - options: agents.map((agent) => ({ - hint: agent.config.description, - label: agent.config.name, - value: agent.config.name, - })), - }); - - const agent = agents.find((a) => a.config.name === selectedAgentName); - if (!agent) return false; - - const systemExists = await files.exists(systemPath); - const confirmMsg = systemExists - ? `SYSTEM.md already exists. Replace with ${agent.config.name}?` - : 'Create agent configuration?'; - - const shouldWrite = await prompter.confirm({ - initialValue: true, - message: confirmMsg, - }); - - if (!shouldWrite) { - throw new CancelledError(); - } - - const s = prompter.spinner(); - s.start('Writing agent configuration...'); - try { - const systemDir = scope === 'project' ? path.join(cwd, '.pi') : getPiAgentDir(homeDir); - await files.mkdir(systemDir); - await files.writeFile(systemPath, toPiPrompt(agent)); - s.stop(`Wrote agent configuration to ${systemPath}`); - } catch (error) { - s.stop('Failed to write agent configuration.'); - throw error; - } - return true; -} - function hasPiProviderInSettings(settings: unknown): boolean { if (!settings || typeof settings !== 'object') return false; const packages = (settings as Record).packages;