feat(FN-3335): fix worktree project root resolution in createFnAgent and ad

Merges FN-3335 (worktree project resolution) and FN-3333 (spurious version reloads). The engine's `createFnAgent` now resolves project root from the worktree's cwd rather than the parent process, with `resolveProjectRoot` added to skill-resolver for consistency. The dashboard's `versionCheck` was up

Fusion-Task-Id: FN-3335
This commit is contained in:
Fusion
2026-05-03 16:01:17 -07:00
committed by gsxdsm
parent 53ab441a97
commit d7e2a3ec42
6 changed files with 195 additions and 9 deletions

View File

@@ -10,10 +10,35 @@
*/
import { existsSync, readFileSync } from "node:fs";
import { join } from "node:path";
import { dirname, join, resolve } from "node:path";
import type { ResourceDiagnostic, Skill } from "@mariozechner/pi-coding-agent";
import { piLog } from "./logger.js";
// ── Project Root Resolution ──────────────────────────────────────────────────
/**
* Resolve the project root directory by walking up from `cwd` looking for
* a directory containing `.fusion/`. This handles worktree paths (e.g.,
* `/project/.worktrees/task-branch`) and any other subdirectory by walking
* up to the actual project root.
*
* Falls back to `cwd` if no `.fusion/` directory is found (mirrors
* `resolvePiExtensionProjectRoot` from `@fusion/core`).
*/
export function resolveProjectRoot(cwd: string): string {
let current = resolve(cwd);
while (true) {
if (existsSync(join(current, ".fusion"))) {
return current;
}
const parent = dirname(current);
if (parent === current) {
return resolve(cwd);
}
current = parent;
}
}
// ── Types ───────────────────────────────────────────────────────────────────
/**
@@ -161,7 +186,12 @@ function isExclusionPattern(pattern: string): boolean {
* - Requested names not matching any discovered skill (warning)
*/
export function resolveSessionSkills(context: SkillSelectionContext): SkillSelectionResult {
const { projectRootDir, requestedSkillNames } = context;
const { requestedSkillNames } = context;
// Resolve project root from the given projectRootDir — it may be a
// worktree path (e.g., /project/.worktrees/task-branch) which doesn't
// contain .fusion/settings.json. Walk up to find the real project root.
const projectRootDir = resolveProjectRoot(context.projectRootDir);
// Read project settings
const settings = readProjectSettings(projectRootDir);