feat(FN-2615): merge fusion/fn-2615 (auto-resolved)

- fix(FN-2615): restore workspace lint and test stability
This commit is contained in:
Fusion
2026-04-26 15:16:22 -07:00
committed by gsxdsm
parent 01ff37632c
commit 112813f122
10 changed files with 46 additions and 37 deletions

View File

@@ -803,8 +803,10 @@ describe("MailboxModal", () => {
}); });
// Inbox tab should have the unread badge // Inbox tab should have the unread badge
const inboxTab = screen.getByTestId("mailbox-agent-subtab-inbox"); await waitFor(() => {
expect(inboxTab.querySelector(".mailbox-tab-badge")?.textContent).toBe("3"); const inboxTab = screen.getByTestId("mailbox-agent-subtab-inbox");
expect(inboxTab.querySelector(".mailbox-tab-badge")?.textContent).toBe("3");
});
}); });
}); });

View File

@@ -1074,7 +1074,7 @@ describe("TaskForm workflow step reordering (FN-836)", () => {
expect(onWorkflowStepsChange).toHaveBeenCalledWith(["WS-001", "WS-002", "WS-003"]); expect(onWorkflowStepsChange).toHaveBeenCalledWith(["WS-001", "WS-002", "WS-003"]);
}); });
it("preserves order when removing a step via checkbox (not reorder remove)", async () => { it("preserves order when removing a step via remove action (not reorder remove)", async () => {
const { fetchWorkflowSteps } = await import("../../api"); const { fetchWorkflowSteps } = await import("../../api");
vi.mocked(fetchWorkflowSteps).mockResolvedValueOnce([ vi.mocked(fetchWorkflowSteps).mockResolvedValueOnce([
{ id: "WS-001", name: "QA Check", description: "Run tests", prompt: "Check tests", enabled: true, createdAt: "", updatedAt: "" }, { id: "WS-001", name: "QA Check", description: "Run tests", prompt: "Check tests", enabled: true, createdAt: "", updatedAt: "" },
@@ -1089,9 +1089,8 @@ describe("TaskForm workflow step reordering (FN-836)", () => {
expect(screen.getByTestId("workflow-step-order")).toBeTruthy(); expect(screen.getByTestId("workflow-step-order")).toBeTruthy();
}); });
// Uncheck WS-002 via checkbox // Remove WS-002 via explicit remove action
const checkbox = screen.getByTestId("workflow-step-checkbox-WS-002").querySelector('input[type="checkbox"]') as HTMLInputElement; fireEvent.click(screen.getByTestId("workflow-step-remove-WS-002"));
fireEvent.click(checkbox);
expect(onWorkflowStepsChange).toHaveBeenCalledWith(["WS-001", "WS-003"]); expect(onWorkflowStepsChange).toHaveBeenCalledWith(["WS-001", "WS-003"]);
}); });

View File

@@ -43,7 +43,7 @@ const promptCatalogReadyPromise = initPromptCatalog();
import { createFnAgent as engineCreateFnAgent } from "@fusion/engine"; import { createFnAgent as engineCreateFnAgent } from "@fusion/engine";
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
let createFnAgent: any = engineCreateFnAgent; const createFnAgent: any = engineCreateFnAgent;
function ensureEngineReady(): Promise<void> { function ensureEngineReady(): Promise<void> {
return Promise.resolve(); return Promise.resolve();

View File

@@ -17,7 +17,7 @@ import { resolvePrompt } from "@fusion/core";
import { createFnAgent as engineCreateFnAgent } from "@fusion/engine"; import { createFnAgent as engineCreateFnAgent } from "@fusion/engine";
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
let createFnAgent: any = engineCreateFnAgent; const createFnAgent: any = engineCreateFnAgent;
function ensureEngineReady(): Promise<void> { function ensureEngineReady(): Promise<void> {
return Promise.resolve(); return Promise.resolve();

View File

@@ -25,17 +25,14 @@ import { EventEmitter } from "node:events";
import { join, resolve, relative } from "node:path"; import { join, resolve, relative } from "node:path";
import { SessionEventBuffer } from "./sse-buffer.js"; import { SessionEventBuffer } from "./sse-buffer.js";
import { import * as engine from "@fusion/engine";
createFnAgent as engineCreateFnAgent,
buildAgentChatPrompt as engineBuildAgentChatPrompt,
} from "@fusion/engine";
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
type AgentResult = any; type AgentResult = any;
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
let createFnAgent: any = engineCreateFnAgent; let createFnAgent: any = engine.createFnAgent;
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
let buildAgentChatPromptFn: any = engineBuildAgentChatPrompt; let buildAgentChatPromptFn: any = "buildAgentChatPrompt" in engine ? engine.buildAgentChatPrompt : undefined;
/** /**
* Diagnostics logger for the chat module. * Diagnostics logger for the chat module.
@@ -889,7 +886,7 @@ export function __setBuildAgentChatPrompt(mock: typeof buildAgentChatPromptFn):
export function __resetChatState(): void { export function __resetChatState(): void {
chatStreamManager.reset(); chatStreamManager.reset();
rateLimits.clear(); rateLimits.clear();
buildAgentChatPromptFn = engineBuildAgentChatPrompt; buildAgentChatPromptFn = "buildAgentChatPrompt" in engine ? engine.buildAgentChatPrompt : undefined;
// Reset diagnostics logger to default // Reset diagnostics logger to default
__setChatDiagnostics(null); __setChatDiagnostics(null);

View File

@@ -99,7 +99,7 @@ import { createFnAgent as engineCreateFnAgent } from "@fusion/engine";
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
type AgentResult = any; type AgentResult = any;
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
let createFnAgent: any = engineCreateFnAgent; const createFnAgent: any = engineCreateFnAgent;
function ensureEngineReady(): Promise<void> { function ensureEngineReady(): Promise<void> {
return Promise.resolve(); return Promise.resolve();

View File

@@ -32,7 +32,7 @@ import { createFnAgent as engineCreateFnAgent } from "@fusion/engine";
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
type AgentResult = any; type AgentResult = any;
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
let createFnAgent: any = engineCreateFnAgent; const createFnAgent: any = engineCreateFnAgent;
/** /**
* Shared diagnostics helper for the mission-interview module. * Shared diagnostics helper for the mission-interview module.

View File

@@ -30,17 +30,12 @@ import {
resetDiagnosticsSink, resetDiagnosticsSink,
nonfatal, nonfatal,
} from "./ai-session-diagnostics.js"; } from "./ai-session-diagnostics.js";
import { import * as engine from "@fusion/engine";
createFnAgent as engineCreateFnAgent,
isNtfyEventEnabled as engineIsNtfyEventEnabled,
buildNtfyClickUrl as engineBuildNtfyClickUrl,
sendNtfyNotification as engineSendNtfyNotification,
} from "@fusion/engine";
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
type AgentResult = any; type AgentResult = any;
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
let createFnAgent: any = engineCreateFnAgent; let createFnAgent: any = engine.createFnAgent;
interface PlanningNtfyConfig { interface PlanningNtfyConfig {
enabled: boolean; enabled: boolean;
@@ -63,11 +58,29 @@ interface PlanningNtfyHelpers {
}) => Promise<void>; }) => Promise<void>;
} }
let planningNtfyHelpers: PlanningNtfyHelpers | undefined = { function buildDefaultPlanningNtfyHelpers(): PlanningNtfyHelpers {
isNtfyEventEnabled: engineIsNtfyEventEnabled, const isNtfyEventEnabled =
buildNtfyClickUrl: engineBuildNtfyClickUrl, "isNtfyEventEnabled" in engine
sendNtfyNotification: engineSendNtfyNotification, ? engine.isNtfyEventEnabled
}; : (events: NtfyNotificationEvent[] | undefined, event: NtfyNotificationEvent) =>
Array.isArray(events) ? events.includes(event) : false;
const buildNtfyClickUrl = "buildNtfyClickUrl" in engine
? engine.buildNtfyClickUrl
: () => undefined;
const sendNtfyNotification = "sendNtfyNotification" in engine
? engine.sendNtfyNotification
: async () => {};
return {
isNtfyEventEnabled,
buildNtfyClickUrl,
sendNtfyNotification,
};
}
let planningNtfyHelpers: PlanningNtfyHelpers | undefined = buildDefaultPlanningNtfyHelpers();
/** /**
* Shared diagnostics helper for the planning module. * Shared diagnostics helper for the planning module.
@@ -1693,11 +1706,7 @@ export function __resetPlanningState(): void {
_aiSessionDeletedListener = undefined; _aiSessionDeletedListener = undefined;
_aiSessionStore = undefined; _aiSessionStore = undefined;
planningNtfyHelpers = { planningNtfyHelpers = buildDefaultPlanningNtfyHelpers();
isNtfyEventEnabled: engineIsNtfyEventEnabled,
buildNtfyClickUrl: engineBuildNtfyClickUrl,
sendNtfyNotification: engineSendNtfyNotification,
};
// Reset diagnostics sink to default // Reset diagnostics sink to default
resetDiagnosticsSink(); resetDiagnosticsSink();

View File

@@ -12,7 +12,7 @@ import {
import { createFnAgent as engineCreateFnAgent } from "@fusion/engine"; import { createFnAgent as engineCreateFnAgent } from "@fusion/engine";
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
let createFnAgent: any = engineCreateFnAgent; const createFnAgent: any = engineCreateFnAgent;
/** /**
* Shared diagnostics helper for the subtask-breakdown module. * Shared diagnostics helper for the subtask-breakdown module.

View File

@@ -22,9 +22,11 @@ export { createFnAgent, promptWithFallback, describeModel, setHostExtensionPaths
// Register createFnAgent into core's loader so consumers in @fusion/core // Register createFnAgent into core's loader so consumers in @fusion/core
// (e.g. ai-summarize, memory-compaction) can resolve it without a circular // (e.g. ai-summarize, memory-compaction) can resolve it without a circular
// static import. Runs once at engine module load. // static import. Runs once at engine module load.
import { setCreateFnAgent } from "@fusion/core"; import * as core from "@fusion/core";
import { createFnAgent as _createFnAgentForCore } from "./pi.js"; import { createFnAgent as _createFnAgentForCore } from "./pi.js";
setCreateFnAgent(_createFnAgentForCore); if ("setCreateFnAgent" in core) {
core.setCreateFnAgent?.(_createFnAgentForCore);
}
export { export {
resolveSessionSkills, resolveSessionSkills,
createSkillsOverrideFromSelection, createSkillsOverrideFromSelection,