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

This commit is contained in:
gsxdsm
2026-04-19 04:52:39 -07:00
parent 9884f87208
commit 3472c122d4
24 changed files with 224 additions and 105 deletions

View File

@@ -748,7 +748,7 @@ describe("fn pi extension", () => {
makeCtx(tmpDir),
);
const store = new TaskStore(tmpDir);
const store = new TaskStore(tmpDir, join(tmpDir, ".fusion-global-settings"));
await store.init();
const persisted = store.getMissionStore().getMilestone(result.details.milestoneId);
@@ -780,7 +780,7 @@ describe("fn pi extension", () => {
makeCtx(tmpDir),
);
const store = new TaskStore(tmpDir);
const store = new TaskStore(tmpDir, join(tmpDir, ".fusion-global-settings"));
await store.init();
const persisted = store.getMissionStore().getSlice(result.details.sliceId);
@@ -820,7 +820,7 @@ describe("fn pi extension", () => {
makeCtx(tmpDir),
);
const store = new TaskStore(tmpDir);
const store = new TaskStore(tmpDir, join(tmpDir, ".fusion-global-settings"));
await store.init();
const persisted = store.getMissionStore().getFeature(result.details.featureId);
@@ -890,7 +890,7 @@ describe("fn pi extension", () => {
makeCtx(tmpDir),
);
const store = new TaskStore(tmpDir);
const store = new TaskStore(tmpDir, join(tmpDir, ".fusion-global-settings"));
await store.init();
const persisted = store.getMissionStore().getSlice(slice.details.sliceId);
@@ -989,7 +989,7 @@ describe("fn pi extension", () => {
makeCtx(tmpDir),
);
const store = new TaskStore(tmpDir);
const store = new TaskStore(tmpDir, join(tmpDir, ".fusion-global-settings"));
await store.init();
const missionStore = store.getMissionStore();
const persisted = missionStore.getFeature(feature.details.featureId);

View File

@@ -21,14 +21,12 @@ describe("project-context", () => {
let tempDir: string;
let homeDir: string;
let central: CentralCore;
const originalHome = process.env.HOME;
const createdProjectIds: string[] = [];
beforeEach(async () => {
tempDir = mkdtempSync(join(tmpdir(), "kb-test-"));
homeDir = mkdtempSync(join(tmpdir(), "kb-home-"));
process.env.HOME = homeDir;
central = new CentralCore();
central = new CentralCore(homeDir);
await central.init();
});
@@ -59,11 +57,6 @@ describe("project-context", () => {
} catch {
// Ignore cleanup errors
}
if (originalHome === undefined) {
delete process.env.HOME;
} else {
process.env.HOME = originalHome;
}
});
function createMockProject(name: string, parentDir: string = tempDir): string {
@@ -167,7 +160,7 @@ describe("project-context", () => {
describe("resolveProject", () => {
it("should throw for unknown project name", async () => {
await expect(resolveProject("unknown-project", tempDir)).rejects.toThrow(
await expect(resolveProject("unknown-project", tempDir, homeDir)).rejects.toThrow(
"not found"
);
});
@@ -175,7 +168,7 @@ describe("project-context", () => {
it("should resolve unregistered local project from cwd", async () => {
const projectPath = createMockProject("legacy-project");
const context = await resolveProject(undefined, projectPath);
const context = await resolveProject(undefined, projectPath, homeDir);
expect(context.projectPath).toBe(resolve(projectPath));
expect(context.projectName).toBe("legacy-project");
@@ -186,7 +179,7 @@ describe("project-context", () => {
const randomDir = join(tempDir, "no-project-here");
mkdirSync(randomDir, { recursive: true });
await expect(resolveProject(undefined, randomDir)).rejects.toThrow(
await expect(resolveProject(undefined, randomDir, homeDir)).rejects.toThrow(
"No fusion project found"
);
});

View File

@@ -41,9 +41,10 @@ const storeCache = new Map<string, TaskStore>();
*/
export async function resolveProject(
projectNameFlag?: string,
cwd: string = process.cwd()
cwd: string = process.cwd(),
globalDir?: string,
): Promise<ProjectContext> {
const central = new CentralCore();
const central = new CentralCore(globalDir);
await central.init();
try {
@@ -61,12 +62,12 @@ export async function resolveProject(
// 2. Default project from global settings
if (!project) {
const defaultProject = await getDefaultProject();
const defaultProject = await getDefaultProject(globalDir);
if (defaultProject) {
project = await central.getProject(defaultProject.id);
// If default project was deleted from registry, clear it
if (!project) {
await clearDefaultProject();
await clearDefaultProject(globalDir);
}
}
}
@@ -82,8 +83,8 @@ export async function resolveProject(
const isRegistered = Boolean(detected.id);
const store = isRegistered
? await getStoreForProject(detected.id, detected.path)
: await createLocalStore(detected.path);
? await getStoreForProject(detected.id, detected.path, globalDir)
: await createLocalStore(detected.path, globalDir);
// For unregistered projects, use the path as the project ID
const projectId = isRegistered ? detected.id : detected.path;
@@ -97,7 +98,7 @@ export async function resolveProject(
};
}
const store = await getStoreForProject(project.id, project.path);
const store = await getStoreForProject(project.id, project.path, globalDir);
return {
projectId: project.id,
@@ -115,8 +116,8 @@ export async function resolveProject(
* Get the default project from global settings.
* Returns undefined if no default is set or if the project no longer exists.
*/
export async function getDefaultProject(): Promise<RegisteredProject | undefined> {
const globalStore = new GlobalSettingsStore();
export async function getDefaultProject(globalDir?: string): Promise<RegisteredProject | undefined> {
const globalStore = new GlobalSettingsStore(globalDir);
await globalStore.init();
const settings = await globalStore.getSettings();
@@ -124,7 +125,7 @@ export async function getDefaultProject(): Promise<RegisteredProject | undefined
return undefined;
}
const central = new CentralCore();
const central = new CentralCore(globalDir);
await central.init();
try {
return await central.getProject(settings.defaultProjectId);
@@ -138,9 +139,9 @@ export async function getDefaultProject(): Promise<RegisteredProject | undefined
* @param projectId - Project ID to set as default
* @throws Error if project not found
*/
export async function setDefaultProject(projectId: string): Promise<void> {
export async function setDefaultProject(projectId: string, globalDir?: string): Promise<void> {
// Verify project exists
const central = new CentralCore();
const central = new CentralCore(globalDir);
await central.init();
try {
const project = await central.getProject(projectId);
@@ -151,7 +152,7 @@ export async function setDefaultProject(projectId: string): Promise<void> {
await central.close();
}
const globalStore = new GlobalSettingsStore();
const globalStore = new GlobalSettingsStore(globalDir);
await globalStore.init();
await globalStore.updateSettings({ defaultProjectId: projectId });
}
@@ -159,8 +160,8 @@ export async function setDefaultProject(projectId: string): Promise<void> {
/**
* Clear the default project setting.
*/
export async function clearDefaultProject(): Promise<void> {
const globalStore = new GlobalSettingsStore();
export async function clearDefaultProject(globalDir?: string): Promise<void> {
const globalStore = new GlobalSettingsStore(globalDir);
await globalStore.init();
const current = await globalStore.getSettings();
@@ -243,7 +244,8 @@ async function findProjectByNameOrId(
*/
export async function getStoreForProject(
projectId: string,
projectPath: string
projectPath: string,
globalSettingsDir?: string,
): Promise<TaskStore> {
// Check cache first
const cached = storeCache.get(projectId);
@@ -252,7 +254,7 @@ export async function getStoreForProject(
}
// Create new store
const store = new TaskStore(projectPath);
const store = new TaskStore(projectPath, globalSettingsDir);
await store.init();
// Cache it
@@ -267,8 +269,11 @@ export function clearStoreCache(): void {
storeCache.clear();
}
async function createLocalStore(projectPath: string): Promise<TaskStore> {
const store = new TaskStore(projectPath);
async function createLocalStore(
projectPath: string,
globalSettingsDir?: string,
): Promise<TaskStore> {
const store = new TaskStore(projectPath, globalSettingsDir);
await store.init();
return store;
}
@@ -298,9 +303,10 @@ export function formatProjectLine(project: RegisteredProject, isDefault: boolean
*/
export async function getStore(
projectName?: string,
cwd: string = process.cwd()
cwd: string = process.cwd(),
globalDir?: string,
): Promise<TaskStore> {
const context = await resolveProject(projectName, cwd);
const context = await resolveProject(projectName, cwd, globalDir);
return context.store;
}