feat(FN-3778): add reports plugin scaffold with notification service improv

The merge introduces a new `fusion-plugin-reports` plugin scaffold with settings schema, manifest, entry point, and tests, alongside a mobile session switcher in the chat header. It also adds a mailbox notifications system with ntfy/webhook providers, cleans up roadmap types from core, and includes

Fusion-Task-Id: FN-3778
This commit is contained in:
Fusion
2026-05-08 22:56:27 -07:00
committed by gsxdsm
parent d6edc2d7d8
commit d71c9102f7
14 changed files with 472 additions and 2 deletions

View File

@@ -0,0 +1,5 @@
# Reports Plugin for Fusion
Generates HTML system activity reports with multi-agent review.
> Scaffold-only package delivered in FN-3778. Runtime scheduling, report generation, review orchestration, publishing, and dashboard view behavior are implemented in follow-up tasks FN-3779 through FN-3787.

View File

@@ -0,0 +1,33 @@
{
"id": "fusion-plugin-reports",
"name": "Reports",
"version": "0.1.0",
"description": "Generates beautiful HTML system-activity reports with multi-agent review.",
"author": "Fusion Team",
"fusionVersion": ">=0.1.0",
"settingsSchema": {
"dailyEnabled": { "type": "boolean", "label": "Enable Daily Reports", "description": "Generate daily reports on schedule.", "group": "Schedules", "defaultValue": true },
"dailyCron": { "type": "string", "label": "Daily Schedule (cron)", "description": "Cron expression for daily report generation.", "group": "Schedules", "required": true, "defaultValue": "0 8 * * *" },
"weeklyEnabled": { "type": "boolean", "label": "Enable Weekly Reports", "description": "Generate weekly reports on schedule.", "group": "Schedules", "defaultValue": true },
"weeklyCron": { "type": "string", "label": "Weekly Schedule (cron)", "description": "Cron expression for weekly report generation.", "group": "Schedules", "required": true, "defaultValue": "0 8 * * 1" },
"timezone": { "type": "string", "label": "Timezone", "description": "IANA timezone used for schedule evaluation.", "group": "Schedules", "required": true, "defaultValue": "UTC" },
"generationPromptDaily": { "type": "string", "multiline": true, "label": "Daily Generation Prompt", "description": "Prompt template used to generate daily reports.", "group": "Prompts", "required": true, "defaultValue": "Summarize today's system activity with clear wins, highlights, lowlights, and proposals." },
"generationPromptWeekly": { "type": "string", "multiline": true, "label": "Weekly Generation Prompt", "description": "Prompt template used to generate weekly reports.", "group": "Prompts", "required": true, "defaultValue": "Summarize this week's system activity trends, major outcomes, and actionable proposals." },
"reviewPrompt": { "type": "string", "multiline": true, "label": "Review Prompt", "description": "Prompt template used by reviewer agents.", "group": "Prompts", "required": true, "defaultValue": "Review this report for factual accuracy, clarity, and actionability. Provide concrete revision suggestions." },
"reviewPanelAgentIds": { "type": "array", "itemType": "string", "label": "Reviewer Agent IDs", "description": "Agent IDs allowed to review generated reports.", "group": "Review Panel", "defaultValue": [] },
"reviewMinApprovals": { "type": "number", "label": "Minimum Approvals", "description": "How many approvals are required from the review panel.", "group": "Review Panel", "defaultValue": 1 },
"reviewBlockingMode": { "type": "enum", "enumValues": ["block", "advisory"], "label": "Review Blocking Mode", "description": "Choose whether failed review blocks publication.", "group": "Review Panel", "defaultValue": "advisory" },
"sectionOrder": { "type": "array", "itemType": "string", "label": "Section Order", "description": "Ordered section IDs for report rendering.", "group": "Sections", "defaultValue": ["wins", "highlights", "lowlights", "proposals", "deep-dives", "per-agent"] },
"enabledSections": { "type": "array", "itemType": "string", "label": "Enabled Sections", "description": "Section IDs enabled for output.", "group": "Sections", "defaultValue": ["wins", "highlights", "lowlights", "proposals", "deep-dives", "per-agent"] },
"includeSystemSummary": { "type": "boolean", "label": "Include System Summary", "description": "Include top-level system summary in report output.", "group": "Sections", "defaultValue": true },
"includePerAgentSections": { "type": "boolean", "label": "Include Per-Agent Sections", "description": "Include per-agent detail sections.", "group": "Sections", "defaultValue": true },
"brandTitle": { "type": "string", "label": "Report Title", "description": "Primary report title for branding.", "group": "Branding", "required": true, "defaultValue": "Fusion Activity Report" },
"brandLogoUrl": { "type": "string", "label": "Logo URL", "description": "Optional URL to a brand logo image.", "group": "Branding" },
"themeMode": { "type": "enum", "enumValues": ["light", "dark", "auto"], "label": "Theme Mode", "description": "Theme style for generated reports.", "group": "Branding", "defaultValue": "auto" },
"accentColor": { "type": "string", "label": "Accent Color", "description": "Accent color used in report styling.", "group": "Branding", "defaultValue": "#5B8DEF" },
"approvalRequired": { "type": "boolean", "label": "Require Approval", "description": "Require explicit approval before publishing.", "group": "Approval Flow", "defaultValue": false },
"autoPublishOnApproval": { "type": "boolean", "label": "Auto Publish on Approval", "description": "Publish automatically after approval threshold is met.", "group": "Approval Flow", "defaultValue": true },
"approverAgentIds": { "type": "array", "itemType": "string", "label": "Approver Agent IDs", "description": "Agent IDs permitted to approve final publish.", "group": "Approval Flow", "defaultValue": [] },
"publishTargets": { "type": "array", "itemType": "string", "label": "Publish Targets", "description": "Destinations to publish reports to (for example dashboard, html-export).", "group": "Approval Flow", "defaultValue": [] }
}
}

