@runfusion/fusion 0.24.0 → 0.26.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 (167) hide show
  1. package/README.md +6 -0
  2. package/dist/bin.js +18646 -15669
  3. package/dist/client/assets/AgentDetailView-Cv-vgOj3.js +18 -0
  4. package/dist/client/assets/{AgentsView-BkB9FiMT.js → AgentsView-D6Zi5zfP.js} +4 -4
  5. package/dist/client/assets/ChatView-CAHjY9uO.js +1 -0
  6. package/dist/client/assets/{DevServerView-BkvtjZBa.js → DevServerView--_WBvIDQ.js} +1 -1
  7. package/dist/client/assets/{DirectoryPicker-BK-KbnhP.js → DirectoryPicker-xedtR-Rd.js} +1 -1
  8. package/dist/client/assets/{DocumentsView-BEg1CQAk.js → DocumentsView-Bg2oaZks.js} +1 -1
  9. package/dist/client/assets/{EvalsView-Berf9bQm.js → EvalsView-B3uOCXfr.js} +1 -1
  10. package/dist/client/assets/{ExperimentalAgentOnboardingModal-jcInE50G.js → ExperimentalAgentOnboardingModal-Bx6yXVS5.js} +1 -1
  11. package/dist/client/assets/{InsightsView-BX5bSF1J.js → InsightsView-Q1zvtF4F.js} +1 -1
  12. package/dist/client/assets/MemoryView-xcN_eouf.js +2 -0
  13. package/dist/client/assets/MemoryView-zaXewZzi.css +1 -0
  14. package/dist/client/assets/{NodesView-DLUOBLf6.js → NodesView-RxXg58_Q.js} +1 -1
  15. package/dist/client/assets/{PiExtensionsManager-COlJf0Kx.js → PiExtensionsManager-Cc8aAZXg.js} +2 -2
  16. package/dist/client/assets/PluginManager-BEkyBajl.js +1 -0
  17. package/dist/client/assets/{ResearchView-BzCcDAS4.css → ResearchView-BEI4ZSGs.css} +1 -1
  18. package/dist/client/assets/ResearchView-CERNf7sJ.js +1 -0
  19. package/dist/client/assets/{SettingsModal-yRqM4DV8.js → SettingsModal-B1r0yASu.js} +1 -1
  20. package/dist/client/assets/SettingsModal-BLsac7CJ.js +31 -0
  21. package/dist/client/assets/SettingsModal-Cis-4Lot.css +1 -0
  22. package/dist/client/assets/{SetupWizardModal-uUZk3TKT.js → SetupWizardModal-D1q548_L.js} +1 -1
  23. package/dist/client/assets/{SkillsView-CP8JX0P_.js → SkillsView-ClLM6u6p.js} +1 -1
  24. package/dist/client/assets/StashRecoveryView-B_8WIQEo.css +1 -0
  25. package/dist/client/assets/StashRecoveryView-ze0pEZ5U.js +1 -0
  26. package/dist/client/assets/{TodoView-DCRIkDZ-.js → TodoView-CTmIfy2M.js} +1 -1
  27. package/dist/client/assets/{dashboard-view-lR7YYmSC.js → dashboard-view-4xAN3yO5.js} +2 -2
  28. package/dist/client/assets/{folder-open-DHjELt8-.js → folder-open-BZuKESeq.js} +1 -1
  29. package/dist/client/assets/index-Bdw6llW6.js +692 -0
  30. package/dist/client/assets/index-CZGlyJuS.css +1 -0
  31. package/dist/client/assets/{star-DYesq1AV.js → star-D75YKEq-.js} +1 -1
  32. package/dist/client/assets/{upload-DTWF3Db5.js → upload-BYYTgWFj.js} +1 -1
  33. package/dist/client/assets/{users--syrel4l.js → users-RS90Aii3.js} +1 -1
  34. package/dist/client/index.html +2 -2
  35. package/dist/client/version.json +1 -1
  36. package/dist/droid-cli/package.json +1 -1
  37. package/dist/extension.js +5640 -3618
  38. package/dist/pi-claude-cli/package.json +1 -1
  39. package/dist/plugins/fusion-plugin-cli-printing-press/manifest.json +6 -0
  40. package/dist/plugins/fusion-plugin-cli-printing-press/package.json +26 -0
  41. package/dist/plugins/fusion-plugin-cli-printing-press/src/__tests__/manifest.test.ts +20 -0
  42. package/dist/plugins/fusion-plugin-cli-printing-press/src/index.ts +14 -0
  43. package/dist/plugins/fusion-plugin-cursor-runtime/bundled.js +9 -11
  44. package/dist/plugins/fusion-plugin-cursor-runtime/package.json +1 -1
  45. package/dist/plugins/fusion-plugin-dependency-graph/bundled.js +30 -0
  46. package/dist/plugins/fusion-plugin-dependency-graph/package.json +3 -28
  47. package/dist/plugins/fusion-plugin-droid-runtime/bundled.js +899 -895
  48. package/dist/plugins/fusion-plugin-droid-runtime/package.json +1 -1
  49. package/dist/plugins/fusion-plugin-hermes-runtime/bundled.js +68 -71
  50. package/dist/plugins/fusion-plugin-hermes-runtime/package.json +1 -1
  51. package/dist/plugins/fusion-plugin-openclaw-runtime/bundled.js +47 -50
  52. package/dist/plugins/fusion-plugin-openclaw-runtime/package.json +1 -1
  53. package/dist/plugins/fusion-plugin-paperclip-runtime/bundled.js +155 -109
  54. package/dist/plugins/fusion-plugin-paperclip-runtime/package.json +1 -1
  55. package/dist/plugins/fusion-plugin-reports/package.json +1 -1
  56. package/dist/plugins/fusion-plugin-reports/src/index.ts +49 -3
  57. package/dist/plugins/fusion-plugin-reports/src/report-schema.ts +38 -0
  58. package/dist/plugins/fusion-plugin-reports/src/store/__tests__/report-schema.test.ts +66 -0
  59. package/dist/plugins/fusion-plugin-reports/src/store/__tests__/report-store.test.ts +177 -0
  60. package/dist/plugins/fusion-plugin-reports/src/store/report-store.ts +341 -0
  61. package/dist/plugins/fusion-plugin-reports/src/store/report-types.ts +77 -0
  62. package/dist/plugins/fusion-plugin-roadmap/{src/dashboard/RoadmapsView.css → bundled.css} +13 -219
  63. package/dist/plugins/fusion-plugin-roadmap/bundled.js +29535 -0
  64. package/dist/plugins/fusion-plugin-roadmap/package.json +4 -41
  65. package/dist/plugins/fusion-plugin-whatsapp-chat/package.json +1 -1
  66. package/package.json +2 -3
  67. package/dist/client/assets/AgentDetailView-gy_5SUj2.js +0 -18
  68. package/dist/client/assets/ChatView-B_-B8fqu.js +0 -1
  69. package/dist/client/assets/MemoryView-CKElJY_3.js +0 -2
  70. package/dist/client/assets/MemoryView-DiajLXby.css +0 -1
  71. package/dist/client/assets/PluginManager-CfW55BF4.js +0 -1
  72. package/dist/client/assets/ResearchView-B256Lr8I.js +0 -1
  73. package/dist/client/assets/SettingsModal-BeA_nQtW.js +0 -31
  74. package/dist/client/assets/SettingsModal-DzsLquBu.css +0 -1
  75. package/dist/client/assets/index-CQyVRLOb.js +0 -692
  76. package/dist/client/assets/index-CxA2Nn0_.css +0 -1
  77. package/dist/plugins/fusion-plugin-dependency-graph/src/DependencyGraph.css +0 -58
  78. package/dist/plugins/fusion-plugin-dependency-graph/src/DependencyGraph.tsx +0 -301
  79. package/dist/plugins/fusion-plugin-dependency-graph/src/GraphHighlight.css +0 -27
  80. package/dist/plugins/fusion-plugin-dependency-graph/src/GraphTaskNode.css +0 -157
  81. package/dist/plugins/fusion-plugin-dependency-graph/src/GraphTaskNode.tsx +0 -126
  82. package/dist/plugins/fusion-plugin-dependency-graph/src/GraphToolbar.css +0 -35
  83. package/dist/plugins/fusion-plugin-dependency-graph/src/GraphToolbar.tsx +0 -36
  84. package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/DependencyGraph.highlighting.test.tsx +0 -112
  85. package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/DependencyGraph.persistence.test.tsx +0 -115
  86. package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/DependencyGraph.test.tsx +0 -128
  87. package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/GraphTaskNode.drag.test.tsx +0 -82
  88. package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/GraphTaskNode.test.tsx +0 -307
  89. package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/GraphToolbar.test.tsx +0 -60
  90. package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/edges.test.tsx +0 -75
  91. package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/filtering.test.tsx +0 -62
  92. package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/filters.test.ts +0 -78
  93. package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/graphPositionStorage.test.ts +0 -95
  94. package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/host-integration.test.ts +0 -74
  95. package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/index.test.ts +0 -58
  96. package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/interactions.test.tsx +0 -121
  97. package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/layout.test.ts +0 -70
  98. package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/persistence.test.tsx +0 -89
  99. package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/useGraphData.test.ts +0 -86
  100. package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/useGraphInteraction.test.ts +0 -167
  101. package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/useGraphPositions.test.ts +0 -66
  102. package/dist/plugins/fusion-plugin-dependency-graph/src/__tests__/useNodeDrag.test.ts +0 -81
  103. package/dist/plugins/fusion-plugin-dependency-graph/src/dashboard-interop.d.ts +0 -35
  104. package/dist/plugins/fusion-plugin-dependency-graph/src/dashboard-view.tsx +0 -19
  105. package/dist/plugins/fusion-plugin-dependency-graph/src/edges.tsx +0 -70
  106. package/dist/plugins/fusion-plugin-dependency-graph/src/filters.ts +0 -8
  107. package/dist/plugins/fusion-plugin-dependency-graph/src/hooks/__tests__/useDependencyChain.test.ts +0 -53
  108. package/dist/plugins/fusion-plugin-dependency-graph/src/hooks/useDependencyChain.ts +0 -60
  109. package/dist/plugins/fusion-plugin-dependency-graph/src/hooks/useGraphPositions.ts +0 -45
  110. package/dist/plugins/fusion-plugin-dependency-graph/src/hooks/useNodeDrag.ts +0 -114
  111. package/dist/plugins/fusion-plugin-dependency-graph/src/index.ts +0 -24
  112. package/dist/plugins/fusion-plugin-dependency-graph/src/layout.ts +0 -91
  113. package/dist/plugins/fusion-plugin-dependency-graph/src/styles/drag.css +0 -15
  114. package/dist/plugins/fusion-plugin-dependency-graph/src/types.ts +0 -21
  115. package/dist/plugins/fusion-plugin-dependency-graph/src/useGraphData.ts +0 -17
  116. package/dist/plugins/fusion-plugin-dependency-graph/src/useGraphInteraction.ts +0 -292
  117. package/dist/plugins/fusion-plugin-dependency-graph/src/utils/graphPositionStorage.ts +0 -65
  118. package/dist/plugins/fusion-plugin-roadmap/src/__tests__/api-client.test.ts +0 -101
  119. package/dist/plugins/fusion-plugin-roadmap/src/__tests__/index.test.ts +0 -92
  120. package/dist/plugins/fusion-plugin-roadmap/src/__tests__/roadmap-routes.test.ts +0 -48
  121. package/dist/plugins/fusion-plugin-roadmap/src/__tests__/roadmap-suggestions.test.ts +0 -31
  122. package/dist/plugins/fusion-plugin-roadmap/src/dashboard/RoadmapsView.tsx +0 -2559
  123. package/dist/plugins/fusion-plugin-roadmap/src/dashboard/__tests__/RoadmapsView.test.tsx +0 -1144
  124. package/dist/plugins/fusion-plugin-roadmap/src/dashboard/__tests__/useRoadmaps.test.ts +0 -1756
  125. package/dist/plugins/fusion-plugin-roadmap/src/dashboard/api.ts +0 -70
  126. package/dist/plugins/fusion-plugin-roadmap/src/dashboard/test-setup.ts +0 -7
  127. package/dist/plugins/fusion-plugin-roadmap/src/dashboard/types.ts +0 -1
  128. package/dist/plugins/fusion-plugin-roadmap/src/dashboard/useConfirm.ts +0 -8
  129. package/dist/plugins/fusion-plugin-roadmap/src/dashboard/useRoadmaps.ts +0 -1188
  130. package/dist/plugins/fusion-plugin-roadmap/src/dashboard/useViewportMode.ts +0 -20
  131. package/dist/plugins/fusion-plugin-roadmap/src/dashboard-view.tsx +0 -6
  132. package/dist/plugins/fusion-plugin-roadmap/src/index.ts +0 -74
  133. package/dist/plugins/fusion-plugin-roadmap/src/roadmap-routes.ts +0 -1
  134. package/dist/plugins/fusion-plugin-roadmap/src/roadmap-schema.ts +0 -41
  135. package/dist/plugins/fusion-plugin-roadmap/src/roadmap-suggestions.d.ts +0 -15
  136. package/dist/plugins/fusion-plugin-roadmap/src/roadmap-suggestions.ts +0 -15
  137. package/dist/plugins/fusion-plugin-roadmap/src/roadmap-types.d.ts +0 -283
  138. package/dist/plugins/fusion-plugin-roadmap/src/roadmap-types.d.ts.map +0 -1
  139. package/dist/plugins/fusion-plugin-roadmap/src/roadmap-types.js +0 -21
  140. package/dist/plugins/fusion-plugin-roadmap/src/roadmap-types.js.map +0 -1
  141. package/dist/plugins/fusion-plugin-roadmap/src/roadmap-types.ts +0 -310
  142. package/dist/plugins/fusion-plugin-roadmap/src/routes/roadmap-routes.d.ts +0 -5
  143. package/dist/plugins/fusion-plugin-roadmap/src/routes/roadmap-routes.d.ts.map +0 -1
  144. package/dist/plugins/fusion-plugin-roadmap/src/routes/roadmap-routes.js +0 -361
  145. package/dist/plugins/fusion-plugin-roadmap/src/routes/roadmap-routes.js.map +0 -1
  146. package/dist/plugins/fusion-plugin-roadmap/src/routes/roadmap-routes.ts +0 -408
  147. package/dist/plugins/fusion-plugin-roadmap/src/routes/roadmap-suggestions.d.ts +0 -68
  148. package/dist/plugins/fusion-plugin-roadmap/src/routes/roadmap-suggestions.d.ts.map +0 -1
  149. package/dist/plugins/fusion-plugin-roadmap/src/routes/roadmap-suggestions.js +0 -300
  150. package/dist/plugins/fusion-plugin-roadmap/src/routes/roadmap-suggestions.js.map +0 -1
  151. package/dist/plugins/fusion-plugin-roadmap/src/routes/roadmap-suggestions.ts +0 -381
  152. package/dist/plugins/fusion-plugin-roadmap/src/server/index.d.ts +0 -3
  153. package/dist/plugins/fusion-plugin-roadmap/src/server/index.ts +0 -1
  154. package/dist/plugins/fusion-plugin-roadmap/src/store/__tests__/roadmap-handoff.test.ts +0 -445
  155. package/dist/plugins/fusion-plugin-roadmap/src/store/__tests__/roadmap-ordering.test.ts +0 -334
  156. package/dist/plugins/fusion-plugin-roadmap/src/store/__tests__/roadmap-store.test.ts +0 -1318
  157. package/dist/plugins/fusion-plugin-roadmap/src/store/roadmap-handoff.ts +0 -163
  158. package/dist/plugins/fusion-plugin-roadmap/src/store/roadmap-ordering.d.ts +0 -37
  159. package/dist/plugins/fusion-plugin-roadmap/src/store/roadmap-ordering.d.ts.map +0 -1
  160. package/dist/plugins/fusion-plugin-roadmap/src/store/roadmap-ordering.js +0 -188
  161. package/dist/plugins/fusion-plugin-roadmap/src/store/roadmap-ordering.js.map +0 -1
  162. package/dist/plugins/fusion-plugin-roadmap/src/store/roadmap-ordering.ts +0 -311
  163. package/dist/plugins/fusion-plugin-roadmap/src/store/roadmap-store.d.ts +0 -299
  164. package/dist/plugins/fusion-plugin-roadmap/src/store/roadmap-store.d.ts.map +0 -1
  165. package/dist/plugins/fusion-plugin-roadmap/src/store/roadmap-store.js +0 -765
  166. package/dist/plugins/fusion-plugin-roadmap/src/store/roadmap-store.js.map +0 -1
  167. package/dist/plugins/fusion-plugin-roadmap/src/store/roadmap-store.ts +0 -1001
