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

@@ -8,3 +8,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

@@ -4,7 +4,7 @@ import { createInterface } from "node:readline/promises";
import type { PlanningQuestion, PlanningSummary } from "@fusion/core";
import { createSession, submitResponse, RateLimitError, SessionNotFoundError, InvalidSessionStateError } from "@fusion/dashboard/planning";
import { watchFile, unwatchFile, statSync, existsSync, readFileSync } from "node:fs";
import { join } from "node:path";
import { basename, join } from "node:path";
import { GitHubClient } from "@fusion/dashboard";
import {
getGhErrorMessage,
@@ -30,7 +30,7 @@ function asLocalProjectContext(store: TaskStore): ProjectContext {
return {
projectId: cwd,
projectPath: cwd,
projectName: cwd.split("/").filter(Boolean).at(-1) ?? "current-project",
projectName: basename(cwd) || "current-project",
isRegistered: false,
store,
};

View File

@@ -6,7 +6,7 @@
*/
import { TaskStore, type RegisteredProject, CentralCore, GlobalSettingsStore } from "@fusion/core";
import { resolve, dirname } from "node:path";
import { resolve, dirname, basename } from "node:path";
import { existsSync } from "node:fs";
/** Project context for CLI operations */
@@ -198,7 +198,7 @@ export async function detectProjectFromCwd(
// Use empty string for id to indicate unregistered status.
return {
id: "",
name: currentDir.split("/").filter(Boolean).at(-1) ?? "current-project",
name: basename(currentDir) || "current-project",
path: currentDir,
};
}
@@ -309,4 +309,3 @@ export async function getStore(
const context = await resolveProject(projectName, cwd, globalDir);
return context.store;
}

View File

@@ -9,7 +9,7 @@
*/
import { existsSync, statSync } from "node:fs";
import { dirname, resolve, normalize } from "node:path";
import { basename, dirname, resolve, normalize } from "node:path";
import { createInterface } from "node:readline/promises";
import { CentralCore, type RegisteredProject, type TaskStore } from "@fusion/core";
import { ProjectManager } from "@fusion/engine";
@@ -250,7 +250,7 @@ export async function resolveProject(options: ResolveOptions = {}): Promise<Reso
if (shouldRegister) {
const rl = createInterface({ input: process.stdin, output: process.stdout });
const defaultName = fusionDir.split("/").pop() || "unnamed";
const defaultName = basename(fusionDir) || "unnamed";
const name = await rl.question(` Project name [${defaultName}]: `);
rl.close();