View File

@@ -0,0 +1,26 @@
{
"name": "@fusion-plugin-examples/reports",
"version": "0.1.0",
"type": "module",
"description": "Reports plugin for Fusion",
"private": true,
"exports": {
".": {
"types": "./src/index.ts",
"import": "./src/index.ts"
}
},
"scripts": {
"build": "tsc",
"test": "vitest run --silent=passed-only --reporter=dot"
},
"dependencies": {
"@fusion/core": "workspace:*",
"@fusion/plugin-sdk": "workspace:*"
},
"devDependencies": {
"@types/node": "^25.5.2",
"typescript": "^5.7.0",
"vitest": "^3.2.4"
}
}

View File

@@ -0,0 +1,51 @@
import { describe, expect, it } from "vitest";
import manifest from "../../manifest.json";
import plugin from "../index.js";
const expectedKeys = [
"dailyEnabled",
"dailyCron",
"weeklyEnabled",
"weeklyCron",
"timezone",
"generationPromptDaily",
"generationPromptWeekly",
"reviewPrompt",
"reviewPanelAgentIds",
"reviewMinApprovals",
"reviewBlockingMode",
"sectionOrder",
"enabledSections",
"includeSystemSummary",
"includePerAgentSections",
"brandTitle",
"brandLogoUrl",
"themeMode",
"accentColor",
"approvalRequired",
"autoPublishOnApproval",
"approverAgentIds",
"publishTargets",
] as const;
describe("reports plugin manifest", () => {
it("exports expected plugin id", () => {
expect(plugin.manifest.id).toBe("fusion-plugin-reports");
});
it("keeps runtime manifest metadata aligned with manifest.json", () => {
expect(plugin.manifest.id).toBe(manifest.id);
expect(plugin.manifest.name).toBe(manifest.name);
expect(plugin.manifest.version).toBe(manifest.version);
expect(plugin.manifest.description).toBe(manifest.description);
expect(plugin.manifest.author).toBe(manifest.author);
expect(plugin.manifest.fusionVersion).toBe(manifest.fusionVersion);
});
it("includes full settings schema", () => {
expect(plugin.manifest.settingsSchema).toBeDefined();
for (const key of expectedKeys) {
expect(plugin.manifest.settingsSchema).toHaveProperty(key);
}
});
});

View File

