fix(core): prevent FirstRunDetector from walking into OS temp directory

`FirstRunDetector.detectExistingProjects()` walks ancestor directories
looking for `.fusion/` projects, stopping only at `homedir()` and the
filesystem root. On systems where a prior Fusion session has left a
`/tmp/.fusion/fusion.db` (e.g. running tests, ephemeral dashboards,
crashed processes), the walk crosses into `/tmp` and incorrectly
"discovers" that stale state as a project.

This was caught by tests in packages/core/src/__tests__/store.test.ts
that intermittently failed when a real Fusion session had been run
on the same box. The walk would find the test's tmp dir AND the host's
real `/tmp/.fusion/fusion.db`, polluting the project-detection invariants.

Fix: import `tmpdir` from `node:os` and add it as a third walk-stop
boundary alongside `homedir()` and `/`. The OS temp directory is a
shared system surface and should never itself host a project.

The bug affected any user with a stale `/tmp/.fusion/` from a previous
session — invisible most of the time, but caused FirstRunDetector to
misclassify project state.

Tested: 4 previously-flaky tests in packages/core now pass deterministically.
This commit is contained in:
Vhailors
2026-04-27 11:34:02 +07:00
committed by gsxdsm
parent 9514d12ef2
commit 3796ba087c

View File

@@ -11,7 +11,7 @@
*/
import { existsSync, statSync } from "node:fs";
import { homedir } from "node:os";
import { homedir, tmpdir } from "node:os";
import { isAbsolute, join, resolve, basename, dirname } from "node:path";
import type { CentralCore } from "./central-core.js";
import { CentralCore as CentralCoreClass } from "./central-core.js";
@@ -194,8 +194,12 @@ export class FirstRunDetector {
let current = resolve(startDir);
const home = homedir();
const root = dirname(current) === current ? current : "/"; // Handle Windows vs Unix root
// Also stop at the OS temp directory — it is a shared system boundary and
// should never itself host a project; stopping here prevents the walk from
// picking up stale .fusion/ directories left by other processes in /tmp.
const systemTmp = resolve(tmpdir());
while (current !== home && current !== root) {
while (current !== home && current !== root && current !== systemTmp) {
if (visited.has(current)) break;
visited.add(current);