Files
fusion/plugins/fusion-plugin-reports/src/index.ts
Fusion 8089953710 feat(FN-3860): add cadence resolution seam (+7 more)
Commits merged:
- feat(FN-3860): complete Step 8 — documentation and delivery
- test(FN-3860): complete Step 7 — add scaffold seam coverage
- feat(FN-3860): complete Step 6 — re-export scaffold seams
- feat(FN-3860): complete Step 5 — add pipeline orchestrator seam
- feat(FN-3860): complete Step 4 — add in-memory runs store seam
- feat(FN-3860): complete Step 3 — add aggregation seam
- feat(FN-3860): complete Step 2 — add cadence resolution seam
- feat(FN-3846): short-circuit phantom merges for already-landed branches

Files changed:
.changeset/fn-3860-reports-scaffold-files.md       |  5 ++
 plugins/fusion-plugin-reports/README.md            |  9 +++
 .../src/__tests__/scaffold.test.ts                 | 60 +++++++++++++++++++
 plugins/fusion-plugin-reports/src/aggregation.ts   | 23 ++++++++
 plugins/fusion-plugin-reports/src/cadence.ts       | 23 ++++++++
 plugins/fusion-plugin-reports/src/index.ts         |  4 ++
 plugins/fusion-plugin-reports/src/pipeline.ts      | 58 ++++++++++++++++++
 plugins/fusion-plugin-reports/src/runs-store.ts    | 69 ++++++++++++++++++++++
 8 files changed, 251 insertions(+)

Fusion-Task-Id: FN-3860
2026-05-11 08:02:53 -07:00

134 lines
4.4 KiB
TypeScript

import type { PluginContext } from "@fusion/core";
import { definePlugin } from "@fusion/plugin-sdk";
import { initializeApprovalState } from "./approval.js";
import { runReviewPanel } from "./review-panel.js";
import { ensureReportSchema } from "./report-schema.js";
import { createReportApprovalRoutes } from "./routes/report-approval-routes.js";
import { createReportExportRoutes } from "./routes/report-export-routes.js";
import { createReportListRoutes } from "./routes/report-list-routes.js";
import type { CombinedReview, ReviewPanelMember, RunReviewPanelInput } from "./review-types.js";
import {
getApprovalRequired,
getApproverAgentIds,
getAutoPublishOnApproval,
getPublishTargets,
settingsSchema,
} from "./settings.js";
import type { ReportCadence, ReportCreateInput } from "./store/report-types.js";
import { ReportStore } from "./store/report-store.js";
export { ReportsDashboardView } from "./dashboard-view.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: {
onSchemaInit: ensureReportSchema,
},
routes: [...createReportListRoutes(), ...createReportExportRoutes(), ...createReportApprovalRoutes()],
dashboardViews: [
{
viewId: "reports",
label: "Reports",
componentPath: "./dashboard-view",
icon: "FileText",
placement: "primary",
order: 35,
},
],
});
export interface RunGeneratedReportReviewInput {
reportDraft: string;
reportMetadata: RunReviewPanelInput["reportMetadata"];
panel: ReviewPanelMember[];
cwd: string;
}
const reportStoreCache = new WeakMap<object, ReportStore>();
export function getReportStore(ctx: PluginContext): ReportStore {
const key = ctx.taskStore as object;
const cached = reportStoreCache.get(key);
if (cached) return cached;
const store = new ReportStore(ctx.taskStore.getDatabase());
reportStoreCache.set(key, store);
return store;
}
function toCadence(cadence: RunReviewPanelInput["reportMetadata"]["cadence"]): ReportCadence {
return cadence;
}
export async function runGeneratedReportReview(input: RunGeneratedReportReviewInput, ctx: PluginContext): Promise<CombinedReview> {
const store = getReportStore(ctx);
const reportInput: ReportCreateInput = {
cadence: toCadence(input.reportMetadata.cadence),
periodStart: input.reportMetadata.periodStart,
periodEnd: input.reportMetadata.periodEnd,
title: `Generated ${input.reportMetadata.cadence} report`,
draftMarkdown: input.reportDraft,
metadata: {
reportMetadata: input.reportMetadata,
source: "runGeneratedReportReview",
},
};
const report = store.createReport(reportInput);
store.setStatus(report.id, "review_pending");
store.setStatus(report.id, "review_in_progress");
const combinedReview = await runReviewPanel({
reportDraft: input.reportDraft,
reportMetadata: {
...input.reportMetadata,
reportId: report.id,
},
panel: input.panel,
cwd: input.cwd,
}, ctx);
const reviewed = store.attachReview(report.id, combinedReview);
const nextApprovalState = initializeApprovalState(reviewed.status, {
approvalRequired: getApprovalRequired(ctx.settings),
autoPublishOnApproval: getAutoPublishOnApproval(ctx.settings),
approverAgentIds: getApproverAgentIds(ctx.settings),
publishTargets: getPublishTargets(ctx.settings),
});
if (nextApprovalState !== "not_required") {
const now = new Date().toISOString();
store.updateReport(report.id, {
approvalState: nextApprovalState,
...(nextApprovalState === "approved"
? { status: "approved", approvedAt: now, approvedBy: "system" }
: {}),
...(nextApprovalState === "published" ? { status: "published", publishedAt: now } : {}),
});
}
return combinedReview;
}
export default plugin;
export * from "./settings.js";
export * from "./cadence.js";
export * from "./aggregation.js";
export * from "./pipeline.js";
export * from "./runs-store.js";
export * from "./review-types.js";
export * from "./review-panel.js";
export { ensureReportSchema } from "./report-schema.js";
export { ReportStore, ReportStoreError, type ReportStoreEvents } from "./store/report-store.js";
export * from "./store/report-types.js";
export * from "./render/index.js";