fix(FN-1952): merge pi package settings

This commit is contained in:
gsxdsm
2026-04-17 00:20:19 -07:00
parent 7807b50bdd
commit d51992850f
7 changed files with 163 additions and 22 deletions

View File

@@ -0,0 +1,45 @@
import { mkdirSync, mkdtempSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { describe, expect, it } from "vitest";
import { getFusionAgentDir, getLegacyAgentDir, getPackageManagerAgentDir } from "./auth-paths.js";
function writeJson(path: string, value: Record<string, unknown>): void {
writeFileSync(path, JSON.stringify(value, null, 2));
}
describe("getPackageManagerAgentDir", () => {
it("falls back to legacy Pi settings when Fusion settings only contain Fusion metadata", () => {
const home = mkdtempSync(join(tmpdir(), "fusion-agent-dir-"));
const fusionAgentDir = getFusionAgentDir(home);
const legacyAgentDir = getLegacyAgentDir(home);
mkdirSync(fusionAgentDir, { recursive: true });
mkdirSync(legacyAgentDir, { recursive: true });
writeJson(join(fusionAgentDir, "settings.json"), {
fusionDisabledExtensions: ["/Users/example/.pi/agent/extensions/browse.ts"],
});
writeJson(join(legacyAgentDir, "settings.json"), {
packages: ["npm:pi-claude-cli"],
});
expect(getPackageManagerAgentDir(home)).toBe(legacyAgentDir);
});
it("prefers Fusion settings when they contain package-manager settings", () => {
const home = mkdtempSync(join(tmpdir(), "fusion-agent-dir-"));
const fusionAgentDir = getFusionAgentDir(home);
const legacyAgentDir = getLegacyAgentDir(home);
mkdirSync(fusionAgentDir, { recursive: true });
mkdirSync(legacyAgentDir, { recursive: true });
writeJson(join(fusionAgentDir, "settings.json"), {
packages: ["npm:pi-claude-cli"],
});
writeJson(join(legacyAgentDir, "settings.json"), {
packages: ["npm:legacy-only"],
});
expect(getPackageManagerAgentDir(home)).toBe(fusionAgentDir);
});
});

View File

@@ -1,5 +1,5 @@
import { homedir } from "node:os";
import { existsSync } from "node:fs";
import { existsSync, readFileSync } from "node:fs";
import { join } from "node:path";
export function getFusionAgentDir(home = process.env.HOME || process.env.USERPROFILE || homedir()): string {
@@ -41,15 +41,34 @@ export function getModelRegistryModelsPath(home = process.env.HOME || process.en
return getLegacyModelsPaths(home).find((modelsPath) => existsSync(modelsPath)) ?? fusionModelsPath;
}
export function getPackageManagerAgentDir(home = process.env.HOME || process.env.USERPROFILE || homedir()): string {
const fusionAgentDir = getFusionAgentDir(home);
if (
existsSync(join(fusionAgentDir, "settings.json")) ||
existsSync(join(fusionAgentDir, "extensions"))
) {
return fusionAgentDir;
function readJsonObject(path: string): Record<string, unknown> {
if (!existsSync(path)) {
return {};
}
const legacyAgentDir = getLegacyAgentDir(home);
return existsSync(legacyAgentDir) ? legacyAgentDir : fusionAgentDir;
try {
const parsed = JSON.parse(readFileSync(path, "utf-8"));
return parsed && typeof parsed === "object" ? parsed as Record<string, unknown> : {};
} catch {
return {};
}
}
function hasPackageManagerSettings(settings: Record<string, unknown>): boolean {
return Array.isArray(settings.packages) || Array.isArray(settings.npmCommand);
}
export function getPackageManagerAgentDir(home = process.env.HOME || process.env.USERPROFILE || homedir()): string {
const fusionAgentDir = getFusionAgentDir(home);
const legacyAgentDir = getLegacyAgentDir(home);
const fusionSettings = readJsonObject(join(fusionAgentDir, "settings.json"));
const legacySettings = readJsonObject(join(legacyAgentDir, "settings.json"));
if (hasPackageManagerSettings(fusionSettings) || !existsSync(legacyAgentDir)) {
return fusionAgentDir;
}
if (hasPackageManagerSettings(legacySettings)) {
return legacyAgentDir;
}
return existsSync(fusionAgentDir) ? fusionAgentDir : legacyAgentDir;
}

View File

@@ -55,6 +55,38 @@ describe("createReadOnlyProviderSettingsView", () => {
expect(view.getProjectSettings()).toEqual({});
expect(view.getNpmCommand()).toEqual(["pnpm"]);
});
it("merges legacy Pi and Fusion agent settings with Fusion taking precedence", () => {
const home = mkdtempSync(join(tmpdir(), "fusion-provider-settings-"));
const cwd = join(home, "project");
const fusionAgentDir = join(home, ".fusion", "agent");
const legacyAgentDir = join(home, ".pi", "agent");
mkdirSync(join(cwd, ".fusion"), { recursive: true });
mkdirSync(fusionAgentDir, { recursive: true });
mkdirSync(legacyAgentDir, { recursive: true });
writeJson(join(legacyAgentDir, "settings.json"), {
packages: ["npm:pi-claude-cli"],
npmCommand: ["npm"],
shared: "legacy",
});
writeJson(join(fusionAgentDir, "settings.json"), {
fusionDisabledExtensions: ["/tmp/disabled.ts"],
npmCommand: ["pnpm"],
shared: "fusion",
});
const view = createReadOnlyProviderSettingsView(cwd, fusionAgentDir);
expect(view.getGlobalSettings()).toMatchObject({
packages: ["npm:pi-claude-cli"],
fusionDisabledExtensions: ["/tmp/disabled.ts"],
npmCommand: ["pnpm"],
shared: "fusion",
});
expect(view.getNpmCommand()).toEqual(["pnpm"]);
});
});
describe("createProjectSettingsPersistence", () => {

View File

@@ -1,5 +1,5 @@
import { existsSync, readFileSync, writeFileSync, mkdirSync } from "node:fs";
import { join, dirname } from "node:path";
import { join, dirname, basename } from "node:path";
export interface PackageManagerSettingsView {
getGlobalSettings(): Record<string, any>;
@@ -7,6 +7,13 @@ export interface PackageManagerSettingsView {
getNpmCommand(): string[] | undefined;
}
function siblingAgentDir(agentDir: string, siblingRoot: ".fusion" | ".pi"): string | undefined {
if (basename(agentDir) !== "agent") {
return undefined;
}
return join(dirname(dirname(agentDir)), siblingRoot, "agent");
}
function readJsonObject(path: string): Record<string, any> {
if (!existsSync(path)) {
return {};
@@ -21,7 +28,16 @@ function readJsonObject(path: string): Record<string, any> {
}
export function createReadOnlyProviderSettingsView(cwd: string, agentDir: string): PackageManagerSettingsView {
const globalSettings = readJsonObject(join(agentDir, "settings.json"));
const fusionAgentDir = agentDir.includes(`${join(".fusion", "agent")}`)
? agentDir
: siblingAgentDir(agentDir, ".fusion");
const legacyAgentDir = agentDir.includes(`${join(".pi", "agent")}`)
? agentDir
: siblingAgentDir(agentDir, ".pi");
const legacyGlobalSettings = legacyAgentDir ? readJsonObject(join(legacyAgentDir, "settings.json")) : {};
const fusionGlobalSettings = fusionAgentDir ? readJsonObject(join(fusionAgentDir, "settings.json")) : {};
const directGlobalSettings = readJsonObject(join(agentDir, "settings.json"));
const globalSettings = { ...legacyGlobalSettings, ...directGlobalSettings, ...fusionGlobalSettings };
const fusionProjectSettings = readJsonObject(join(cwd, ".fusion", "settings.json"));
const mergedSettings = { ...globalSettings, ...fusionProjectSettings };