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:
51
plugins/fusion-plugin-reports/src/__tests__/manifest.test.ts
Normal file
51
plugins/fusion-plugin-reports/src/__tests__/manifest.test.ts
Normal 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);
|
||||
}
|
||||
});
|
||||
});
|
||||
157
plugins/fusion-plugin-reports/src/__tests__/settings.test.ts
Normal file
157
plugins/fusion-plugin-reports/src/__tests__/settings.test.ts
Normal 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"]);
|
||||
});
|
||||
});
|
||||
20
plugins/fusion-plugin-reports/src/index.ts
Normal file
20
plugins/fusion-plugin-reports/src/index.ts
Normal 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";
|
||||
105
plugins/fusion-plugin-reports/src/settings.ts
Normal file
105
plugins/fusion-plugin-reports/src/settings.ts
Normal 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); }
|
||||
Reference in New Issue
Block a user