feat(FN-2944): merge fusion/fn-2944

- test(FN-2944): cover already checked out worktree conflict recovery
- fix(FN-2944): recognize git already checked out worktree conflict
- fix(engine): auto-recover from squash-merge orphan rebase failures

Fusion-Task-Id: FN-2944
This commit is contained in:
Fusion
2026-04-29 07:10:52 -07:00
committed by gsxdsm
parent 98fb71c202
commit 995165ea60
46 changed files with 454 additions and 163 deletions

View File

@@ -0,0 +1,30 @@
// @vitest-environment node
import { readFileSync } from "node:fs";
import { dirname, join } from "node:path";
import { fileURLToPath } from "node:url";
import { describe, expect, it } from "vitest";
import { getCliPackageVersion, resolveCliPackageVersionInfo } from "../cli-package-version.js";
const __dirname = dirname(fileURLToPath(import.meta.url));
describe("cli-package-version", () => {
it("resolves the published CLI package from dashboard source directories", () => {
const versionInfo = resolveCliPackageVersionInfo(join(__dirname, ".."));
const expectedCliPackageJson = join(__dirname, "..", "..", "..", "cli", "package.json");
const dashboardPackageJson = join(__dirname, "..", "..", "package.json");
expect(versionInfo).toEqual({
packageJsonPath: expectedCliPackageJson,
version: JSON.parse(readFileSync(expectedCliPackageJson, "utf-8")).version,
});
expect(versionInfo?.packageJsonPath).not.toBe(dashboardPackageJson);
});
it("returns the published CLI version for dashboard consumers", () => {
const expectedCliPackageJson = join(__dirname, "..", "..", "..", "cli", "package.json");
const expectedVersion = JSON.parse(readFileSync(expectedCliPackageJson, "utf-8")).version;
expect(getCliPackageVersion()).toBe(expectedVersion);
});
});

View File

@@ -36,8 +36,8 @@ vi.mock("../terminal-service.js", () => {
const { __mockTerminalService: mockTerminalService } = await import("../terminal-service.js") as any;
const __dirname = dirname(fileURLToPath(import.meta.url));
const DASHBOARD_PACKAGE_VERSION = (() => {
const packageJsonPath = join(__dirname, "..", "..", "package.json");
const CLI_PACKAGE_VERSION = (() => {
const packageJsonPath = join(__dirname, "..", "..", "..", "cli", "package.json");
const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8")) as {
version?: unknown;
};
@@ -305,7 +305,7 @@ describe("createServer health and headless mode", () => {
expect(res.status).toBe(200);
expect(res.body).toEqual({
status: "ok",
version: DASHBOARD_PACKAGE_VERSION,
version: CLI_PACKAGE_VERSION,
uptime: expect.any(Number),
});
});
@@ -317,7 +317,7 @@ describe("createServer health and headless mode", () => {
const res = await GET(app, "/api/health");
expect(res.status).toBe(200);
if (DASHBOARD_PACKAGE_VERSION === "0.4.0") {
if (CLI_PACKAGE_VERSION === "0.4.0") {
expect(res.body.version).toBe("0.4.0");
return;
}

View File

@@ -10,3 +10,11 @@ import { join } from "node:path";
const tempHome = mkdtempSync(join(tmpdir(), "fn-test-home-"));
process.env.HOME = tempHome;
process.env.USERPROFILE = tempHome;
if (process.platform === "win32") {
const match = tempHome.match(/^([A-Za-z]:)(.*)$/);
if (match) {
process.env.HOMEDRIVE = match[1];
process.env.HOMEPATH = match[2] || "\\";
}
}

View File

@@ -43,6 +43,36 @@ describe("update-check", () => {
expect(fetchSpy).not.toHaveBeenCalled();
});
it("ignores a fresh cache entry after the installed version changes", async () => {
const cached: UpdateCheckResult = {
currentVersion: "0.8.1",
latestVersion: "0.8.3",
updateAvailable: true,
lastChecked: Date.now(),
};
await writeFile(join(fusionDir, "update-check.json"), JSON.stringify(cached), "utf-8");
const fetchSpy = vi.fn().mockResolvedValue({
json: async () => ({
"dist-tags": {
latest: "0.8.3",
},
}),
});
vi.stubGlobal("fetch", fetchSpy);
const result = await performUpdateCheck(fusionDir, "0.8.3");
expect(fetchSpy).toHaveBeenCalledOnce();
expect(result).toEqual({
currentVersion: "0.8.3",
latestVersion: "0.8.3",
updateAvailable: false,
lastChecked: expect.any(Number),
});
});
it("fetches latest version when cache is expired", async () => {
const stale: UpdateCheckResult = {
currentVersion: "0.6.0",
@@ -198,6 +228,17 @@ describe("update-check", () => {
expect(fetchSpy).not.toHaveBeenCalled();
expect(fromCache).toEqual(cached);
// After an upgrade, ignore stale cached currentVersion instead of
// surfacing an outdated update banner.
const afterUpgrade = await performUpdateCheck(fusionDir, "0.8.3", { frequency: "manual" });
expect(fetchSpy).not.toHaveBeenCalled();
expect(afterUpgrade).toEqual({
currentVersion: "0.8.3",
latestVersion: null,
updateAvailable: false,
lastChecked: expect.any(Number),
});
// force=true (used by /update-check/refresh) overrides manual.
fetchSpy.mockResolvedValueOnce({
json: async () => ({ "dist-tags": { latest: "1.0.0" } }),