@runfusion/fusion 0.23.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 (204) hide show
  1. package/dist/bin.js +26610 -20597
  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-DSGQWObq.css → AgentsView-CV3vm7Qk.css} +1 -1
  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-C9lzHrcT.js → DevServerView-BkvtjZBa.js} +1 -1
  9. package/dist/client/assets/{DirectoryPicker-aVdFaV37.js → DirectoryPicker-BK-KbnhP.js} +1 -1
  10. package/dist/client/assets/{DocumentsView-DIpg3NSP.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-nXlTqebk.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-Buopv-jb.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-_BHXUv2j.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-C89Ikhfm.js → SettingsModal-yRqM4DV8.js} +1 -1
  28. package/dist/client/assets/SetupWizardModal-uUZk3TKT.js +1 -0
  29. package/dist/client/assets/{SkillsView-hDpTBdFT.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-usZkXdq2.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-BAT_ObKE.js → star-DYesq1AV.js} +1 -1
  41. package/dist/client/assets/{upload-BC2YKNEV.js → upload-DTWF3Db5.js} +1 -1
  42. package/dist/client/assets/{users-Dkd4rtrN.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 +14287 -9568
  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/package.json +1 -1
  100. package/dist/plugins/fusion-plugin-openclaw-runtime/bundled.js +93 -6
  101. package/dist/plugins/fusion-plugin-openclaw-runtime/mcp-schema-server.cjs +59 -0
  102. package/dist/plugins/fusion-plugin-openclaw-runtime/package.json +1 -1
  103. package/dist/plugins/fusion-plugin-paperclip-runtime/package.json +1 -1
  104. package/dist/plugins/fusion-plugin-reports/manifest.json +33 -0
  105. package/dist/plugins/fusion-plugin-reports/package.json +26 -0
  106. package/dist/plugins/fusion-plugin-reports/src/__tests__/manifest.test.ts +51 -0
  107. package/dist/plugins/fusion-plugin-reports/src/__tests__/review-panel.test.ts +166 -0
  108. package/dist/plugins/fusion-plugin-reports/src/__tests__/settings.test.ts +157 -0
  109. package/dist/plugins/fusion-plugin-reports/src/index.ts +41 -0
  110. package/dist/plugins/fusion-plugin-reports/src/review-panel.ts +294 -0
  111. package/dist/plugins/fusion-plugin-reports/src/review-types.ts +75 -0
  112. package/dist/plugins/fusion-plugin-reports/src/settings.ts +105 -0
  113. package/dist/plugins/fusion-plugin-roadmap/manifest.json +16 -0
  114. package/dist/plugins/fusion-plugin-roadmap/package.json +48 -0
  115. package/dist/plugins/fusion-plugin-roadmap/src/__tests__/api-client.test.ts +101 -0
  116. package/dist/plugins/fusion-plugin-roadmap/src/__tests__/index.test.ts +92 -0
  117. package/dist/plugins/fusion-plugin-roadmap/src/__tests__/roadmap-routes.test.ts +48 -0
  118. package/dist/plugins/fusion-plugin-roadmap/src/__tests__/roadmap-suggestions.test.ts +31 -0
  119. package/dist/plugins/fusion-plugin-roadmap/src/dashboard/RoadmapsView.css +1299 -0
  120. package/dist/plugins/fusion-plugin-roadmap/src/dashboard/RoadmapsView.tsx +2559 -0
  121. package/dist/plugins/fusion-plugin-roadmap/src/dashboard/__tests__/RoadmapsView.test.tsx +1144 -0
  122. package/dist/plugins/fusion-plugin-roadmap/src/dashboard/__tests__/useRoadmaps.test.ts +1756 -0
  123. package/dist/plugins/fusion-plugin-roadmap/src/dashboard/api.ts +70 -0
  124. package/dist/plugins/fusion-plugin-roadmap/src/dashboard/test-setup.ts +7 -0
  125. package/dist/plugins/fusion-plugin-roadmap/src/dashboard/types.ts +1 -0
  126. package/dist/plugins/fusion-plugin-roadmap/src/dashboard/useConfirm.ts +8 -0
  127. package/dist/plugins/fusion-plugin-roadmap/src/dashboard/useRoadmaps.ts +1188 -0
  128. package/dist/plugins/fusion-plugin-roadmap/src/dashboard/useViewportMode.ts +20 -0
  129. package/dist/plugins/fusion-plugin-roadmap/src/dashboard-view.tsx +6 -0
  130. package/dist/plugins/fusion-plugin-roadmap/src/index.ts +74 -0
  131. package/dist/plugins/fusion-plugin-roadmap/src/roadmap-routes.ts +1 -0
  132. package/dist/plugins/fusion-plugin-roadmap/src/roadmap-schema.ts +41 -0
  133. package/dist/plugins/fusion-plugin-roadmap/src/roadmap-suggestions.d.ts +15 -0
  134. package/dist/plugins/fusion-plugin-roadmap/src/roadmap-suggestions.ts +15 -0
  135. package/dist/plugins/fusion-plugin-roadmap/src/roadmap-types.d.ts +283 -0
  136. package/dist/plugins/fusion-plugin-roadmap/src/roadmap-types.d.ts.map +1 -0
  137. package/dist/plugins/fusion-plugin-roadmap/src/roadmap-types.js +21 -0
  138. package/dist/plugins/fusion-plugin-roadmap/src/roadmap-types.js.map +1 -0
  139. package/dist/plugins/fusion-plugin-roadmap/src/roadmap-types.ts +310 -0
  140. package/dist/plugins/fusion-plugin-roadmap/src/routes/roadmap-routes.d.ts +5 -0
  141. package/dist/plugins/fusion-plugin-roadmap/src/routes/roadmap-routes.d.ts.map +1 -0
  142. package/dist/plugins/fusion-plugin-roadmap/src/routes/roadmap-routes.js +361 -0
  143. package/dist/plugins/fusion-plugin-roadmap/src/routes/roadmap-routes.js.map +1 -0
  144. package/dist/plugins/fusion-plugin-roadmap/src/routes/roadmap-routes.ts +408 -0
  145. package/dist/plugins/fusion-plugin-roadmap/src/routes/roadmap-suggestions.d.ts +68 -0
  146. package/dist/plugins/fusion-plugin-roadmap/src/routes/roadmap-suggestions.d.ts.map +1 -0
  147. package/dist/plugins/fusion-plugin-roadmap/src/routes/roadmap-suggestions.js +300 -0
  148. package/dist/plugins/fusion-plugin-roadmap/src/routes/roadmap-suggestions.js.map +1 -0
  149. package/dist/plugins/fusion-plugin-roadmap/src/routes/roadmap-suggestions.ts +381 -0
  150. package/dist/plugins/fusion-plugin-roadmap/src/server/index.d.ts +3 -0
  151. package/dist/plugins/fusion-plugin-roadmap/src/server/index.ts +1 -0
  152. package/dist/plugins/fusion-plugin-roadmap/src/store/__tests__/roadmap-handoff.test.ts +445 -0
  153. package/dist/plugins/fusion-plugin-roadmap/src/store/__tests__/roadmap-ordering.test.ts +334 -0
  154. package/dist/plugins/fusion-plugin-roadmap/src/store/__tests__/roadmap-store.test.ts +1318 -0
  155. package/dist/plugins/fusion-plugin-roadmap/src/store/roadmap-handoff.ts +163 -0
  156. package/dist/plugins/fusion-plugin-roadmap/src/store/roadmap-ordering.d.ts +37 -0
  157. package/dist/plugins/fusion-plugin-roadmap/src/store/roadmap-ordering.d.ts.map +1 -0
  158. package/dist/plugins/fusion-plugin-roadmap/src/store/roadmap-ordering.js +188 -0
  159. package/dist/plugins/fusion-plugin-roadmap/src/store/roadmap-ordering.js.map +1 -0
  160. package/dist/plugins/fusion-plugin-roadmap/src/store/roadmap-ordering.ts +311 -0
  161. package/dist/plugins/fusion-plugin-roadmap/src/store/roadmap-store.d.ts +299 -0
  162. package/dist/plugins/fusion-plugin-roadmap/src/store/roadmap-store.d.ts.map +1 -0
  163. package/dist/plugins/fusion-plugin-roadmap/src/store/roadmap-store.js +765 -0
  164. package/dist/plugins/fusion-plugin-roadmap/src/store/roadmap-store.js.map +1 -0
  165. package/dist/plugins/fusion-plugin-roadmap/src/store/roadmap-store.ts +1001 -0
  166. package/dist/plugins/fusion-plugin-whatsapp-chat/manifest.json +8 -0
  167. package/dist/plugins/fusion-plugin-whatsapp-chat/package.json +34 -0
  168. package/dist/plugins/fusion-plugin-whatsapp-chat/src/__tests__/auth-state.test.ts +99 -0
  169. package/dist/plugins/fusion-plugin-whatsapp-chat/src/__tests__/connection.test.ts +145 -0
  170. package/dist/plugins/fusion-plugin-whatsapp-chat/src/__tests__/index.test.ts +216 -0
  171. package/dist/plugins/fusion-plugin-whatsapp-chat/src/__tests__/reply.test.ts +52 -0
  172. package/dist/plugins/fusion-plugin-whatsapp-chat/src/auth-state.ts +89 -0
  173. package/dist/plugins/fusion-plugin-whatsapp-chat/src/connection.ts +253 -0
  174. package/dist/plugins/fusion-plugin-whatsapp-chat/src/index.ts +262 -0
  175. package/dist/plugins/fusion-plugin-whatsapp-chat/src/qrcode.d.ts +1 -0
  176. package/dist/plugins/fusion-plugin-whatsapp-chat/src/reply.ts +37 -0
  177. package/package.json +2 -2
  178. package/skill/fusion/SKILL.md +2 -2
  179. package/skill/fusion/references/engine-tools.md +3 -0
  180. package/skill/fusion/references/extension-tools.md +39 -0
  181. package/skill/fusion/references/fusion-capabilities.md +3 -0
  182. package/dist/client/assets/AgentDetailView-C1XceMgi.js +0 -18
  183. package/dist/client/assets/AgentDetailView-CeO_1MK7.css +0 -1
  184. package/dist/client/assets/AgentsView-Deh125ss.js +0 -527
  185. package/dist/client/assets/ChatView-7D_RQDqT.js +0 -1
  186. package/dist/client/assets/InsightsView-AWo5o_81.css +0 -1
  187. package/dist/client/assets/InsightsView-jKjEFAx_.js +0 -11
  188. package/dist/client/assets/NodesView-Di2SvOhg.js +0 -14
  189. package/dist/client/assets/NodesView-fXqDk9ur.css +0 -1
  190. package/dist/client/assets/PluginManager-B9-NbQ8f.js +0 -1
  191. package/dist/client/assets/PluginManager-C1DbPaar.css +0 -1
  192. package/dist/client/assets/RoadmapsView-DHWjUoc8.js +0 -6
  193. package/dist/client/assets/SettingsModal-DHitIpsa.css +0 -1
  194. package/dist/client/assets/SettingsModal-DR_yirvK.js +0 -31
  195. package/dist/client/assets/SetupWizardModal-BtDMY9pa.js +0 -1
  196. package/dist/client/assets/agentSkills-B-w5wFHh.js +0 -1
  197. package/dist/client/assets/index-Bc6ZdGMz.css +0 -1
  198. package/dist/client/assets/index-D__RMku8.js +0 -694
  199. package/dist/plugins/fusion-plugin-dependency-graph/src/DependencyGraphView.css +0 -141
  200. package/dist/plugins/fusion-plugin-dependency-graph/src/DependencyGraphView.tsx +0 -428
  201. package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/DependencyGraphView.test.tsx +0 -261
  202. package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/storage.test.ts +0 -41
  203. package/dist/plugins/fusion-plugin-dependency-graph/src/storage.ts +0 -22
  204. /package/dist/client/assets/{RoadmapsView-DdGlfuu-.css → dashboard-view-DdGlfuu-.css} +0 -0
@@ -1,261 +0,0 @@
1
- import { describe, expect, it, vi, beforeEach, afterEach } from "vitest";
2
- import { render, fireEvent, screen, act, cleanup } from "@testing-library/react";
3
- import * as React from "react";
4
- import { DependencyGraphView } from "../DependencyGraphView";
5
- import type { DependencyGraphHostContext, PluginDashboardViewComponentProps } from "../DependencyGraphView";
6
- import type { Task } from "@fusion/core";
7
-
8
- // Mock storage to avoid localStorage dependency
9
- vi.mock("../storage", () => ({
10
- loadPositions: () => ({}),
11
- savePositions: () => {},
12
- }));
13
-
14
- // Helper to create a minimal Task
15
- function createTask(overrides: Partial<Task> & { id: string; column: Task["column"] }): Task {
16
- return {
17
- description: overrides.description ?? `Task ${overrides.id}`,
18
- column: overrides.column,
19
- dependencies: overrides.dependencies ?? [],
20
- steps: overrides.steps ?? [],
21
- currentStep: overrides.currentStep ?? 0,
22
- log: overrides.log ?? [],
23
- ...overrides,
24
- } as Task;
25
- }
26
-
27
- function createMockContext(tasks: Task[] = []): DependencyGraphHostContext {
28
- return {
29
- projectId: "test-project",
30
- tasks,
31
- openTaskDetail: vi.fn(),
32
- renderTaskCard: (task: Task) => React.createElement("div", { "data-testid": "task-card" }, task.id),
33
- };
34
- }
35
-
36
- function renderView(context?: DependencyGraphHostContext) {
37
- const props: PluginDashboardViewComponentProps = {
38
- context: context ?? createMockContext(),
39
- };
40
- return render(React.createElement(DependencyGraphView, props));
41
- }
42
-
43
- describe("DependencyGraphView", () => {
44
- beforeEach(() => {
45
- // Mock getComputedStyle for rem calculations
46
- vi.spyOn(window, "getComputedStyle").mockImplementation((() => {
47
- return { fontSize: "16px" } as CSSStyleDeclaration;
48
- }) as typeof window.getComputedStyle);
49
-
50
- // Mock matchMedia to default to desktop
51
- window.matchMedia = vi.fn().mockImplementation((query: string) => ({
52
- matches: false,
53
- media: query,
54
- onchange: null,
55
- addListener: vi.fn(),
56
- removeListener: vi.fn(),
57
- addEventListener: vi.fn(),
58
- removeEventListener: vi.fn(),
59
- dispatchEvent: vi.fn(),
60
- }));
61
- });
62
-
63
- afterEach(() => {
64
- cleanup();
65
- vi.restoreAllMocks();
66
- });
67
-
68
- it("renders empty state when no active-column tasks provided", () => {
69
- const { container } = renderView(createMockContext([]));
70
- const empty = container.querySelector(".dependency-graph-empty");
71
- expect(empty).toBeTruthy();
72
- expect(empty?.textContent).toContain("No tasks to display");
73
- });
74
-
75
- it("renders nodes for active-column tasks", () => {
76
- const tasks = [
77
- createTask({ id: "FN-001", column: "todo" }),
78
- createTask({ id: "FN-002", column: "in-progress" }),
79
- ];
80
- const { container } = renderView(createMockContext(tasks));
81
- const nodes = container.querySelectorAll(".dependency-graph-node");
82
- expect(nodes.length).toBe(2);
83
- });
84
-
85
- it("filters out tasks not in active columns", () => {
86
- const tasks = [
87
- createTask({ id: "FN-001", column: "todo" }),
88
- createTask({ id: "FN-002", column: "done" }),
89
- createTask({ id: "FN-003", column: "archived" }),
90
- ];
91
- const { container } = renderView(createMockContext(tasks));
92
- const nodes = container.querySelectorAll(".dependency-graph-node");
93
- expect(nodes.length).toBe(1);
94
- });
95
-
96
- it("renders edges for tasks with dependencies in the active set", () => {
97
- const tasks = [
98
- createTask({ id: "FN-001", column: "todo" }),
99
- createTask({ id: "FN-002", column: "todo", dependencies: ["FN-001"] }),
100
- ];
101
- const { container } = renderView(createMockContext(tasks));
102
- const edges = container.querySelectorAll(".dependency-graph-edge");
103
- expect(edges.length).toBe(1);
104
- });
105
-
106
- it("does not render edges for dependencies not in the active set", () => {
107
- const tasks = [
108
- createTask({ id: "FN-002", column: "todo", dependencies: ["FN-999"] }),
109
- ];
110
- const { container } = renderView(createMockContext(tasks));
111
- const edges = container.querySelectorAll(".dependency-graph-edge");
112
- expect(edges.length).toBe(0);
113
- });
114
-
115
- it("zoom-in button increases scale", () => {
116
- const tasks = [createTask({ id: "FN-001", column: "todo" })];
117
- const { container, unmount } = renderView(createMockContext(tasks));
118
- const zoomInBtn = Array.from(container.querySelectorAll("button")).find((b) => b.textContent === "Zoom In")!;
119
- fireEvent.click(zoomInBtn);
120
- const scene = container.querySelector(".dependency-graph-scene") as HTMLElement;
121
- expect(scene).toBeTruthy();
122
- const transform = scene.style.transform;
123
- expect(transform).toMatch(/scale\([1-9]/);
124
- });
125
-
126
- it("zoom-out button decreases scale", () => {
127
- const tasks = [createTask({ id: "FN-001", column: "todo" })];
128
- const { container, unmount } = renderView(createMockContext(tasks));
129
- const zoomOutBtn = Array.from(container.querySelectorAll("button")).find((b) => b.textContent === "Zoom Out")!;
130
- fireEvent.click(zoomOutBtn);
131
- const scene = container.querySelector(".dependency-graph-scene") as HTMLElement;
132
- expect(scene).toBeTruthy();
133
- const transform = scene.style.transform;
134
- expect(transform).toMatch(/scale\(0\./);
135
- });
136
-
137
- it("fit-to-graph button produces a valid scale", () => {
138
- const tasks = [createTask({ id: "FN-001", column: "todo" })];
139
- const { container, unmount } = renderView(createMockContext(tasks));
140
-
141
- // Mock canvas dimensions for fitToGraph
142
- const canvas = container.querySelector(".dependency-graph-canvas") as HTMLElement;
143
- if (canvas) {
144
- Object.defineProperty(canvas, "clientWidth", { value: 800, configurable: true });
145
- Object.defineProperty(canvas, "clientHeight", { value: 600, configurable: true });
146
- }
147
-
148
- const fitBtn = Array.from(container.querySelectorAll("button")).find((b) => b.textContent === "Fit")!;
149
- fireEvent.click(fitBtn);
150
-
151
- const scene = container.querySelector(".dependency-graph-scene") as HTMLElement;
152
- expect(scene).toBeTruthy();
153
- const transform = scene.style.transform;
154
- const scaleMatch = transform.match(/scale\(([\d.]+)\)/);
155
- expect(scaleMatch).toBeTruthy();
156
- const scaleValue = parseFloat(scaleMatch![1]);
157
- expect(scaleValue).toBeGreaterThanOrEqual(0.4);
158
- expect(scaleValue).toBeLessThanOrEqual(2);
159
- });
160
-
161
- it("wheel event zooms the graph", () => {
162
- const tasks = [createTask({ id: "FN-001", column: "todo" })];
163
- const { container } = renderView(createMockContext(tasks));
164
- const canvas = container.querySelector(".dependency-graph-canvas") as HTMLElement;
165
-
166
- expect(canvas).toBeTruthy();
167
-
168
- // Mock getBoundingClientRect on the canvas
169
- canvas.getBoundingClientRect = vi.fn().mockReturnValue({
170
- left: 0, top: 0, right: 800, bottom: 600, width: 800, height: 600, x: 0, y: 0,
171
- });
172
-
173
- const initialScene = container.querySelector(".dependency-graph-scene") as HTMLElement;
174
- const initialTransform = initialScene.style.transform;
175
-
176
- // Negative deltaY = zoom in
177
- fireEvent.wheel(canvas, { deltaY: -100, clientX: 400, clientY: 300 });
178
-
179
- const updatedScene = container.querySelector(".dependency-graph-scene") as HTMLElement;
180
- const updatedTransform = updatedScene.style.transform;
181
-
182
- expect(updatedTransform).not.toBe(initialTransform);
183
- const scaleMatch = updatedTransform.match(/scale\(([\d.]+)\)/);
184
- expect(scaleMatch).toBeTruthy();
185
- expect(parseFloat(scaleMatch![1])).toBeGreaterThan(1);
186
- });
187
-
188
- it("pinch gesture changes scale", () => {
189
- const tasks = [createTask({ id: "FN-001", column: "todo" })];
190
- const { container } = renderView(createMockContext(tasks));
191
- const canvas = container.querySelector(".dependency-graph-canvas") as HTMLElement;
192
-
193
- expect(canvas).toBeTruthy();
194
-
195
- // First pointer down (finger 1)
196
- fireEvent.pointerDown(canvas, {
197
- pointerId: 1,
198
- pointerType: "touch",
199
- button: 0,
200
- clientX: 200,
201
- clientY: 300,
202
- });
203
-
204
- // Second pointer down (finger 2) — starts pinch
205
- fireEvent.pointerDown(canvas, {
206
- pointerId: 2,
207
- pointerType: "touch",
208
- button: 0,
209
- clientX: 600,
210
- clientY: 300,
211
- });
212
-
213
- // Move fingers apart (increasing distance)
214
- fireEvent.pointerMove(canvas, {
215
- pointerId: 1,
216
- pointerType: "touch",
217
- clientX: 100,
218
- clientY: 300,
219
- });
220
-
221
- fireEvent.pointerMove(canvas, {
222
- pointerId: 2,
223
- pointerType: "touch",
224
- clientX: 700,
225
- clientY: 300,
226
- });
227
-
228
- const scene = container.querySelector(".dependency-graph-scene") as HTMLElement;
229
- const transform = scene.style.transform;
230
- const scaleMatch = transform.match(/scale\(([\d.]+)\)/);
231
- expect(scaleMatch).toBeTruthy();
232
- expect(parseFloat(scaleMatch![1])).toBeGreaterThan(1);
233
- });
234
-
235
- it("scale is clamped between MIN_SCALE and MAX_SCALE", () => {
236
- const tasks = [createTask({ id: "FN-001", column: "todo" })];
237
- const { container, unmount } = renderView(createMockContext(tasks));
238
-
239
- // Try to zoom in beyond MAX_SCALE (2.0)
240
- const zoomInBtn = Array.from(container.querySelectorAll("button")).find((b) => b.textContent === "Zoom In")!;
241
- for (let i = 0; i < 50; i++) {
242
- fireEvent.click(zoomInBtn);
243
- }
244
-
245
- const scene = container.querySelector(".dependency-graph-scene") as HTMLElement;
246
- let scaleMatch = scene.style.transform.match(/scale\(([\d.]+)\)/);
247
- expect(scaleMatch).toBeTruthy();
248
- expect(parseFloat(scaleMatch![1])).toBeLessThanOrEqual(2);
249
-
250
- // Try to zoom out beyond MIN_SCALE (0.4)
251
- const zoomOutBtn = Array.from(container.querySelectorAll("button")).find((b) => b.textContent === "Zoom Out")!;
252
- for (let i = 0; i < 100; i++) {
253
- fireEvent.click(zoomOutBtn);
254
- }
255
-
256
- const updatedScene = container.querySelector(".dependency-graph-scene") as HTMLElement;
257
- scaleMatch = updatedScene.style.transform.match(/scale\(([\d.]+)\)/);
258
- expect(scaleMatch).toBeTruthy();
259
- expect(parseFloat(scaleMatch![1])).toBeGreaterThanOrEqual(0.4);
260
- });
261
- });
@@ -1,41 +0,0 @@
1
- import { describe, expect, it, beforeEach } from "vitest";
2
- import { projectScopedKey, loadPositions, savePositions } from "../storage";
3
-
4
- const createMemoryStorage = () => {
5
- const map = new Map<string, string>();
6
- return {
7
- getItem: (key: string) => map.get(key) ?? null,
8
- setItem: (key: string, value: string) => {
9
- map.set(key, value);
10
- },
11
- clear: () => map.clear(),
12
- };
13
- };
14
-
15
- describe("storage", () => {
16
- const localStorage = createMemoryStorage();
17
-
18
- beforeEach(() => {
19
- (globalThis as { window?: { localStorage?: typeof localStorage } }).window = { localStorage };
20
- localStorage.clear();
21
- });
22
-
23
- it("builds project-scoped key with canonical base key", () => {
24
- expect(projectScopedKey("proj_123")).toBe("kb:proj_123:fusion-plugin-dependency-graph:positions");
25
- });
26
-
27
- it("falls back to unscoped key when projectId is missing or empty", () => {
28
- expect(projectScopedKey()).toBe("fusion-plugin-dependency-graph:positions");
29
- expect(projectScopedKey("")).toBe("fusion-plugin-dependency-graph:positions");
30
- });
31
-
32
- it("persists and restores positions", () => {
33
- savePositions("proj_123", { "FN-1": { x: 10, y: 20 } });
34
- expect(loadPositions("proj_123")).toEqual({ "FN-1": { x: 10, y: 20 } });
35
- });
36
-
37
- it("returns empty object for invalid JSON", () => {
38
- localStorage.setItem("kb:proj_123:fusion-plugin-dependency-graph:positions", "not-json");
39
- expect(loadPositions("proj_123")).toEqual({});
40
- });
41
- });
@@ -1,22 +0,0 @@
1
- import { getScopedItem, scopedKey, setScopedItem } from "../../../packages/dashboard/app/utils/projectStorage";
2
-
3
- const BASE_KEY = "fusion-plugin-dependency-graph:positions";
4
-
5
- export function projectScopedKey(projectId?: string): string {
6
- return scopedKey(BASE_KEY, projectId);
7
- }
8
-
9
- export function loadPositions(projectId?: string): Record<string, { x: number; y: number }> {
10
- try {
11
- const raw = getScopedItem(BASE_KEY, projectId);
12
- if (!raw) return {};
13
- const parsed = JSON.parse(raw) as Record<string, { x: number; y: number }>;
14
- return parsed ?? {};
15
- } catch {
16
- return {};
17
- }
18
- }
19
-
20
- export function savePositions(projectId: string | undefined, positions: Record<string, { x: number; y: number }>): void {
21
- setScopedItem(BASE_KEY, JSON.stringify(positions), projectId);
22
- }