@runfusion/fusion 0.22.0 → 0.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (206) hide show
  1. package/dist/bin.js +30071 -20735
  2. package/dist/client/assets/AgentDetailView-BwJaLqZh.css +1 -0
  3. package/dist/client/assets/AgentDetailView-gy_5SUj2.js +18 -0
  4. package/dist/client/assets/AgentsView-BkB9FiMT.js +29 -0
  5. package/dist/client/assets/AgentsView-CV3vm7Qk.css +1 -0
  6. package/dist/client/assets/ChatView-B_-B8fqu.js +1 -0
  7. package/dist/client/assets/ChatView-DwJAd5G1.css +1 -0
  8. package/dist/client/assets/{DevServerView-l8RCyL2k.js → DevServerView-BkvtjZBa.js} +1 -1
  9. package/dist/client/assets/{DirectoryPicker-CS1dwqcC.js → DirectoryPicker-BK-KbnhP.js} +1 -1
  10. package/dist/client/assets/{DocumentsView-DmthQWDZ.js → DocumentsView-BEg1CQAk.js} +1 -1
  11. package/dist/client/assets/{DocumentsView-BrhyOdeE.css → DocumentsView-gv4zG3aT.css} +1 -1
  12. package/dist/client/assets/EvalsView-Berf9bQm.js +1 -0
  13. package/dist/client/assets/EvalsView-CUNJ1TLc.css +1 -0
  14. package/dist/client/assets/{agentSkills-DDHJnrkn.css → ExperimentalAgentOnboardingModal-B-APN_lM.css} +1 -1
  15. package/dist/client/assets/ExperimentalAgentOnboardingModal-jcInE50G.js +499 -0
  16. package/dist/client/assets/InsightsView-B0J4mhzV.css +1 -0
  17. package/dist/client/assets/InsightsView-BX5bSF1J.js +11 -0
  18. package/dist/client/assets/{MemoryView-CPwlKnUI.js → MemoryView-CKElJY_3.js} +2 -2
  19. package/dist/client/assets/NodesView-DLUOBLf6.js +14 -0
  20. package/dist/client/assets/NodesView-DT4pXowv.css +1 -0
  21. package/dist/client/assets/{PiExtensionsManager-j8rPXqmB.js → PiExtensionsManager-COlJf0Kx.js} +2 -2
  22. package/dist/client/assets/PluginManager-CfW55BF4.js +1 -0
  23. package/dist/client/assets/PluginManager-DtRQXia5.css +1 -0
  24. package/dist/client/assets/{ResearchView-D9DNJYDq.js → ResearchView-B256Lr8I.js} +1 -1
  25. package/dist/client/assets/SettingsModal-BeA_nQtW.js +31 -0
  26. package/dist/client/assets/SettingsModal-DzsLquBu.css +1 -0
  27. package/dist/client/assets/{SettingsModal-fxvTFLtR.js → SettingsModal-yRqM4DV8.js} +1 -1
  28. package/dist/client/assets/SetupWizardModal-uUZk3TKT.js +1 -0
  29. package/dist/client/assets/{SkillsView-Ddf0YL8z.js → SkillsView-CP8JX0P_.js} +1 -1
  30. package/dist/client/assets/TodoView-Cx9cVhq7.css +1 -0
  31. package/dist/client/assets/TodoView-DCRIkDZ-.js +6 -0
  32. package/dist/client/assets/createLucideIcon-BazL2hk5.js +21 -0
  33. package/dist/client/assets/dashboard-view-BkTMSZYn.css +1 -0
  34. package/dist/client/assets/dashboard-view-CyWN-d02.js +63 -0
  35. package/dist/client/assets/dashboard-view-lR7YYmSC.js +21 -0
  36. package/dist/client/assets/{folder-open-BiJpmnaT.js → folder-open-DHjELt8-.js} +1 -1
  37. package/dist/client/assets/index-CQyVRLOb.js +692 -0
  38. package/dist/client/assets/index-CxA2Nn0_.css +1 -0
  39. package/dist/client/assets/projectDetection-G3XuxD2X.js +1 -0
  40. package/dist/client/assets/{star-BwRZmiuZ.js → star-DYesq1AV.js} +1 -1
  41. package/dist/client/assets/{upload-D4NwZhPp.js → upload-DTWF3Db5.js} +1 -1
  42. package/dist/client/assets/{users-DNISDtI1.js → users--syrel4l.js} +1 -1
  43. package/dist/client/index.html +12 -20
  44. package/dist/client/theme-data.css +106 -0
  45. package/dist/client/version.json +1 -1
  46. package/dist/droid-cli/package.json +1 -1
  47. package/dist/extension.js +17072 -9627
  48. package/dist/pi-claude-cli/package.json +1 -1
  49. package/dist/plugins/fusion-plugin-cursor-runtime/bundled.js +218 -0
  50. package/dist/plugins/fusion-plugin-cursor-runtime/manifest.json +6 -0
  51. package/dist/plugins/fusion-plugin-cursor-runtime/package.json +11 -0
  52. package/dist/plugins/fusion-plugin-dependency-graph/manifest.json +1 -1
  53. package/dist/plugins/fusion-plugin-dependency-graph/package.json +6 -4
  54. package/dist/plugins/fusion-plugin-dependency-graph/src/DependencyGraph.css +58 -0
  55. package/dist/plugins/fusion-plugin-dependency-graph/src/DependencyGraph.tsx +301 -0
  56. package/dist/plugins/fusion-plugin-dependency-graph/src/GraphHighlight.css +27 -0
  57. package/dist/plugins/fusion-plugin-dependency-graph/src/GraphTaskNode.css +157 -0
  58. package/dist/plugins/fusion-plugin-dependency-graph/src/GraphTaskNode.tsx +126 -0
  59. package/dist/plugins/fusion-plugin-dependency-graph/src/GraphToolbar.css +35 -0
  60. package/dist/plugins/fusion-plugin-dependency-graph/src/GraphToolbar.tsx +36 -0
  61. package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/DependencyGraph.highlighting.test.tsx +112 -0
  62. package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/DependencyGraph.persistence.test.tsx +115 -0
  63. package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/DependencyGraph.test.tsx +128 -0
  64. package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/GraphTaskNode.drag.test.tsx +82 -0
  65. package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/GraphTaskNode.test.tsx +307 -0
  66. package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/GraphToolbar.test.tsx +60 -0
  67. package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/edges.test.tsx +75 -0
  68. package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/filtering.test.tsx +62 -0
  69. package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/filters.test.ts +78 -0
  70. package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/graphPositionStorage.test.ts +95 -0
  71. package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/host-integration.test.ts +74 -0
  72. package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/index.test.ts +58 -0
  73. package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/interactions.test.tsx +121 -0
  74. package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/layout.test.ts +70 -0
  75. package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/persistence.test.tsx +89 -0
  76. package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/useGraphData.test.ts +86 -0
  77. package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/useGraphInteraction.test.ts +167 -0
  78. package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/useGraphPositions.test.ts +66 -0
  79. package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/useNodeDrag.test.ts +81 -0
  80. package/dist/plugins/fusion-plugin-dependency-graph/src/dashboard-interop.d.ts +35 -0
  81. package/dist/plugins/fusion-plugin-dependency-graph/src/dashboard-view.tsx +19 -0
  82. package/dist/plugins/fusion-plugin-dependency-graph/src/edges.tsx +70 -0
  83. package/dist/plugins/fusion-plugin-dependency-graph/src/filters.ts +8 -0
  84. package/dist/plugins/fusion-plugin-dependency-graph/src/hooks/__tests__/useDependencyChain.test.ts +53 -0
  85. package/dist/plugins/fusion-plugin-dependency-graph/src/hooks/useDependencyChain.ts +60 -0
  86. package/dist/plugins/fusion-plugin-dependency-graph/src/hooks/useGraphPositions.ts +45 -0
  87. package/dist/plugins/fusion-plugin-dependency-graph/src/hooks/useNodeDrag.ts +114 -0
  88. package/dist/plugins/fusion-plugin-dependency-graph/src/index.ts +1 -2
  89. package/dist/plugins/fusion-plugin-dependency-graph/src/layout.ts +91 -0
  90. package/dist/plugins/fusion-plugin-dependency-graph/src/styles/drag.css +15 -0
  91. package/dist/plugins/fusion-plugin-dependency-graph/src/types.ts +21 -0
  92. package/dist/plugins/fusion-plugin-dependency-graph/src/useGraphData.ts +17 -0
  93. package/dist/plugins/fusion-plugin-dependency-graph/src/useGraphInteraction.ts +292 -0
  94. package/dist/plugins/fusion-plugin-dependency-graph/src/utils/graphPositionStorage.ts +65 -0
  95. package/dist/plugins/fusion-plugin-droid-runtime/bundled.js +136680 -0
  96. package/dist/plugins/fusion-plugin-droid-runtime/manifest.json +13 -0
  97. package/dist/plugins/fusion-plugin-droid-runtime/mcp-schema-server.cjs +49 -0
  98. package/dist/plugins/fusion-plugin-droid-runtime/package.json +11 -0
  99. package/dist/plugins/fusion-plugin-hermes-runtime/bundled.js +176 -7
  100. package/dist/plugins/fusion-plugin-hermes-runtime/package.json +1 -1
  101. package/dist/plugins/fusion-plugin-openclaw-runtime/bundled.js +93 -6
  102. package/dist/plugins/fusion-plugin-openclaw-runtime/mcp-schema-server.cjs +59 -0
  103. package/dist/plugins/fusion-plugin-openclaw-runtime/package.json +1 -1
  104. package/dist/plugins/fusion-plugin-paperclip-runtime/package.json +1 -1
  105. package/dist/plugins/fusion-plugin-reports/manifest.json +33 -0
  106. package/dist/plugins/fusion-plugin-reports/package.json +26 -0
  107. package/dist/plugins/fusion-plugin-reports/src/__tests__/manifest.test.ts +51 -0
  108. package/dist/plugins/fusion-plugin-reports/src/__tests__/review-panel.test.ts +166 -0
  109. package/dist/plugins/fusion-plugin-reports/src/__tests__/settings.test.ts +157 -0
  110. package/dist/plugins/fusion-plugin-reports/src/index.ts +41 -0
  111. package/dist/plugins/fusion-plugin-reports/src/review-panel.ts +294 -0
  112. package/dist/plugins/fusion-plugin-reports/src/review-types.ts +75 -0
  113. package/dist/plugins/fusion-plugin-reports/src/settings.ts +105 -0
  114. package/dist/plugins/fusion-plugin-roadmap/manifest.json +16 -0
  115. package/dist/plugins/fusion-plugin-roadmap/package.json +48 -0
  116. package/dist/plugins/fusion-plugin-roadmap/src/__tests__/api-client.test.ts +101 -0
  117. package/dist/plugins/fusion-plugin-roadmap/src/__tests__/index.test.ts +92 -0
  118. package/dist/plugins/fusion-plugin-roadmap/src/__tests__/roadmap-routes.test.ts +48 -0
  119. package/dist/plugins/fusion-plugin-roadmap/src/__tests__/roadmap-suggestions.test.ts +31 -0
  120. package/dist/plugins/fusion-plugin-roadmap/src/dashboard/RoadmapsView.css +1299 -0
  121. package/dist/plugins/fusion-plugin-roadmap/src/dashboard/RoadmapsView.tsx +2559 -0
  122. package/dist/plugins/fusion-plugin-roadmap/src/dashboard/__tests__/RoadmapsView.test.tsx +1144 -0
  123. package/dist/plugins/fusion-plugin-roadmap/src/dashboard/__tests__/useRoadmaps.test.ts +1756 -0
  124. package/dist/plugins/fusion-plugin-roadmap/src/dashboard/api.ts +70 -0
  125. package/dist/plugins/fusion-plugin-roadmap/src/dashboard/test-setup.ts +7 -0
  126. package/dist/plugins/fusion-plugin-roadmap/src/dashboard/types.ts +1 -0
  127. package/dist/plugins/fusion-plugin-roadmap/src/dashboard/useConfirm.ts +8 -0
  128. package/dist/plugins/fusion-plugin-roadmap/src/dashboard/useRoadmaps.ts +1188 -0
  129. package/dist/plugins/fusion-plugin-roadmap/src/dashboard/useViewportMode.ts +20 -0
  130. package/dist/plugins/fusion-plugin-roadmap/src/dashboard-view.tsx +6 -0
  131. package/dist/plugins/fusion-plugin-roadmap/src/index.ts +74 -0
  132. package/dist/plugins/fusion-plugin-roadmap/src/roadmap-routes.ts +1 -0
  133. package/dist/plugins/fusion-plugin-roadmap/src/roadmap-schema.ts +41 -0
  134. package/dist/plugins/fusion-plugin-roadmap/src/roadmap-suggestions.d.ts +15 -0
  135. package/dist/plugins/fusion-plugin-roadmap/src/roadmap-suggestions.ts +15 -0
  136. package/dist/plugins/fusion-plugin-roadmap/src/roadmap-types.d.ts +283 -0
  137. package/dist/plugins/fusion-plugin-roadmap/src/roadmap-types.d.ts.map +1 -0
  138. package/dist/plugins/fusion-plugin-roadmap/src/roadmap-types.js +21 -0
  139. package/dist/plugins/fusion-plugin-roadmap/src/roadmap-types.js.map +1 -0
  140. package/dist/plugins/fusion-plugin-roadmap/src/roadmap-types.ts +310 -0
  141. package/dist/plugins/fusion-plugin-roadmap/src/routes/roadmap-routes.d.ts +5 -0
  142. package/dist/plugins/fusion-plugin-roadmap/src/routes/roadmap-routes.d.ts.map +1 -0
  143. package/dist/plugins/fusion-plugin-roadmap/src/routes/roadmap-routes.js +361 -0
  144. package/dist/plugins/fusion-plugin-roadmap/src/routes/roadmap-routes.js.map +1 -0
  145. package/dist/plugins/fusion-plugin-roadmap/src/routes/roadmap-routes.ts +408 -0
  146. package/dist/plugins/fusion-plugin-roadmap/src/routes/roadmap-suggestions.d.ts +68 -0
  147. package/dist/plugins/fusion-plugin-roadmap/src/routes/roadmap-suggestions.d.ts.map +1 -0
  148. package/dist/plugins/fusion-plugin-roadmap/src/routes/roadmap-suggestions.js +300 -0
  149. package/dist/plugins/fusion-plugin-roadmap/src/routes/roadmap-suggestions.js.map +1 -0
  150. package/dist/plugins/fusion-plugin-roadmap/src/routes/roadmap-suggestions.ts +381 -0
  151. package/dist/plugins/fusion-plugin-roadmap/src/server/index.d.ts +3 -0
  152. package/dist/plugins/fusion-plugin-roadmap/src/server/index.ts +1 -0
  153. package/dist/plugins/fusion-plugin-roadmap/src/store/__tests__/roadmap-handoff.test.ts +445 -0
  154. package/dist/plugins/fusion-plugin-roadmap/src/store/__tests__/roadmap-ordering.test.ts +334 -0
  155. package/dist/plugins/fusion-plugin-roadmap/src/store/__tests__/roadmap-store.test.ts +1318 -0
  156. package/dist/plugins/fusion-plugin-roadmap/src/store/roadmap-handoff.ts +163 -0
  157. package/dist/plugins/fusion-plugin-roadmap/src/store/roadmap-ordering.d.ts +37 -0
  158. package/dist/plugins/fusion-plugin-roadmap/src/store/roadmap-ordering.d.ts.map +1 -0
  159. package/dist/plugins/fusion-plugin-roadmap/src/store/roadmap-ordering.js +188 -0
  160. package/dist/plugins/fusion-plugin-roadmap/src/store/roadmap-ordering.js.map +1 -0
  161. package/dist/plugins/fusion-plugin-roadmap/src/store/roadmap-ordering.ts +311 -0
  162. package/dist/plugins/fusion-plugin-roadmap/src/store/roadmap-store.d.ts +299 -0
  163. package/dist/plugins/fusion-plugin-roadmap/src/store/roadmap-store.d.ts.map +1 -0
  164. package/dist/plugins/fusion-plugin-roadmap/src/store/roadmap-store.js +765 -0
  165. package/dist/plugins/fusion-plugin-roadmap/src/store/roadmap-store.js.map +1 -0
  166. package/dist/plugins/fusion-plugin-roadmap/src/store/roadmap-store.ts +1001 -0
  167. package/dist/plugins/fusion-plugin-whatsapp-chat/manifest.json +8 -0
  168. package/dist/plugins/fusion-plugin-whatsapp-chat/package.json +34 -0
  169. package/dist/plugins/fusion-plugin-whatsapp-chat/src/__tests__/auth-state.test.ts +99 -0
  170. package/dist/plugins/fusion-plugin-whatsapp-chat/src/__tests__/connection.test.ts +145 -0
  171. package/dist/plugins/fusion-plugin-whatsapp-chat/src/__tests__/index.test.ts +216 -0
  172. package/dist/plugins/fusion-plugin-whatsapp-chat/src/__tests__/reply.test.ts +52 -0
  173. package/dist/plugins/fusion-plugin-whatsapp-chat/src/auth-state.ts +89 -0
  174. package/dist/plugins/fusion-plugin-whatsapp-chat/src/connection.ts +253 -0
  175. package/dist/plugins/fusion-plugin-whatsapp-chat/src/index.ts +262 -0
  176. package/dist/plugins/fusion-plugin-whatsapp-chat/src/qrcode.d.ts +1 -0
  177. package/dist/plugins/fusion-plugin-whatsapp-chat/src/reply.ts +37 -0
  178. package/package.json +2 -2
  179. package/skill/fusion/SKILL.md +2 -2
  180. package/skill/fusion/references/engine-tools.md +8 -2
  181. package/skill/fusion/references/extension-tools.md +39 -0
  182. package/skill/fusion/references/fusion-capabilities.md +3 -0
  183. package/dist/client/assets/AgentDetailView-BKKpbp1S.js +0 -18
  184. package/dist/client/assets/AgentDetailView-CeO_1MK7.css +0 -1
  185. package/dist/client/assets/AgentsView-BRXFmrcJ.js +0 -527
  186. package/dist/client/assets/AgentsView-Bs03ptrd.css +0 -1
  187. package/dist/client/assets/ChatView-D7L2e_qu.js +0 -1
  188. package/dist/client/assets/InsightsView-AWo5o_81.css +0 -1
  189. package/dist/client/assets/InsightsView-DvXpMKmH.js +0 -11
  190. package/dist/client/assets/NodesView-BLlfUfsy.js +0 -14
  191. package/dist/client/assets/NodesView-fXqDk9ur.css +0 -1
  192. package/dist/client/assets/PluginManager-DA_T0GHn.css +0 -1
  193. package/dist/client/assets/PluginManager-pW6RMz5z.js +0 -1
  194. package/dist/client/assets/RoadmapsView-Djc_X35v.js +0 -6
  195. package/dist/client/assets/SettingsModal-BWe0KrGY.css +0 -1
  196. package/dist/client/assets/SettingsModal-WGCF_pk8.js +0 -31
  197. package/dist/client/assets/SetupWizardModal-tG_MF_nA.js +0 -1
  198. package/dist/client/assets/agentSkills-EwIwBlG8.js +0 -1
  199. package/dist/client/assets/index-D6ebxTPF.css +0 -1
  200. package/dist/client/assets/index-DYDLmOcK.js +0 -694
  201. package/dist/plugins/fusion-plugin-dependency-graph/src/DependencyGraphView.css +0 -132
  202. package/dist/plugins/fusion-plugin-dependency-graph/src/DependencyGraphView.tsx +0 -428
  203. package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/DependencyGraphView.test.tsx +0 -261
  204. package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/storage.test.ts +0 -31
  205. package/dist/plugins/fusion-plugin-dependency-graph/src/storage.ts +0 -23
  206. /package/dist/client/assets/{RoadmapsView-DdGlfuu-.css → dashboard-view-DdGlfuu-.css} +0 -0