@@ -0,0 +1,157 @@
import { describe, expect, it } from "vitest";
import type { PluginSettingType } from "@fusion/plugin-sdk";
import {
DEFAULT_ACCENT_COLOR,
DEFAULT_AUTO_PUBLISH_ON_APPROVAL,
DEFAULT_BRAND_TITLE,
DEFAULT_DAILY_CRON,
DEFAULT_DAILY_ENABLED,
DEFAULT_ENABLED_SECTIONS,
DEFAULT_GENERATION_PROMPT_DAILY,
DEFAULT_GENERATION_PROMPT_WEEKLY,
DEFAULT_INCLUDE_PER_AGENT_SECTIONS,
DEFAULT_INCLUDE_SYSTEM_SUMMARY,
DEFAULT_PUBLISH_TARGETS,
DEFAULT_REVIEW_BLOCKING_MODE,
DEFAULT_REVIEW_MIN_APPROVALS,
DEFAULT_REVIEW_PROMPT,
DEFAULT_SECTION_ORDER,
DEFAULT_THEME_MODE,
DEFAULT_TIMEZONE,
DEFAULT_WEEKLY_CRON,
DEFAULT_WEEKLY_ENABLED,
getAccentColor,
getApprovalRequired,
getApproverAgentIds,
getAutoPublishOnApproval,
getBrandLogoUrl,
getBrandTitle,
getDailyCron,
getDailyEnabled,
getEnabledSections,
getGenerationPromptDaily,
getGenerationPromptWeekly,
getIncludePerAgentSections,
getIncludeSystemSummary,
getPublishTargets,
getReviewBlockingMode,
getReviewMinApprovals,
getReviewPanelAgentIds,
getReviewPrompt,
getSectionOrder,
getThemeMode,
getTimezone,
getWeeklyCron,
getWeeklyEnabled,
settingsSchema,
} from "../settings.js";
const VALID_TYPES: PluginSettingType[] = ["string", "number", "boolean", "enum", "password", "array"];
describe("reports plugin settings schema", () => {
it("uses only valid plugin setting types and labels", () => {
for (const [key, schema] of Object.entries(settingsSchema)) {
expect(VALID_TYPES).toContain(schema.type);
expect(typeof schema.label).toBe("string");
expect(schema.label?.trim().length).toBeGreaterThan(0);
if (schema.type === "enum") {
expect(Array.isArray(schema.enumValues)).toBe(true);
expect(schema.enumValues?.length ?? 0).toBeGreaterThan(0);
}
if (schema.type === "array") {
expect(schema.itemType).toBe("string");
}
expect(key.length).toBeGreaterThan(0);
}
});
it("uses documented literal defaults", () => {
expect(settingsSchema.dailyCron.defaultValue).toBe("0 8 * * *");
expect(settingsSchema.weeklyCron.defaultValue).toBe("0 8 * * 1");
expect(settingsSchema.timezone.defaultValue).toBe("UTC");
expect(settingsSchema.themeMode.defaultValue).toBe("auto");
expect(settingsSchema.brandTitle.defaultValue).toBe("Fusion Activity Report");
});
it("returns defaults for empty settings", () => {
const empty = {};
expect(getDailyEnabled(empty)).toBe(DEFAULT_DAILY_ENABLED);
expect(getDailyCron(empty)).toBe(DEFAULT_DAILY_CRON);
expect(getWeeklyEnabled(empty)).toBe(DEFAULT_WEEKLY_ENABLED);
expect(getWeeklyCron(empty)).toBe(DEFAULT_WEEKLY_CRON);
expect(getTimezone(empty)).toBe(DEFAULT_TIMEZONE);
expect(getGenerationPromptDaily(empty)).toBe(DEFAULT_GENERATION_PROMPT_DAILY);
expect(getGenerationPromptWeekly(empty)).toBe(DEFAULT_GENERATION_PROMPT_WEEKLY);
expect(getReviewPrompt(empty)).toBe(DEFAULT_REVIEW_PROMPT);
expect(getReviewPanelAgentIds(empty)).toEqual([]);
expect(getReviewMinApprovals(empty)).toBe(DEFAULT_REVIEW_MIN_APPROVALS);
expect(getReviewBlockingMode(empty)).toBe(DEFAULT_REVIEW_BLOCKING_MODE);
expect(getSectionOrder(empty)).toEqual(DEFAULT_SECTION_ORDER);
expect(getEnabledSections(empty)).toEqual(DEFAULT_ENABLED_SECTIONS);
expect(getIncludeSystemSummary(empty)).toBe(DEFAULT_INCLUDE_SYSTEM_SUMMARY);
expect(getIncludePerAgentSections(empty)).toBe(DEFAULT_INCLUDE_PER_AGENT_SECTIONS);
expect(getBrandTitle(empty)).toBe(DEFAULT_BRAND_TITLE);
expect(getBrandLogoUrl(empty)).toBeUndefined();
expect(getThemeMode(empty)).toBe(DEFAULT_THEME_MODE);
expect(getAccentColor(empty)).toBe(DEFAULT_ACCENT_COLOR);
expect(getApprovalRequired(empty)).toBe(false);
expect(getAutoPublishOnApproval(empty)).toBe(DEFAULT_AUTO_PUBLISH_ON_APPROVAL);
expect(getApproverAgentIds(empty)).toEqual([]);
expect(getPublishTargets(empty)).toEqual(DEFAULT_PUBLISH_TARGETS);
});
it("returns configured values when provided", () => {
const populated = {
dailyEnabled: false,
dailyCron: "5 9 * * *",
weeklyEnabled: false,
weeklyCron: "15 7 * * 2",
timezone: "America/New_York",
generationPromptDaily: "daily prompt",
generationPromptWeekly: "weekly prompt",
reviewPrompt: "review prompt",
reviewPanelAgentIds: ["agent-a", "agent-b"],
reviewMinApprovals: 3,
reviewBlockingMode: "block",
sectionOrder: ["highlights", "wins"],
enabledSections: ["wins"],
includeSystemSummary: false,
includePerAgentSections: false,
brandTitle: "Custom Report",
brandLogoUrl: "https://example.com/logo.png",
themeMode: "dark",
accentColor: "#123456",
approvalRequired: true,
autoPublishOnApproval: false,
approverAgentIds: ["approver-a"],
publishTargets: ["dashboard", "html-export"],
} satisfies Record<string, unknown>;
expect(getDailyEnabled(populated)).toBe(false);
expect(getDailyCron(populated)).toBe("5 9 * * *");
expect(getWeeklyEnabled(populated)).toBe(false);
expect(getWeeklyCron(populated)).toBe("15 7 * * 2");
expect(getTimezone(populated)).toBe("America/New_York");
expect(getGenerationPromptDaily(populated)).toBe("daily prompt");
expect(getGenerationPromptWeekly(populated)).toBe("weekly prompt");
expect(getReviewPrompt(populated)).toBe("review prompt");
expect(getReviewPanelAgentIds(populated)).toEqual(["agent-a", "agent-b"]);
expect(getReviewMinApprovals(populated)).toBe(3);
expect(getReviewBlockingMode(populated)).toBe("block");
expect(getSectionOrder(populated)).toEqual(["highlights", "wins"]);
expect(getEnabledSections(populated)).toEqual(["wins"]);
expect(getIncludeSystemSummary(populated)).toBe(false);
expect(getIncludePerAgentSections(populated)).toBe(false);
expect(getBrandTitle(populated)).toBe("Custom Report");
expect(getBrandLogoUrl(populated)).toBe("https://example.com/logo.png");
expect(getThemeMode(populated)).toBe("dark");
expect(getAccentColor(populated)).toBe("#123456");
expect(getApprovalRequired(populated)).toBe(true);
expect(getAutoPublishOnApproval(populated)).toBe(false);
expect(getApproverAgentIds(populated)).toEqual(["approver-a"]);
expect(getPublishTargets(populated)).toEqual(["dashboard", "html-export"]);
});
});