@@ -1,445 +0,0 @@
1
- /**
2
- * Tests for roadmap handoff mapping helpers.
3
- */
4
-
5
- import { describe, it, expect } from "vitest";
6
- import {
7
- mapFeatureToTaskHandoff,
8
- mapRoadmapToMissionHandoff,
9
- mapRoadmapWithHierarchyToMissionHandoff,
10
- mapAllFeaturesToTaskHandoffs,
11
- } from "../roadmap-handoff.js";
12
- import { normalizeRoadmapMilestoneOrder } from "../roadmap-ordering.js";
13
- import type {
14
- Roadmap,
15
- RoadmapMilestone,
16
- RoadmapFeature,
17
- RoadmapWithHierarchy,
18
- RoadmapFeatureTaskPlanningHandoff,
19
- RoadmapMissionPlanningHandoff,
20
- } from "../../roadmap-types.js";
21
-
22
- // ── Test Fixtures ─────────────────────────────────────────────────────────────
23
-
24
- function createRoadmap(overrides: Partial<Roadmap> = {}): Roadmap {
25
- return {
26
- id: "RM-001",
27
- title: "Test Roadmap",
28
- description: "A test roadmap",
29
- createdAt: "2024-01-01T00:00:00.000Z",
30
- updatedAt: "2024-01-01T00:00:00.000Z",
31
- ...overrides,
32
- };
33
- }
34
-
35
- function createMilestone(id: string, roadmapId: string, orderIndex: number, overrides: Partial<RoadmapMilestone> = {}): RoadmapMilestone {
36
- return {
37
- id,
38
- roadmapId,
39
- title: `Milestone ${id}`,
40
- description: `Description for ${id}`,
41
- orderIndex,
42
- createdAt: "2024-01-01T00:00:00.000Z",
43
- updatedAt: "2024-01-01T00:00:00.000Z",
44
- ...overrides,
45
- };
46
- }
47
-
48
- function createFeature(id: string, milestoneId: string, orderIndex: number, overrides: Partial<RoadmapFeature> = {}): RoadmapFeature {
49
- return {
50
- id,
51
- milestoneId,
52
- title: `Feature ${id}`,
53
- description: `Description for ${id}`,
54
- orderIndex,
55
- createdAt: "2024-01-01T00:00:00.000Z",
56
- updatedAt: "2024-01-01T00:00:00.000Z",
57
- ...overrides,
58
- };
59
- }
60
-
61
- // ── Tests for mapFeatureToTaskHandoff ─────────────────────────────────────────
62
-
63
- describe("mapFeatureToTaskHandoff", () => {
64
- it("maps a feature to a task planning handoff with all fields", () => {
65
- const roadmap = createRoadmap();
66
- const milestone = createMilestone("MS-001", "RM-001", 0);
67
- const feature = createFeature("F-001", "MS-001", 0);
68
-
69
- const handoff = mapFeatureToTaskHandoff(roadmap, milestone, feature);
70
-
71
- expect(handoff.title).toBe("Feature F-001");
72
- expect(handoff.description).toBe("Description for F-001");
73
- expect(handoff.source.roadmapId).toBe("RM-001");
74
- expect(handoff.source.milestoneId).toBe("MS-001");
75
- expect(handoff.source.featureId).toBe("F-001");
76
- expect(handoff.source.roadmapTitle).toBe("Test Roadmap");
77
- expect(handoff.source.milestoneTitle).toBe("Milestone MS-001");
78
- expect(handoff.source.milestoneOrderIndex).toBe(0);
79
- expect(handoff.source.featureOrderIndex).toBe(0);
80
- });
81
-
82
- it("handles features without descriptions", () => {
83
- const roadmap = createRoadmap();
84
- const milestone = createMilestone("MS-001", "RM-001", 0);
85
- const feature = createFeature("F-001", "MS-001", 0, { description: undefined });
86
-
87
- const handoff = mapFeatureToTaskHandoff(roadmap, milestone, feature);
88
-
89
- expect(handoff.title).toBe("Feature F-001");
90
- expect(handoff.description).toBeUndefined();
91
- });
92
-
93
- it("preserves exact IDs from source entities", () => {
94
- const roadmap = createRoadmap({ id: "RM-SPECIAL-123" });
95
- const milestone = createMilestone("RMS-SPECIAL-456", "RM-SPECIAL-123", 5);
96
- const feature = createFeature("RF-SPECIAL-789", "RMS-SPECIAL-456", 3);
97
-
98
- const handoff = mapFeatureToTaskHandoff(roadmap, milestone, feature);
99
-
100
- expect(handoff.source.roadmapId).toBe("RM-SPECIAL-123");
101
- expect(handoff.source.milestoneId).toBe("RMS-SPECIAL-456");
102
- expect(handoff.source.featureId).toBe("RF-SPECIAL-789");
103
- });
104
- });
105
-
106
- // ── Tests for mapRoadmapToMissionHandoff ─────────────────────────────────────
107
-
108
- describe("mapRoadmapToMissionHandoff", () => {
109
- it("maps a roadmap with milestones and features to mission handoff", () => {
110
- const roadmap = createRoadmap({ title: "Q1 Planning", description: "Quarterly goals" });
111
- const milestones = [
112
- createMilestone("MS-001", "RM-001", 0, { title: "Phase 1" }),
113
- createMilestone("MS-002", "RM-001", 1, { title: "Phase 2" }),
114
- ];
115
- const featuresByMilestoneId = new Map<string, readonly RoadmapFeature[]>([
116
- ["MS-001", [
117
- createFeature("F-001", "MS-001", 0, { title: "Auth Feature" }),
118
- createFeature("F-002", "MS-001", 1, { title: "Dashboard Feature" }),
119
- ]],
120
- ["MS-002", [
121
- createFeature("F-003", "MS-002", 0, { title: "Reporting Feature" }),
122
- ]],
123
- ]);
124
-
125
- const handoff = mapRoadmapToMissionHandoff(roadmap, milestones, featuresByMilestoneId);
126
-
127
- expect(handoff.sourceRoadmapId).toBe("RM-001");
128
- expect(handoff.title).toBe("Q1 Planning");
129
- expect(handoff.description).toBe("Quarterly goals");
130
- expect(handoff.milestones).toHaveLength(2);
131
-
132
- // Verify milestone ordering
133
- expect(handoff.milestones[0].title).toBe("Phase 1");
134
- expect(handoff.milestones[0].orderIndex).toBe(0);
135
- expect(handoff.milestones[1].title).toBe("Phase 2");
136
- expect(handoff.milestones[1].orderIndex).toBe(1);
137
-
138
- // Verify feature ordering within milestones
139
- expect(handoff.milestones[0].features).toHaveLength(2);
140
- expect(handoff.milestones[0].features[0].title).toBe("Auth Feature");
141
- expect(handoff.milestones[0].features[0].orderIndex).toBe(0);
142
- expect(handoff.milestones[0].features[1].title).toBe("Dashboard Feature");
143
- expect(handoff.milestones[0].features[1].orderIndex).toBe(1);
144
-
145
- expect(handoff.milestones[1].features).toHaveLength(1);
146
- expect(handoff.milestones[1].features[0].title).toBe("Reporting Feature");
147
- });
148
-
149
- it("handles empty milestones array", () => {
150
- const roadmap = createRoadmap();
151
- const featuresByMilestoneId = new Map<string, readonly RoadmapFeature[]>();
152
-
153
- const handoff = mapRoadmapToMissionHandoff(roadmap, [], featuresByMilestoneId);
154
-
155
- expect(handoff.sourceRoadmapId).toBe("RM-001");
156
- expect(handoff.milestones).toHaveLength(0);
157
- });
158
-
159
- it("handles milestones with empty features", () => {
160
- const roadmap = createRoadmap();
161
- const milestones = [
162
- createMilestone("MS-001", "RM-001", 0),
163
- ];
164
- const featuresByMilestoneId = new Map<string, readonly RoadmapFeature[]>();
165
-
166
- const handoff = mapRoadmapToMissionHandoff(roadmap, milestones, featuresByMilestoneId);
167
-
168
- expect(handoff.milestones).toHaveLength(1);
169
- expect(handoff.milestones[0].features).toHaveLength(0);
170
- });
171
-
172
- it("normalizes deterministic ordering when order indices are out of sequence", () => {
173
- const roadmap = createRoadmap();
174
- // Simulate out-of-sequence order indices
175
- const milestones = [
176
- createMilestone("MS-001", "RM-001", 10), // Out of sequence
177
- createMilestone("MS-002", "RM-001", 5), // Out of sequence
178
- createMilestone("MS-003", "RM-001", 20), // Out of sequence
179
- ];
180
- const featuresByMilestoneId = new Map<string, readonly RoadmapFeature[]>();
181
-
182
- const handoff = mapRoadmapToMissionHandoff(roadmap, milestones, featuresByMilestoneId);
183
-
184
- // Should be normalized to 0, 1, 2
185
- expect(handoff.milestones[0].orderIndex).toBe(0);
186
- expect(handoff.milestones[1].orderIndex).toBe(1);
187
- expect(handoff.milestones[2].orderIndex).toBe(2);
188
- });
189
- });
190
-
191
- // ── Tests for mapRoadmapWithHierarchyToMissionHandoff ────────────────────────
192
-
193
- describe("mapRoadmapWithHierarchyToMissionHandoff", () => {
194
- it("maps RoadmapWithHierarchy to mission handoff", () => {
195
- const roadmapWithHierarchy: RoadmapWithHierarchy = {
196
- id: "RM-001",
197
- title: "Hierarchy Roadmap",
198
- description: "With full hierarchy",
199
- createdAt: "2024-01-01T00:00:00.000Z",
200
- updatedAt: "2024-01-01T00:00:00.000Z",
201
- milestones: [
202
- {
203
- ...createMilestone("MS-001", "RM-001", 0, { title: "Alpha Phase" }),
204
- features: [
205
- createFeature("F-001", "MS-001", 0, { title: "Alpha Feature 1" }),
206
- createFeature("F-002", "MS-001", 1, { title: "Alpha Feature 2" }),
207
- ],
208
- },
209
- {
210
- ...createMilestone("MS-002", "RM-001", 1, { title: "Beta Phase" }),
211
- features: [
212
- createFeature("F-003", "MS-002", 0, { title: "Beta Feature" }),
213
- ],
214
- },
215
- ],
216
- };
217
-
218
- const handoff = mapRoadmapWithHierarchyToMissionHandoff(roadmapWithHierarchy);
219
-
220
- expect(handoff.sourceRoadmapId).toBe("RM-001");
221
- expect(handoff.title).toBe("Hierarchy Roadmap");
222
- expect(handoff.milestones).toHaveLength(2);
223
- expect(handoff.milestones[0].title).toBe("Alpha Phase");
224
- expect(handoff.milestones[0].features).toHaveLength(2);
225
- expect(handoff.milestones[1].title).toBe("Beta Phase");
226
- expect(handoff.milestones[1].features).toHaveLength(1);
227
- });
228
-
229
- it("handles empty milestone hierarchy", () => {
230
- const roadmapWithHierarchy: RoadmapWithHierarchy = {
231
- ...createRoadmap(),
232
- milestones: [],
233
- };
234
-
235
- const handoff = mapRoadmapWithHierarchyToMissionHandoff(roadmapWithHierarchy);
236
-
237
- expect(handoff.milestones).toHaveLength(0);
238
- });
239
- });
240
-
241
- // ── Tests for mapAllFeaturesToTaskHandoffs ────────────────────────────────────
242
-
243
- describe("mapAllFeaturesToTaskHandoffs", () => {
244
- it("flattens all features from a roadmap into individual handoffs", () => {
245
- const roadmap = createRoadmap();
246
- const milestones = [
247
- createMilestone("MS-001", "RM-001", 0),
248
- createMilestone("MS-002", "RM-001", 1),
249
- ];
250
- const featuresByMilestoneId = new Map<string, readonly RoadmapFeature[]>([
251
- ["MS-001", [
252
- createFeature("F-001", "MS-001", 0),
253
- createFeature("F-002", "MS-001", 1),
254
- ]],
255
- ["MS-002", [
256
- createFeature("F-003", "MS-002", 0),
257
- ]],
258
- ]);
259
-
260
- const handoffs = mapAllFeaturesToTaskHandoffs(roadmap, milestones, featuresByMilestoneId);
261
-
262
- expect(handoffs).toHaveLength(3);
263
- expect(handoffs[0].source.featureId).toBe("F-001");
264
- expect(handoffs[0].source.milestoneOrderIndex).toBe(0);
265
- expect(handoffs[0].source.featureOrderIndex).toBe(0);
266
- expect(handoffs[1].source.featureId).toBe("F-002");
267
- expect(handoffs[1].source.milestoneOrderIndex).toBe(0);
268
- expect(handoffs[1].source.featureOrderIndex).toBe(1);
269
- expect(handoffs[2].source.featureId).toBe("F-003");
270
- expect(handoffs[2].source.milestoneOrderIndex).toBe(1);
271
- expect(handoffs[2].source.featureOrderIndex).toBe(0);
272
- });
273
-
274
- it("returns empty array when no milestones exist", () => {
275
- const roadmap = createRoadmap();
276
- const featuresByMilestoneId = new Map<string, readonly RoadmapFeature[]>();
277
-
278
- const handoffs = mapAllFeaturesToTaskHandoffs(roadmap, [], featuresByMilestoneId);
279
-
280
- expect(handoffs).toHaveLength(0);
281
- });
282
-
283
- it("returns empty array when milestones have no features", () => {
284
- const roadmap = createRoadmap();
285
- const milestones = [createMilestone("MS-001", "RM-001", 0)];
286
- const featuresByMilestoneId = new Map<string, readonly RoadmapFeature[]>();
287
-
288
- const handoffs = mapAllFeaturesToTaskHandoffs(roadmap, milestones, featuresByMilestoneId);
289
-
290
- expect(handoffs).toHaveLength(0);
291
- });
292
-
293
- it("preserves feature titles and descriptions", () => {
294
- const roadmap = createRoadmap();
295
- const milestones = [createMilestone("MS-001", "RM-001", 0)];
296
- const featuresByMilestoneId = new Map<string, readonly RoadmapFeature[]>([
297
- ["MS-001", [
298
- createFeature("F-001", "MS-001", 0, { title: "Core Feature", description: "Main functionality" }),
299
- createFeature("F-002", "MS-001", 1, { title: "Secondary Feature", description: undefined }),
300
- ]],
301
- ]);
302
-
303
- const handoffs = mapAllFeaturesToTaskHandoffs(roadmap, milestones, featuresByMilestoneId);
304
-
305
- expect(handoffs[0].title).toBe("Core Feature");
306
- expect(handoffs[0].description).toBe("Main functionality");
307
- expect(handoffs[1].title).toBe("Secondary Feature");
308
- expect(handoffs[1].description).toBeUndefined();
309
- });
310
-
311
- it("normalizes ordering when feature order indices are out of sequence", () => {
312
- const roadmap = createRoadmap();
313
- const milestones = [createMilestone("MS-001", "RM-001", 0)];
314
- // Simulate out-of-sequence feature order indices
315
- const featuresByMilestoneId = new Map<string, readonly RoadmapFeature[]>([
316
- ["MS-001", [
317
- createFeature("F-001", "MS-001", 100),
318
- createFeature("F-002", "MS-001", 50),
319
- createFeature("F-003", "MS-001", 75),
320
- ]],
321
- ]);
322
-
323
- const handoffs = mapAllFeaturesToTaskHandoffs(roadmap, milestones, featuresByMilestoneId);
324
-
325
- expect(handoffs).toHaveLength(3);
326
- // Should be normalized to 0, 1, 2
327
- expect(handoffs[0].source.featureOrderIndex).toBe(0);
328
- expect(handoffs[1].source.featureOrderIndex).toBe(1);
329
- expect(handoffs[2].source.featureOrderIndex).toBe(2);
330
- });
331
-
332
- it("skips features from unknown milestone IDs", () => {
333
- const roadmap = createRoadmap();
334
- const milestones = [createMilestone("MS-001", "RM-001", 0)];
335
- const featuresByMilestoneId = new Map<string, readonly RoadmapFeature[]>([
336
- ["MS-001", [createFeature("F-001", "MS-001", 0)]],
337
- // MS-999 is not in milestones, so its features should be ignored
338
- ["MS-999", [createFeature("F-999", "MS-999", 0)]],
339
- ]);
340
-
341
- const handoffs = mapAllFeaturesToTaskHandoffs(roadmap, milestones, featuresByMilestoneId);
342
-
343
- expect(handoffs).toHaveLength(1);
344
- expect(handoffs[0].source.featureId).toBe("F-001");
345
- });
346
- });
347
-
348
- // ── Deterministic Ordering Tests ───────────────────────────────────────────────
349
-
350
- describe("deterministic ordering", () => {
351
- it("uses stable ordering when order indices are equal", () => {
352
- const roadmap = createRoadmap();
353
- // Same order index for all milestones - should sort by createdAt then id
354
- const rawMilestones = [
355
- createMilestone("MS-001", "RM-001", 0, { createdAt: "2024-01-01T00:00:00.000Z" }),
356
- createMilestone("MS-002", "RM-001", 0, { createdAt: "2024-01-01T00:00:00.000Z" }),
357
- createMilestone("MS-003", "RM-001", 0, { createdAt: "2024-01-02T00:00:00.000Z" }),
358
- ];
359
- // Normalize before passing to handoff function (mirrors store behavior)
360
- const milestones = normalizeRoadmapMilestoneOrder(rawMilestones);
361
- const featuresByMilestoneId = new Map<string, readonly RoadmapFeature[]>();
362
-
363
- const handoff = mapRoadmapToMissionHandoff(roadmap, milestones, featuresByMilestoneId);
364
-
365
- // MS-001 and MS-002 have same orderIndex and createdAt, so should sort by id
366
- // MS-003 has later createdAt
367
- expect(handoff.milestones[0].sourceMilestoneId).toBe("MS-001");
368
- expect(handoff.milestones[1].sourceMilestoneId).toBe("MS-002");
369
- expect(handoff.milestones[2].sourceMilestoneId).toBe("MS-003");
370
- });
371
-
372
- it("produces consistent output across multiple calls with same input", () => {
373
- const roadmap = createRoadmap({ id: "RM-STABLE" });
374
- const milestones = [
375
- createMilestone("MS-001", "RM-STABLE", 1),
376
- createMilestone("MS-002", "RM-STABLE", 0),
377
- ];
378
- const featuresByMilestoneId = new Map<string, readonly RoadmapFeature[]>([
379
- ["MS-001", [createFeature("F-001", "MS-001", 1)]],
380
- ["MS-002", [createFeature("F-002", "MS-002", 0)]],
381
- ]);
382
-
383
- const first = mapRoadmapToMissionHandoff(roadmap, milestones, featuresByMilestoneId);
384
- const second = mapRoadmapToMissionHandoff(roadmap, milestones, featuresByMilestoneId);
385
-
386
- expect(first).toEqual(second);
387
- expect(first.milestones[0].sourceMilestoneId).toBe(second.milestones[0].sourceMilestoneId);
388
- expect(first.milestones[1].sourceMilestoneId).toBe(second.milestones[1].sourceMilestoneId);
389
- });
390
- });
391
-
392
- // ── Source Lineage Preservation Tests ─────────────────────────────────────────
393
-
394
- describe("source lineage preservation", () => {
395
- it("preserves roadmap context in all feature handoffs", () => {
396
- const roadmap = createRoadmap({ id: "RM-LINEAGE", title: "Lineage Test" });
397
- const milestones = [createMilestone("MS-LINEAGE", "RM-LINEAGE", 0)];
398
- const featuresByMilestoneId = new Map<string, readonly RoadmapFeature[]>([
399
- ["MS-LINEAGE", [createFeature("F-LINEAGE", "MS-LINEAGE", 0)]],
400
- ]);
401
-
402
- const handoffs = mapAllFeaturesToTaskHandoffs(roadmap, milestones, featuresByMilestoneId);
403
-
404
- expect(handoffs[0].source.roadmapId).toBe("RM-LINEAGE");
405
- expect(handoffs[0].source.roadmapTitle).toBe("Lineage Test");
406
- });
407
-
408
- it("preserves milestone context in all feature handoffs", () => {
409
- const roadmap = createRoadmap();
410
- const milestones = [
411
- createMilestone("MS-ALPHA", "RM-001", 0, { title: "Alpha Milestone" }),
412
- createMilestone("MS-BETA", "RM-001", 1, { title: "Beta Milestone" }),
413
- ];
414
- const featuresByMilestoneId = new Map<string, readonly RoadmapFeature[]>([
415
- ["MS-ALPHA", [createFeature("F-001", "MS-ALPHA", 0)]],
416
- ["MS-BETA", [createFeature("F-002", "MS-BETA", 0)]],
417
- ]);
418
-
419
- const handoffs = mapAllFeaturesToTaskHandoffs(roadmap, milestones, featuresByMilestoneId);
420
-
421
- expect(handoffs).toHaveLength(2);
422
- expect(handoffs[0].source.milestoneId).toBe("MS-ALPHA");
423
- expect(handoffs[0].source.milestoneTitle).toBe("Alpha Milestone");
424
- expect(handoffs[1].source.milestoneId).toBe("MS-BETA");
425
- expect(handoffs[1].source.milestoneTitle).toBe("Beta Milestone");
426
- });
427
-
428
- it("mission handoff preserves source IDs on all entities", () => {
429
- const roadmap = createRoadmap({ id: "RM-MISSION" });
430
- const milestones = [
431
- createMilestone("MS-MISSION-1", "RM-MISSION", 0, { title: "First Phase" }),
432
- ];
433
- const featuresByMilestoneId = new Map<string, readonly RoadmapFeature[]>([
434
- ["MS-MISSION-1", [
435
- createFeature("RF-MISSION-1", "MS-MISSION-1", 0, { title: "Mission Feature" }),
436
- ]],
437
- ]);
438
-
439
- const handoff = mapRoadmapToMissionHandoff(roadmap, milestones, featuresByMilestoneId);
440
-
441
- expect(handoff.sourceRoadmapId).toBe("RM-MISSION");
442
- expect(handoff.milestones[0].sourceMilestoneId).toBe("MS-MISSION-1");
443
- expect(handoff.milestones[0].features[0].sourceFeatureId).toBe("RF-MISSION-1");
444
- });
445
- });