feat(FN-3180): add dreams notification event and harden plugin setup sync

This merge lands four features: a new "dreams" notification event exposed through settings and docs (FN-3180), hardened plugin setup sync with test isolation improvements (FN-3573), and feedback-driven enhancements to the native shell connection manager (FN-3402). Core settings schema, the plugin AP

Fusion-Task-Id: FN-3180
This commit is contained in:
Fusion
2026-05-06 14:36:50 -07:00
committed by gsxdsm
parent ea485b28bb
commit f22db4d1fe
9 changed files with 20 additions and 8 deletions

View File

@@ -243,6 +243,7 @@ const DEFAULT_NTFY_EVENTS: NtfyNotificationEvent[] = [
"planning-awaiting-input",
"gridlock",
"fallback-used",
"memory-dreams-processed",
];
const NOTIFICATION_EVENT_OPTIONS: Array<{ event: NtfyNotificationEvent; label: string; description: string }> = [
@@ -254,6 +255,7 @@ const NOTIFICATION_EVENT_OPTIONS: Array<{ event: NtfyNotificationEvent; label: s
{ event: "planning-awaiting-input", label: "Planning needs input", description: "When planning mode is waiting for your response to continue" },
{ event: "gridlock", label: "Pipeline gridlocked", description: "When all schedulable todo tasks are blocked and work cannot advance" },
{ event: "fallback-used", label: "Fallback model used (recovered)", description: "When Fusion recovers from a retryable model failure by switching to a fallback model" },
{ event: "memory-dreams-processed", label: "DREAMS.md entry added", description: "When manual dream processing writes a new entry to project or agent DREAMS.md" },
];
/** Well-known experimental feature flags with display labels.

View File

@@ -2578,16 +2578,18 @@ describe("SettingsModal", () => {
expect(screen.getByRole("button", { name: /Test notification/ })).toBeInTheDocument();
});
it("shows fallback-used event option for both providers", async () => {
it("shows fallback-used and dreams events for both providers", async () => {
mockFetchSettings.mockResolvedValueOnce({ ...defaultSettings, ntfyEnabled: true, ntfyTopic: "test-topic" });
renderModal();
await waitForSettingsModalReady();
await openNotificationsSection();
expect(screen.getByLabelText("Fallback model used (recovered)")).toBeInTheDocument();
expect(screen.getByLabelText("DREAMS.md entry added")).toBeInTheDocument();
await userEvent.click(screen.getByLabelText("Webhook notifications"));
expect(screen.getAllByLabelText("Fallback model used (recovered)").length).toBeGreaterThan(0);
expect(screen.getAllByLabelText("DREAMS.md entry added").length).toBeGreaterThan(0);
});
it("shows webhook fields when webhook provider is enabled", async () => {
@@ -2668,10 +2670,12 @@ describe("SettingsModal", () => {
const failed = screen.getByLabelText("Task failed") as HTMLInputElement;
const merged = screen.getByLabelText("Task merged") as HTMLInputElement;
const fallbackUsed = screen.getByLabelText("Fallback model used (recovered)") as HTMLInputElement;
const dreamsProcessed = screen.getByLabelText("DREAMS.md entry added") as HTMLInputElement;
expect(inReview.checked).toBe(true);
expect(failed.checked).toBe(true);
expect(merged.checked).toBe(false);
expect(fallbackUsed.checked).toBe(false);
expect(dreamsProcessed.checked).toBe(false);
});
});

View File

@@ -28,7 +28,7 @@ const defaultSettings = {
defaultPresetBySize: {},
ntfyEnabled: false,
ntfyTopic: undefined,
ntfyEvents: ["in-review", "merged", "failed", "awaiting-approval", "awaiting-user-review", "fallback-used"],
ntfyEvents: ["in-review", "merged", "failed", "awaiting-approval", "awaiting-user-review", "fallback-used", "memory-dreams-processed"],
webhookEnabled: false,
webhookUrl: undefined,
webhookFormat: undefined,