@@ -0,0 +1,51 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import manifest from "../../manifest.json";
3
+ import plugin from "../index.js";
4
+
5
+ const expectedKeys = [
6
+ "dailyEnabled",
7
+ "dailyCron",
8
+ "weeklyEnabled",
9
+ "weeklyCron",
10
+ "timezone",
11
+ "generationPromptDaily",
12
+ "generationPromptWeekly",
13
+ "reviewPrompt",
14
+ "reviewPanelAgentIds",
15
+ "reviewMinApprovals",
16
+ "reviewBlockingMode",
17
+ "sectionOrder",
18
+ "enabledSections",
19
+ "includeSystemSummary",
20
+ "includePerAgentSections",
21
+ "brandTitle",
22
+ "brandLogoUrl",
23
+ "themeMode",
24
+ "accentColor",
25
+ "approvalRequired",
26
+ "autoPublishOnApproval",
27
+ "approverAgentIds",
28
+ "publishTargets",
29
+ ] as const;
30
+
31
+ describe("reports plugin manifest", () => {
32
+ it("exports expected plugin id", () => {
33
+ expect(plugin.manifest.id).toBe("fusion-plugin-reports");
34
+ });
35
+
36
+ it("keeps runtime manifest metadata aligned with manifest.json", () => {
37
+ expect(plugin.manifest.id).toBe(manifest.id);
38
+ expect(plugin.manifest.name).toBe(manifest.name);
39
+ expect(plugin.manifest.version).toBe(manifest.version);
40
+ expect(plugin.manifest.description).toBe(manifest.description);
41
+ expect(plugin.manifest.author).toBe(manifest.author);
42
+ expect(plugin.manifest.fusionVersion).toBe(manifest.fusionVersion);
43
+ });
44
+
45
+ it("includes full settings schema", () => {
46
+ expect(plugin.manifest.settingsSchema).toBeDefined();
47
+ for (const key of expectedKeys) {
48
+ expect(plugin.manifest.settingsSchema).toHaveProperty(key);
49
+ }
50
+ });
51
+ });
@@ -0,0 +1,166 @@
1
+ import { afterEach, describe, expect, it, vi } from "vitest";
2
+ import type { CreateAiSessionFactory, PluginContext } from "@fusion/core";
3
+ import { __setCreateAiSessionFactory, combineReviews, runReviewPanel } from "../review-panel.js";
4
+ import type { ReviewPanelMember } from "../review-types.js";
5
+ import { ReviewPanelError } from "../review-types.js";
6
+
7
+ function createContext(createAiSession?: CreateAiSessionFactory): PluginContext {
8
+ return {
9
+ pluginId: "fusion-plugin-reports",
10
+ taskStore: {} as PluginContext["taskStore"],
11
+ settings: {},
12
+ logger: { info: vi.fn(), warn: vi.fn(), error: vi.fn(), debug: vi.fn() },
13
+ emitEvent: vi.fn(),
14
+ createAiSession,
15
+ };
16
+ }
17
+
18
+ const panel: ReviewPanelMember[] = [
19
+ { id: "qa", name: "QA", perspective: "Quality" },
20
+ { id: "ops", name: "Ops", perspective: "Operations" },
21
+ { id: "pm", name: "PM", perspective: "Product" },
22
+ ];
23
+
24
+ afterEach(() => {
25
+ __setCreateAiSessionFactory(undefined);
26
+ vi.restoreAllMocks();
27
+ vi.useRealTimers();
28
+ });
29
+
30
+ describe("runReviewPanel", () => {
31
+ it("returns individual and combined reviews for a 3-member panel", async () => {
32
+ const createAiSession = vi.fn(async ({ systemPrompt }) => ({
33
+ session: {
34
+ prompt: vi.fn(async () => {}),
35
+ state: {
36
+ messages: [{ role: "assistant", content: JSON.stringify({ verdict: "approve", summary: systemPrompt, highlights: ["A"], lowlights: ["B"], suggestions: ["C"] }) }],
37
+ },
38
+ dispose: vi.fn(),
39
+ },
40
+ }));
41
+
42
+ const result = await runReviewPanel({
43
+ reportDraft: "draft",
44
+ reportMetadata: { reportId: "r-1", cadence: "daily", periodStart: "2026-01-01", periodEnd: "2026-01-02" },
45
+ panel,
46
+ cwd: "/tmp",
47
+ }, createContext(createAiSession));
48
+
49
+ expect(result.individual).toHaveLength(3);
50
+ expect(result.failures).toEqual([]);
51
+ expect(result.overallVerdict).toBe("approve");
52
+ expect(result.consensusSummary).toContain("Quality:");
53
+ });
54
+
55
+ it("deduplicates merged arrays in first-seen order", () => {
56
+ const merged = combineReviews([
57
+ { memberId: "a", memberName: "A", perspective: "P1", verdict: "approve", summary: "ok", highlights: [" Alpha ", "Beta"], lowlights: ["Lag"], suggestions: ["Fix docs"], rawText: "", durationMs: 1 },
58
+ { memberId: "b", memberName: "B", perspective: "P2", verdict: "approve", summary: "ok", highlights: ["alpha", "Gamma"], lowlights: [" lag "], suggestions: ["fix docs", "Add tests"], rawText: "", durationMs: 1 },
59
+ ], []);
60
+
61
+ expect(merged.mergedHighlights).toEqual(["Alpha", "Beta", "Gamma"]);
62
+ expect(merged.mergedLowlights).toEqual(["Lag"]);
63
+ expect(merged.mergedSuggestions).toEqual(["Fix docs", "Add tests"]);
64
+ });
65
+
66
+ it("applies verdict precedence", () => {
67
+ const revise = combineReviews([
68
+ { memberId: "a", memberName: "A", perspective: "P1", verdict: "approve", summary: "ok", highlights: [], lowlights: [], suggestions: [], rawText: "", durationMs: 1 },
69
+ { memberId: "b", memberName: "B", perspective: "P2", verdict: "revise", summary: "rev", highlights: [], lowlights: [], suggestions: [], rawText: "", durationMs: 1 },
70
+ ], []);
71
+ expect(revise.overallVerdict).toBe("revise");
72
+
73
+ const reject = combineReviews([
74
+ { memberId: "a", memberName: "A", perspective: "P1", verdict: "approve", summary: "ok", highlights: [], lowlights: [], suggestions: [], rawText: "", durationMs: 1 },
75
+ { memberId: "b", memberName: "B", perspective: "P2", verdict: "reject", summary: "no", highlights: [], lowlights: [], suggestions: [], rawText: "", durationMs: 1 },
76
+ ], []);
77
+ expect(reject.overallVerdict).toBe("reject");
78
+ });
79
+
80
+ it("records timeout failure without aborting other reviewers", async () => {
81
+ vi.useFakeTimers();
82
+ const createAiSession = vi.fn(async ({ systemPrompt }) => {
83
+ if (systemPrompt.includes("Operations")) {
84
+ return {
85
+ session: {
86
+ prompt: vi.fn(async () => new Promise(() => {})),
87
+ state: { messages: [] },
88
+ dispose: vi.fn(),
89
+ },
90
+ };
91
+ }
92
+ return {
93
+ session: {
94
+ prompt: vi.fn(async () => {}),
95
+ state: { messages: [{ role: "assistant", content: JSON.stringify({ verdict: "approve", summary: "ok", highlights: [], lowlights: [], suggestions: [] }) }] },
96
+ dispose: vi.fn(),
97
+ },
98
+ };
99
+ });
100
+
101
+ const promise = runReviewPanel({
102
+ reportDraft: "draft",
103
+ reportMetadata: { reportId: "r-1", cadence: "daily", periodStart: "2026-01-01", periodEnd: "2026-01-02" },
104
+ panel,
105
+ cwd: "/tmp",
106
+ }, createContext(createAiSession));
107
+
108
+ await vi.advanceTimersByTimeAsync(120_000);
109
+ const result = await promise;
110
+
111
+ expect(result.individual).toHaveLength(2);
112
+ expect(result.failures).toHaveLength(1);
113
+ expect(result.failures[0]?.reason).toBe("timeout");
114
+ });
115
+
116
+ it("retries malformed JSON once then reports parse_error", async () => {
117
+ const prompt = vi.fn(async () => {});
118
+ const createAiSession = vi.fn(async () => ({
119
+ session: {
120
+ prompt,
121
+ state: { messages: [{ role: "assistant", content: "not-json" }] },
122
+ dispose: vi.fn(),
123
+ },
124
+ }));
125
+
126
+ const result = await runReviewPanel({
127
+ reportDraft: "draft",
128
+ reportMetadata: { reportId: "r-1", cadence: "daily", periodStart: "2026-01-01", periodEnd: "2026-01-02" },
129
+ panel: [panel[0]],
130
+ cwd: "/tmp",
131
+ }, createContext(createAiSession));
132
+
133
+ expect(prompt).toHaveBeenCalledTimes(2);
134
+ expect(result.individual).toEqual([]);
135
+ expect(result.failures).toHaveLength(1);
136
+ expect(result.failures[0]?.reason).toBe("parse_error");
137
+ });
138
+
139
+ it("throws ReviewPanelError when createAiSession is unavailable", async () => {
140
+ await expect(runReviewPanel({
141
+ reportDraft: "draft",
142
+ reportMetadata: { reportId: "r-1", cadence: "daily", periodStart: "2026-01-01", periodEnd: "2026-01-02" },
143
+ panel,
144
+ cwd: "/tmp",
145
+ }, createContext(undefined))).rejects.toBeInstanceOf(ReviewPanelError);
146
+ });
147
+
148
+ it("forwards provider/modelId to createAiSession per member", async () => {
149
+ const createAiSession = vi.fn(async () => ({
150
+ session: {
151
+ prompt: vi.fn(async () => {}),
152
+ state: { messages: [{ role: "assistant", content: JSON.stringify({ verdict: "approve", summary: "ok", highlights: [], lowlights: [], suggestions: [] }) }] },
153
+ dispose: vi.fn(),
154
+ },
155
+ }));
156
+
157
+ await runReviewPanel({
158
+ reportDraft: "draft",
159
+ reportMetadata: { reportId: "r-1", cadence: "daily", periodStart: "2026-01-01", periodEnd: "2026-01-02" },
160
+ panel: [{ id: "m1", name: "M1", perspective: "P", provider: "anthropic", modelId: "claude" }],
161
+ cwd: "/tmp",
162
+ }, createContext(createAiSession));
163
+
164
+ expect(createAiSession).toHaveBeenCalledWith(expect.objectContaining({ defaultProvider: "anthropic", defaultModelId: "claude" }));
165
+ });
166
+ });
@@ -0,0 +1,157 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import type { PluginSettingType } from "@fusion/plugin-sdk";
3
+ import {
4
+ DEFAULT_ACCENT_COLOR,
5
+ DEFAULT_AUTO_PUBLISH_ON_APPROVAL,
6
+ DEFAULT_BRAND_TITLE,
7
+ DEFAULT_DAILY_CRON,
8
+ DEFAULT_DAILY_ENABLED,
9
+ DEFAULT_ENABLED_SECTIONS,
10
+ DEFAULT_GENERATION_PROMPT_DAILY,
11
+ DEFAULT_GENERATION_PROMPT_WEEKLY,
12
+ DEFAULT_INCLUDE_PER_AGENT_SECTIONS,
13
+ DEFAULT_INCLUDE_SYSTEM_SUMMARY,
14
+ DEFAULT_PUBLISH_TARGETS,
15
+ DEFAULT_REVIEW_BLOCKING_MODE,
16
+ DEFAULT_REVIEW_MIN_APPROVALS,
17
+ DEFAULT_REVIEW_PROMPT,
18
+ DEFAULT_SECTION_ORDER,
19
+ DEFAULT_THEME_MODE,
20
+ DEFAULT_TIMEZONE,
21
+ DEFAULT_WEEKLY_CRON,
22
+ DEFAULT_WEEKLY_ENABLED,
23
+ getAccentColor,
24
+ getApprovalRequired,
25
+ getApproverAgentIds,
26
+ getAutoPublishOnApproval,
27
+ getBrandLogoUrl,
28
+ getBrandTitle,
29
+ getDailyCron,
30
+ getDailyEnabled,
31
+ getEnabledSections,
32
+ getGenerationPromptDaily,
33
+ getGenerationPromptWeekly,
34
+ getIncludePerAgentSections,
35
+ getIncludeSystemSummary,
36
+ getPublishTargets,
37
+ getReviewBlockingMode,
38
+ getReviewMinApprovals,
39
+ getReviewPanelAgentIds,
40
+ getReviewPrompt,
41
+ getSectionOrder,
42
+ getThemeMode,
43
+ getTimezone,
44
+ getWeeklyCron,
45
+ getWeeklyEnabled,
46
+ settingsSchema,
47
+ } from "../settings.js";
48
+
49
+ const VALID_TYPES: PluginSettingType[] = ["string", "number", "boolean", "enum", "password", "array"];
50
+
51
+ describe("reports plugin settings schema", () => {
52
+ it("uses only valid plugin setting types and labels", () => {
53
+ for (const [key, schema] of Object.entries(settingsSchema)) {
54
+ expect(VALID_TYPES).toContain(schema.type);
55
+ expect(typeof schema.label).toBe("string");
56
+ expect(schema.label?.trim().length).toBeGreaterThan(0);
57
+
58
+ if (schema.type === "enum") {
59
+ expect(Array.isArray(schema.enumValues)).toBe(true);
60
+ expect(schema.enumValues?.length ?? 0).toBeGreaterThan(0);
61
+ }
62
+
63
+ if (schema.type === "array") {
64
+ expect(schema.itemType).toBe("string");
65
+ }
66
+
67
+ expect(key.length).toBeGreaterThan(0);
68
+ }
69
+ });
70
+
71
+ it("uses documented literal defaults", () => {
72
+ expect(settingsSchema.dailyCron.defaultValue).toBe("0 8 * * *");
73
+ expect(settingsSchema.weeklyCron.defaultValue).toBe("0 8 * * 1");
74
+ expect(settingsSchema.timezone.defaultValue).toBe("UTC");
75
+ expect(settingsSchema.themeMode.defaultValue).toBe("auto");
76
+ expect(settingsSchema.brandTitle.defaultValue).toBe("Fusion Activity Report");
77
+ });
78
+
79
+ it("returns defaults for empty settings", () => {
80
+ const empty = {};
81
+ expect(getDailyEnabled(empty)).toBe(DEFAULT_DAILY_ENABLED);
82
+ expect(getDailyCron(empty)).toBe(DEFAULT_DAILY_CRON);
83
+ expect(getWeeklyEnabled(empty)).toBe(DEFAULT_WEEKLY_ENABLED);
84
+ expect(getWeeklyCron(empty)).toBe(DEFAULT_WEEKLY_CRON);
85
+ expect(getTimezone(empty)).toBe(DEFAULT_TIMEZONE);
86
+ expect(getGenerationPromptDaily(empty)).toBe(DEFAULT_GENERATION_PROMPT_DAILY);
87
+ expect(getGenerationPromptWeekly(empty)).toBe(DEFAULT_GENERATION_PROMPT_WEEKLY);
88
+ expect(getReviewPrompt(empty)).toBe(DEFAULT_REVIEW_PROMPT);
89
+ expect(getReviewPanelAgentIds(empty)).toEqual([]);
90
+ expect(getReviewMinApprovals(empty)).toBe(DEFAULT_REVIEW_MIN_APPROVALS);
91
+ expect(getReviewBlockingMode(empty)).toBe(DEFAULT_REVIEW_BLOCKING_MODE);
92
+ expect(getSectionOrder(empty)).toEqual(DEFAULT_SECTION_ORDER);
93
+ expect(getEnabledSections(empty)).toEqual(DEFAULT_ENABLED_SECTIONS);
94
+ expect(getIncludeSystemSummary(empty)).toBe(DEFAULT_INCLUDE_SYSTEM_SUMMARY);
95
+ expect(getIncludePerAgentSections(empty)).toBe(DEFAULT_INCLUDE_PER_AGENT_SECTIONS);
96
+ expect(getBrandTitle(empty)).toBe(DEFAULT_BRAND_TITLE);
97
+ expect(getBrandLogoUrl(empty)).toBeUndefined();
98
+ expect(getThemeMode(empty)).toBe(DEFAULT_THEME_MODE);
99
+ expect(getAccentColor(empty)).toBe(DEFAULT_ACCENT_COLOR);
100
+ expect(getApprovalRequired(empty)).toBe(false);
101
+ expect(getAutoPublishOnApproval(empty)).toBe(DEFAULT_AUTO_PUBLISH_ON_APPROVAL);
102
+ expect(getApproverAgentIds(empty)).toEqual([]);
103
+ expect(getPublishTargets(empty)).toEqual(DEFAULT_PUBLISH_TARGETS);
104
+ });
105
+
106
+ it("returns configured values when provided", () => {
107
+ const populated = {
108
+ dailyEnabled: false,
109
+ dailyCron: "5 9 * * *",
110
+ weeklyEnabled: false,
111
+ weeklyCron: "15 7 * * 2",
112
+ timezone: "America/New_York",
113
+ generationPromptDaily: "daily prompt",
114
+ generationPromptWeekly: "weekly prompt",
115
+ reviewPrompt: "review prompt",
116
+ reviewPanelAgentIds: ["agent-a", "agent-b"],
117
+ reviewMinApprovals: 3,
118
+ reviewBlockingMode: "block",
119
+ sectionOrder: ["highlights", "wins"],
120
+ enabledSections: ["wins"],
121
+ includeSystemSummary: false,
122
+ includePerAgentSections: false,
123
+ brandTitle: "Custom Report",
124
+ brandLogoUrl: "https://example.com/logo.png",
125
+ themeMode: "dark",
126
+ accentColor: "#123456",
127
+ approvalRequired: true,
128
+ autoPublishOnApproval: false,
129
+ approverAgentIds: ["approver-a"],
130
+ publishTargets: ["dashboard", "html-export"],
131
+ } satisfies Record<string, unknown>;
132
+
133
+ expect(getDailyEnabled(populated)).toBe(false);
134
+ expect(getDailyCron(populated)).toBe("5 9 * * *");
135
+ expect(getWeeklyEnabled(populated)).toBe(false);
136
+ expect(getWeeklyCron(populated)).toBe("15 7 * * 2");
137
+ expect(getTimezone(populated)).toBe("America/New_York");
138
+ expect(getGenerationPromptDaily(populated)).toBe("daily prompt");
139
+ expect(getGenerationPromptWeekly(populated)).toBe("weekly prompt");
140
+ expect(getReviewPrompt(populated)).toBe("review prompt");
141
+ expect(getReviewPanelAgentIds(populated)).toEqual(["agent-a", "agent-b"]);
142
+ expect(getReviewMinApprovals(populated)).toBe(3);
143
+ expect(getReviewBlockingMode(populated)).toBe("block");
144
+ expect(getSectionOrder(populated)).toEqual(["highlights", "wins"]);
145
+ expect(getEnabledSections(populated)).toEqual(["wins"]);
146
+ expect(getIncludeSystemSummary(populated)).toBe(false);
147
+ expect(getIncludePerAgentSections(populated)).toBe(false);
148
+ expect(getBrandTitle(populated)).toBe("Custom Report");
149
+ expect(getBrandLogoUrl(populated)).toBe("https://example.com/logo.png");
150
+ expect(getThemeMode(populated)).toBe("dark");
151
+ expect(getAccentColor(populated)).toBe("#123456");
152
+ expect(getApprovalRequired(populated)).toBe(true);
153
+ expect(getAutoPublishOnApproval(populated)).toBe(false);
154
+ expect(getApproverAgentIds(populated)).toEqual(["approver-a"]);
155
+ expect(getPublishTargets(populated)).toEqual(["dashboard", "html-export"]);
156
+ });
157
+ });
@@ -0,0 +1,41 @@
1
+ import type { PluginContext } from "@fusion/core";
2
+ import { definePlugin } from "@fusion/plugin-sdk";
3
+ import { runReviewPanel } from "./review-panel.js";
4
+ import type { CombinedReview, ReviewPanelMember, RunReviewPanelInput } from "./review-types.js";
5
+ import { settingsSchema } from "./settings.js";
6
+
7
+ const plugin = definePlugin({
8
+ manifest: {
9
+ id: "fusion-plugin-reports",
10
+ name: "Reports",
11
+ version: "0.1.0",
12
+ description: "Generates beautiful HTML system-activity reports with multi-agent review.",
13
+ author: "Fusion Team",
14
+ fusionVersion: ">=0.1.0",
15
+ settingsSchema,
16
+ },
17
+ state: "installed",
18
+ hooks: {},
19
+ });
20
+
21
+ export interface RunGeneratedReportReviewInput {
22
+ reportDraft: string;
23
+ reportMetadata: RunReviewPanelInput["reportMetadata"];
24
+ panel: ReviewPanelMember[];
25
+ cwd: string;
26
+ }
27
+
28
+ export async function runGeneratedReportReview(input: RunGeneratedReportReviewInput, ctx: PluginContext): Promise<CombinedReview> {
29
+ return runReviewPanel({
30
+ reportDraft: input.reportDraft,
31
+ reportMetadata: input.reportMetadata,
32
+ panel: input.panel,
33
+ cwd: input.cwd,
34
+ }, ctx);
35
+ }
36
+
37
+ export default plugin;
38
+
39
+ export * from "./settings.js";
40
+ export * from "./review-types.js";
41
+ export * from "./review-panel.js";