From 1da903983ad72c60995507e813a00bb2bd6faf09 Mon Sep 17 00:00:00 2001 From: Vegard Stikbakke Date: Thu, 11 Jun 2026 21:36:26 +0200 Subject: [PATCH] fix(coding-agent): skip first-time setup for forks (#5627) --- packages/coding-agent/src/cli/startup-ui.ts | 30 +++++++++++++- .../test/first-time-setup-fork.test.ts | 39 +++++++++++++++++++ 2 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 packages/coding-agent/test/first-time-setup-fork.test.ts diff --git a/packages/coding-agent/src/cli/startup-ui.ts b/packages/coding-agent/src/cli/startup-ui.ts index 5a9de2036..ec7aa5e7f 100644 --- a/packages/coding-agent/src/cli/startup-ui.ts +++ b/packages/coding-agent/src/cli/startup-ui.ts @@ -1,6 +1,6 @@ import { ProcessTerminal, setKeybindings, TUI } from "@earendil-works/pi-tui"; import { existsSync } from "fs"; -import { ENV_AGENT_DIR, getSettingsPath } from "../config.ts"; +import { APP_NAME, CONFIG_DIR_NAME, ENV_AGENT_DIR, getSettingsPath, PACKAGE_NAME } from "../config.ts"; import { areExperimentalFeaturesEnabled } from "../core/experimental.ts"; import { KeybindingsManager } from "../core/keybindings.ts"; import type { SettingsManager } from "../core/settings-manager.ts"; @@ -12,6 +12,24 @@ import { } from "../modes/interactive/components/first-time-setup.ts"; import { detectTerminalBackground, initTheme, setTheme } from "../modes/interactive/theme/theme.ts"; +const OFFICIAL_PACKAGE_NAME = "@earendil-works/pi-coding-agent"; +const OFFICIAL_APP_NAME = "pi"; +const OFFICIAL_CONFIG_DIR_NAME = ".pi"; + +interface DistributionMetadata { + packageName: string; + appName: string; + configDirName: string; +} + +function isOfficialDistribution({ packageName, appName, configDirName }: DistributionMetadata): boolean { + return ( + packageName === OFFICIAL_PACKAGE_NAME && + appName === OFFICIAL_APP_NAME && + configDirName === OFFICIAL_CONFIG_DIR_NAME + ); +} + function createStartupTui(settingsManager: SettingsManager): TUI { initTheme(settingsManager.getTheme()); setKeybindings(KeybindingsManager.create()); @@ -28,11 +46,21 @@ async function clearStartupTui(ui: TUI): Promise { /** * First-time setup runs when all of these hold: + * - this is the official Pi distribution (not a fork/rebrand) * - experimental features are enabled (PI_EXPERIMENTAL=1) * - the default agent directory is used (no custom agent dir override) * - setup was not completed before (settings.json does not exist) */ export function shouldRunFirstTimeSetup(settingsPath: string = getSettingsPath()): boolean { + if ( + !isOfficialDistribution({ + packageName: PACKAGE_NAME, + appName: APP_NAME, + configDirName: CONFIG_DIR_NAME, + }) + ) { + return false; + } if (!areExperimentalFeaturesEnabled()) { return false; } diff --git a/packages/coding-agent/test/first-time-setup-fork.test.ts b/packages/coding-agent/test/first-time-setup-fork.test.ts new file mode 100644 index 000000000..e9b892071 --- /dev/null +++ b/packages/coding-agent/test/first-time-setup-fork.test.ts @@ -0,0 +1,39 @@ +import { mkdtempSync, rmSync } from "fs"; +import { tmpdir } from "os"; +import { join } from "path"; +import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; + +vi.mock("../src/config.ts", async (importOriginal) => { + const actual = await importOriginal(); + return { + ...(actual as Record), + PACKAGE_NAME: "@example/pi-coding-agent", + }; +}); + +import { shouldRunFirstTimeSetup } from "../src/cli/startup-ui.ts"; + +describe("shouldRunFirstTimeSetup in forked distributions", () => { + const originalPiExperimental = process.env.PI_EXPERIMENTAL; + let tempDir: string; + let settingsPath: string; + + beforeEach(() => { + tempDir = mkdtempSync(join(tmpdir(), "pi-first-time-setup-fork-")); + settingsPath = join(tempDir, "settings.json"); + process.env.PI_EXPERIMENTAL = "1"; + }); + + afterEach(() => { + rmSync(tempDir, { recursive: true, force: true }); + if (originalPiExperimental === undefined) { + delete process.env.PI_EXPERIMENTAL; + } else { + process.env.PI_EXPERIMENTAL = originalPiExperimental; + } + }); + + it("returns false for a forked package", () => { + expect(shouldRunFirstTimeSetup(settingsPath)).toBe(false); + }); +});