View File

@@ -0,0 +1,20 @@
import { definePlugin } from "@fusion/plugin-sdk";
import { settingsSchema } from "./settings.js";
const plugin = definePlugin({
manifest: {
id: "fusion-plugin-reports",
name: "Reports",
version: "0.1.0",
description: "Generates beautiful HTML system-activity reports with multi-agent review.",
author: "Fusion Team",
fusionVersion: ">=0.1.0",
settingsSchema,
},
state: "installed",
hooks: {},
});
export default plugin;
export * from "./settings.js";

View File

@@ -0,0 +1,105 @@
import type { PluginSettingSchema } from "@fusion/plugin-sdk";
export const DEFAULT_DAILY_ENABLED = true;
export const DEFAULT_DAILY_CRON = "0 8 * * *";
export const DEFAULT_WEEKLY_ENABLED = true;
export const DEFAULT_WEEKLY_CRON = "0 8 * * 1";
export const DEFAULT_TIMEZONE = "UTC";
export const DEFAULT_GENERATION_PROMPT_DAILY = "Summarize today's system activity with clear wins, highlights, lowlights, and proposals.";
export const DEFAULT_GENERATION_PROMPT_WEEKLY = "Summarize this week's system activity trends, major outcomes, and actionable proposals.";
export const DEFAULT_REVIEW_PROMPT = "Review this report for factual accuracy, clarity, and actionability. Provide concrete revision suggestions.";
export const DEFAULT_REVIEW_MIN_APPROVALS = 1;
export const DEFAULT_REVIEW_BLOCKING_MODE = "advisory";
export const DEFAULT_SECTION_ORDER = ["wins", "highlights", "lowlights", "proposals", "deep-dives", "per-agent"];
export const DEFAULT_ENABLED_SECTIONS = [...DEFAULT_SECTION_ORDER];
export const DEFAULT_INCLUDE_SYSTEM_SUMMARY = true;
export const DEFAULT_INCLUDE_PER_AGENT_SECTIONS = true;
export const DEFAULT_BRAND_TITLE = "Fusion Activity Report";
export const DEFAULT_THEME_MODE = "auto";
export const DEFAULT_ACCENT_COLOR = "#5B8DEF";
export const DEFAULT_APPROVAL_REQUIRED = false;
export const DEFAULT_AUTO_PUBLISH_ON_APPROVAL = true;
export const DEFAULT_PUBLISH_TARGETS: string[] = [];
export const settingsSchema: Record<string, PluginSettingSchema> = {
dailyEnabled: { type: "boolean", label: "Enable Daily Reports", description: "Generate daily reports on schedule.", group: "Schedules", defaultValue: DEFAULT_DAILY_ENABLED },
dailyCron: { type: "string", label: "Daily Schedule (cron)", description: "Cron expression for daily report generation.", group: "Schedules", required: true, defaultValue: DEFAULT_DAILY_CRON },
weeklyEnabled: { type: "boolean", label: "Enable Weekly Reports", description: "Generate weekly reports on schedule.", group: "Schedules", defaultValue: DEFAULT_WEEKLY_ENABLED },
weeklyCron: { type: "string", label: "Weekly Schedule (cron)", description: "Cron expression for weekly report generation.", group: "Schedules", required: true, defaultValue: DEFAULT_WEEKLY_CRON },
timezone: { type: "string", label: "Timezone", description: "IANA timezone used for schedule evaluation.", group: "Schedules", required: true, defaultValue: DEFAULT_TIMEZONE },
generationPromptDaily: { type: "string", multiline: true, label: "Daily Generation Prompt", description: "Prompt template used to generate daily reports.", group: "Prompts", required: true, defaultValue: DEFAULT_GENERATION_PROMPT_DAILY },
generationPromptWeekly: { type: "string", multiline: true, label: "Weekly Generation Prompt", description: "Prompt template used to generate weekly reports.", group: "Prompts", required: true, defaultValue: DEFAULT_GENERATION_PROMPT_WEEKLY },
reviewPrompt: { type: "string", multiline: true, label: "Review Prompt", description: "Prompt template used by reviewer agents.", group: "Prompts", required: true, defaultValue: DEFAULT_REVIEW_PROMPT },
reviewPanelAgentIds: { type: "array", itemType: "string", label: "Reviewer Agent IDs", description: "Agent IDs allowed to review generated reports.", group: "Review Panel", defaultValue: [] },
reviewMinApprovals: { type: "number", label: "Minimum Approvals", description: "How many approvals are required from the review panel.", group: "Review Panel", defaultValue: DEFAULT_REVIEW_MIN_APPROVALS },
reviewBlockingMode: { type: "enum", enumValues: ["block", "advisory"], label: "Review Blocking Mode", description: "Choose whether failed review blocks publication.", group: "Review Panel", defaultValue: DEFAULT_REVIEW_BLOCKING_MODE },
sectionOrder: { type: "array", itemType: "string", label: "Section Order", description: "Ordered section IDs for report rendering.", group: "Sections", defaultValue: DEFAULT_SECTION_ORDER },
enabledSections: { type: "array", itemType: "string", label: "Enabled Sections", description: "Section IDs enabled for output.", group: "Sections", defaultValue: DEFAULT_ENABLED_SECTIONS },
includeSystemSummary: { type: "boolean", label: "Include System Summary", description: "Include top-level system summary in report output.", group: "Sections", defaultValue: DEFAULT_INCLUDE_SYSTEM_SUMMARY },
includePerAgentSections: { type: "boolean", label: "Include Per-Agent Sections", description: "Include per-agent detail sections.", group: "Sections", defaultValue: DEFAULT_INCLUDE_PER_AGENT_SECTIONS },
brandTitle: { type: "string", label: "Report Title", description: "Primary report title for branding.", group: "Branding", required: true, defaultValue: DEFAULT_BRAND_TITLE },
brandLogoUrl: { type: "string", label: "Logo URL", description: "Optional URL to a brand logo image.", group: "Branding" },
themeMode: { type: "enum", enumValues: ["light", "dark", "auto"], label: "Theme Mode", description: "Theme style for generated reports.", group: "Branding", defaultValue: DEFAULT_THEME_MODE },
accentColor: { type: "string", label: "Accent Color", description: "Accent color used in report styling.", group: "Branding", defaultValue: DEFAULT_ACCENT_COLOR },
approvalRequired: { type: "boolean", label: "Require Approval", description: "Require explicit approval before publishing.", group: "Approval Flow", defaultValue: DEFAULT_APPROVAL_REQUIRED },
autoPublishOnApproval: { type: "boolean", label: "Auto Publish on Approval", description: "Publish automatically after approval threshold is met.", group: "Approval Flow", defaultValue: DEFAULT_AUTO_PUBLISH_ON_APPROVAL },
approverAgentIds: { type: "array", itemType: "string", label: "Approver Agent IDs", description: "Agent IDs permitted to approve final publish.", group: "Approval Flow", defaultValue: [] },
publishTargets: { type: "array", itemType: "string", label: "Publish Targets", description: "Destinations to publish reports to (for example dashboard, html-export).", group: "Approval Flow", defaultValue: DEFAULT_PUBLISH_TARGETS },
};
function asString(settings: Record<string, unknown>, key: string): string | undefined {
const value = settings[key];
return typeof value === "string" && value.trim().length > 0 ? value.trim() : undefined;
}
function asBoolean(settings: Record<string, unknown>, key: string, fallback: boolean): boolean {
const value = settings[key];
return typeof value === "boolean" ? value : fallback;
}
function asNumber(settings: Record<string, unknown>, key: string, fallback: number): number {
const value = settings[key];
return typeof value === "number" && Number.isFinite(value) ? value : fallback;
}
function asStringArray(settings: Record<string, unknown>, key: string, fallback: string[]): string[] {
const value = settings[key];
if (!Array.isArray(value)) return [...fallback];
const normalized = value.filter((item): item is string => typeof item === "string").map((item) => item.trim()).filter(Boolean);
return normalized.length > 0 ? normalized : [...fallback];
}
export function getDailyEnabled(settings: Record<string, unknown>): boolean { return asBoolean(settings, "dailyEnabled", DEFAULT_DAILY_ENABLED); }
export function getDailyCron(settings: Record<string, unknown>): string { return asString(settings, "dailyCron") ?? DEFAULT_DAILY_CRON; }
export function getWeeklyEnabled(settings: Record<string, unknown>): boolean { return asBoolean(settings, "weeklyEnabled", DEFAULT_WEEKLY_ENABLED); }
export function getWeeklyCron(settings: Record<string, unknown>): string { return asString(settings, "weeklyCron") ?? DEFAULT_WEEKLY_CRON; }
export function getTimezone(settings: Record<string, unknown>): string { return asString(settings, "timezone") ?? DEFAULT_TIMEZONE; }
export function getGenerationPromptDaily(settings: Record<string, unknown>): string { return asString(settings, "generationPromptDaily") ?? DEFAULT_GENERATION_PROMPT_DAILY; }
export function getGenerationPromptWeekly(settings: Record<string, unknown>): string { return asString(settings, "generationPromptWeekly") ?? DEFAULT_GENERATION_PROMPT_WEEKLY; }
export function getReviewPrompt(settings: Record<string, unknown>): string { return asString(settings, "reviewPrompt") ?? DEFAULT_REVIEW_PROMPT; }
export function getReviewPanelAgentIds(settings: Record<string, unknown>): string[] { return asStringArray(settings, "reviewPanelAgentIds", []); }
export function getReviewMinApprovals(settings: Record<string, unknown>): number { return Math.max(1, Math.floor(asNumber(settings, "reviewMinApprovals", DEFAULT_REVIEW_MIN_APPROVALS))); }
export function getReviewBlockingMode(settings: Record<string, unknown>): "block" | "advisory" {
const value = asString(settings, "reviewBlockingMode");
return value === "block" ? "block" : "advisory";
}
export function getSectionOrder(settings: Record<string, unknown>): string[] { return asStringArray(settings, "sectionOrder", DEFAULT_SECTION_ORDER); }
export function getEnabledSections(settings: Record<string, unknown>): string[] { return asStringArray(settings, "enabledSections", DEFAULT_ENABLED_SECTIONS); }
export function getIncludeSystemSummary(settings: Record<string, unknown>): boolean { return asBoolean(settings, "includeSystemSummary", DEFAULT_INCLUDE_SYSTEM_SUMMARY); }
export function getIncludePerAgentSections(settings: Record<string, unknown>): boolean { return asBoolean(settings, "includePerAgentSections", DEFAULT_INCLUDE_PER_AGENT_SECTIONS); }
export function getBrandTitle(settings: Record<string, unknown>): string { return asString(settings, "brandTitle") ?? DEFAULT_BRAND_TITLE; }
export function getBrandLogoUrl(settings: Record<string, unknown>): string | undefined { return asString(settings, "brandLogoUrl"); }
export function getThemeMode(settings: Record<string, unknown>): "light" | "dark" | "auto" {
const value = asString(settings, "themeMode");
return value === "light" || value === "dark" ? value : "auto";
}
export function getAccentColor(settings: Record<string, unknown>): string { return asString(settings, "accentColor") ?? DEFAULT_ACCENT_COLOR; }
export function getApprovalRequired(settings: Record<string, unknown>): boolean { return asBoolean(settings, "approvalRequired", DEFAULT_APPROVAL_REQUIRED); }
export function getAutoPublishOnApproval(settings: Record<string, unknown>): boolean { return asBoolean(settings, "autoPublishOnApproval", DEFAULT_AUTO_PUBLISH_ON_APPROVAL); }
export function getApproverAgentIds(settings: Record<string, unknown>): string[] { return asStringArray(settings, "approverAgentIds", []); }
export function getPublishTargets(settings: Record<string, unknown>): string[] { return asStringArray(settings, "publishTargets", DEFAULT_PUBLISH_TARGETS); }

View File

@@ -0,0 +1,9 @@
{
"extends": "../tsconfig.base.json",
"compilerOptions": {
"outDir": "dist",
"rootDir": "src",
"types": ["node", "vitest/globals"]
},
"include": ["src/**/*"]
}

View File

@@ -0,0 +1,22 @@
import { defineConfig } from "vitest/config";
import { fileURLToPath } from "node:url";
import { computeMaxWorkers } from "../../packages/core/src/__test-utils__/vitest-workers";
const maxWorkers = computeMaxWorkers();
export default defineConfig({
resolve: {
alias: {
"@fusion/core": fileURLToPath(new URL("../../packages/core/src/index.ts", import.meta.url)),
"@fusion/plugin-sdk": fileURLToPath(new URL("../../packages/plugin-sdk/src/index.ts", import.meta.url)),
},
},
test: {
include: ["src/**/__tests__/**/*.test.{ts,tsx}", "src/**/*.test.{ts,tsx}"],
setupFiles: [fileURLToPath(new URL("../../packages/core/src/__test-utils__/vitest-setup.ts", import.meta.url))],
globalSetup: [fileURLToPath(new URL("../../packages/core/src/__test-utils__/vitest-teardown.ts", import.meta.url))],
pool: "threads",
maxWorkers,
poolOptions: { threads: { minThreads: 1, maxThreads: maxWorkers }, forks: { minForks: 1, maxForks: maxWorkers } },
},
});