@runfusion/fusion 0.25.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 (113) hide show
  1. package/README.md +6 -0
  2. package/dist/bin.js +47492 -45420
  3. package/dist/client/assets/{AgentDetailView-ZbHEbYRT.js → AgentDetailView-Cv-vgOj3.js} +3 -3
  4. package/dist/client/assets/{AgentsView-B3jYk8Kt.js → AgentsView-D6Zi5zfP.js} +4 -4
  5. package/dist/client/assets/ChatView-CAHjY9uO.js +1 -0
  6. package/dist/client/assets/{DevServerView-DyGDEiBP.js → DevServerView--_WBvIDQ.js} +1 -1
  7. package/dist/client/assets/{DirectoryPicker-D5UIeIl6.js → DirectoryPicker-xedtR-Rd.js} +1 -1
  8. package/dist/client/assets/{DocumentsView-DNHu1T8K.js → DocumentsView-Bg2oaZks.js} +1 -1
  9. package/dist/client/assets/{EvalsView-CpRobtDi.js → EvalsView-B3uOCXfr.js} +1 -1
  10. package/dist/client/assets/{ExperimentalAgentOnboardingModal-DOY_oZi7.js → ExperimentalAgentOnboardingModal-Bx6yXVS5.js} +1 -1
  11. package/dist/client/assets/{InsightsView-vp0RE8Mg.js → InsightsView-Q1zvtF4F.js} +1 -1
  12. package/dist/client/assets/{MemoryView-PSc5lGJt.js → MemoryView-xcN_eouf.js} +1 -1
  13. package/dist/client/assets/{NodesView-DMj6HGeC.js → NodesView-RxXg58_Q.js} +1 -1
  14. package/dist/client/assets/{PiExtensionsManager-DL_QcN56.js → PiExtensionsManager-Cc8aAZXg.js} +2 -2
  15. package/dist/client/assets/{PluginManager-BtYKm8IT.js → PluginManager-BEkyBajl.js} +1 -1
  16. package/dist/client/assets/{ResearchView-BzCcDAS4.css → ResearchView-BEI4ZSGs.css} +1 -1
  17. package/dist/client/assets/ResearchView-CERNf7sJ.js +1 -0
  18. package/dist/client/assets/{SettingsModal-CUCyaAyE.js → SettingsModal-B1r0yASu.js} +1 -1
  19. package/dist/client/assets/SettingsModal-BLsac7CJ.js +31 -0
  20. package/dist/client/assets/SettingsModal-Cis-4Lot.css +1 -0
  21. package/dist/client/assets/{SetupWizardModal-BKscasuh.js → SetupWizardModal-D1q548_L.js} +1 -1
  22. package/dist/client/assets/{SkillsView-BdELqTy7.js → SkillsView-ClLM6u6p.js} +1 -1
  23. package/dist/client/assets/StashRecoveryView-B_8WIQEo.css +1 -0
  24. package/dist/client/assets/StashRecoveryView-ze0pEZ5U.js +1 -0
  25. package/dist/client/assets/{TodoView-DFNGBDNV.js → TodoView-CTmIfy2M.js} +1 -1
  26. package/dist/client/assets/createLucideIcon-BazL2hk5.js +21 -0
  27. package/dist/client/assets/dashboard-view-4xAN3yO5.js +21 -0
  28. package/dist/client/assets/dashboard-view-BkTMSZYn.css +1 -0
  29. package/dist/client/assets/dashboard-view-CyWN-d02.js +63 -0
  30. package/dist/client/assets/dashboard-view-DdGlfuu-.css +1 -0
  31. package/dist/client/assets/{folder-open-k1xmUMyr.js → folder-open-BZuKESeq.js} +1 -1
  32. package/dist/client/assets/index-Bdw6llW6.js +692 -0
  33. package/dist/client/assets/index-CZGlyJuS.css +1 -0
  34. package/dist/client/assets/{star-ne32r3Y4.js → star-D75YKEq-.js} +1 -1
  35. package/dist/client/assets/{upload-MS-2Gx53.js → upload-BYYTgWFj.js} +1 -1
  36. package/dist/client/assets/{users-C519GSjH.js → users-RS90Aii3.js} +1 -1
  37. package/dist/client/index.html +2 -2
  38. package/dist/client/version.json +1 -1
  39. package/dist/droid-cli/package.json +1 -1
  40. package/dist/extension.js +4340 -3059
  41. package/dist/pi-claude-cli/package.json +1 -1
  42. package/dist/plugins/fusion-plugin-cli-printing-press/manifest.json +6 -0
  43. package/dist/plugins/fusion-plugin-cli-printing-press/package.json +26 -0
  44. package/dist/plugins/fusion-plugin-cli-printing-press/src/__tests__/manifest.test.ts +20 -0
  45. package/dist/plugins/fusion-plugin-cli-printing-press/src/index.ts +14 -0
  46. package/dist/plugins/fusion-plugin-cursor-runtime/package.json +1 -1
  47. package/dist/plugins/fusion-plugin-dependency-graph/package.json +1 -1
  48. package/dist/plugins/fusion-plugin-droid-runtime/package.json +1 -1
  49. package/dist/plugins/fusion-plugin-hermes-runtime/package.json +1 -1
  50. package/dist/plugins/fusion-plugin-openclaw-runtime/package.json +1 -1
  51. package/dist/plugins/fusion-plugin-paperclip-runtime/package.json +1 -1
  52. package/dist/plugins/fusion-plugin-reports/package.json +1 -1
  53. package/dist/plugins/fusion-plugin-roadmap/{src/dashboard/RoadmapsView.css → bundled.css} +13 -219
  54. package/dist/plugins/fusion-plugin-roadmap/bundled.js +29535 -0
  55. package/dist/plugins/fusion-plugin-roadmap/package.json +4 -41
  56. package/dist/plugins/fusion-plugin-whatsapp-chat/package.json +1 -1
  57. package/package.json +2 -3
  58. package/dist/client/assets/ChatView-DhPkiEGs.js +0 -1
  59. package/dist/client/assets/ResearchView-BhWqfdV0.js +0 -1
  60. package/dist/client/assets/SettingsModal-BAgB4_AR.js +0 -31
  61. package/dist/client/assets/SettingsModal-DzsLquBu.css +0 -1
  62. package/dist/client/assets/index-Qq2JOOWx.css +0 -1
  63. package/dist/client/assets/index-TFYXEVpn.js +0 -692
  64. package/dist/plugins/fusion-plugin-roadmap/src/__tests__/api-client.test.ts +0 -101
  65. package/dist/plugins/fusion-plugin-roadmap/src/__tests__/index.test.ts +0 -92
  66. package/dist/plugins/fusion-plugin-roadmap/src/__tests__/roadmap-routes.test.ts +0 -48
  67. package/dist/plugins/fusion-plugin-roadmap/src/__tests__/roadmap-suggestions.test.ts +0 -31
  68. package/dist/plugins/fusion-plugin-roadmap/src/dashboard/RoadmapsView.tsx +0 -2559
  69. package/dist/plugins/fusion-plugin-roadmap/src/dashboard/__tests__/RoadmapsView.test.tsx +0 -1144
  70. package/dist/plugins/fusion-plugin-roadmap/src/dashboard/__tests__/useRoadmaps.test.ts +0 -1756
  71. package/dist/plugins/fusion-plugin-roadmap/src/dashboard/api.ts +0 -70
  72. package/dist/plugins/fusion-plugin-roadmap/src/dashboard/test-setup.ts +0 -7
  73. package/dist/plugins/fusion-plugin-roadmap/src/dashboard/types.ts +0 -1
  74. package/dist/plugins/fusion-plugin-roadmap/src/dashboard/useConfirm.ts +0 -8
  75. package/dist/plugins/fusion-plugin-roadmap/src/dashboard/useRoadmaps.ts +0 -1188
  76. package/dist/plugins/fusion-plugin-roadmap/src/dashboard/useViewportMode.ts +0 -20
  77. package/dist/plugins/fusion-plugin-roadmap/src/dashboard-view.tsx +0 -6
  78. package/dist/plugins/fusion-plugin-roadmap/src/index.ts +0 -74
  79. package/dist/plugins/fusion-plugin-roadmap/src/roadmap-routes.ts +0 -1
  80. package/dist/plugins/fusion-plugin-roadmap/src/roadmap-schema.ts +0 -41
  81. package/dist/plugins/fusion-plugin-roadmap/src/roadmap-suggestions.d.ts +0 -15
  82. package/dist/plugins/fusion-plugin-roadmap/src/roadmap-suggestions.ts +0 -15
  83. package/dist/plugins/fusion-plugin-roadmap/src/roadmap-types.d.ts +0 -283
  84. package/dist/plugins/fusion-plugin-roadmap/src/roadmap-types.d.ts.map +0 -1
  85. package/dist/plugins/fusion-plugin-roadmap/src/roadmap-types.js +0 -21
  86. package/dist/plugins/fusion-plugin-roadmap/src/roadmap-types.js.map +0 -1
  87. package/dist/plugins/fusion-plugin-roadmap/src/roadmap-types.ts +0 -310
  88. package/dist/plugins/fusion-plugin-roadmap/src/routes/roadmap-routes.d.ts +0 -5
  89. package/dist/plugins/fusion-plugin-roadmap/src/routes/roadmap-routes.d.ts.map +0 -1
  90. package/dist/plugins/fusion-plugin-roadmap/src/routes/roadmap-routes.js +0 -361
  91. package/dist/plugins/fusion-plugin-roadmap/src/routes/roadmap-routes.js.map +0 -1
  92. package/dist/plugins/fusion-plugin-roadmap/src/routes/roadmap-routes.ts +0 -408
  93. package/dist/plugins/fusion-plugin-roadmap/src/routes/roadmap-suggestions.d.ts +0 -68
  94. package/dist/plugins/fusion-plugin-roadmap/src/routes/roadmap-suggestions.d.ts.map +0 -1
  95. package/dist/plugins/fusion-plugin-roadmap/src/routes/roadmap-suggestions.js +0 -300
  96. package/dist/plugins/fusion-plugin-roadmap/src/routes/roadmap-suggestions.js.map +0 -1
  97. package/dist/plugins/fusion-plugin-roadmap/src/routes/roadmap-suggestions.ts +0 -381
  98. package/dist/plugins/fusion-plugin-roadmap/src/server/index.d.ts +0 -3
  99. package/dist/plugins/fusion-plugin-roadmap/src/server/index.ts +0 -1
  100. package/dist/plugins/fusion-plugin-roadmap/src/store/__tests__/roadmap-handoff.test.ts +0 -445
  101. package/dist/plugins/fusion-plugin-roadmap/src/store/__tests__/roadmap-ordering.test.ts +0 -334
  102. package/dist/plugins/fusion-plugin-roadmap/src/store/__tests__/roadmap-store.test.ts +0 -1318
  103. package/dist/plugins/fusion-plugin-roadmap/src/store/roadmap-handoff.ts +0 -163
  104. package/dist/plugins/fusion-plugin-roadmap/src/store/roadmap-ordering.d.ts +0 -37
  105. package/dist/plugins/fusion-plugin-roadmap/src/store/roadmap-ordering.d.ts.map +0 -1
  106. package/dist/plugins/fusion-plugin-roadmap/src/store/roadmap-ordering.js +0 -188
  107. package/dist/plugins/fusion-plugin-roadmap/src/store/roadmap-ordering.js.map +0 -1
  108. package/dist/plugins/fusion-plugin-roadmap/src/store/roadmap-ordering.ts +0 -311
  109. package/dist/plugins/fusion-plugin-roadmap/src/store/roadmap-store.d.ts +0 -299
  110. package/dist/plugins/fusion-plugin-roadmap/src/store/roadmap-store.d.ts.map +0 -1
  111. package/dist/plugins/fusion-plugin-roadmap/src/store/roadmap-store.js +0 -765
  112. package/dist/plugins/fusion-plugin-roadmap/src/store/roadmap-store.js.map +0 -1
  113. package/dist/plugins/fusion-plugin-roadmap/src/store/roadmap-store.ts +0 -1001
@@ -1,334 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import {
3
- applyRoadmapFeatureReorder,
4
- applyRoadmapMilestoneReorder,
5
- moveRoadmapFeature,
6
- normalizeRoadmapFeatureOrder,
7
- normalizeRoadmapMilestoneOrder,
8
- } from "../roadmap-ordering.js";
9
- import type { RoadmapFeature, RoadmapMilestone } from "../../roadmap-types.js";
10
-
11
- function createMilestone(
12
- id: string,
13
- roadmapId: string,
14
- orderIndex: number,
15
- createdAt: string,
16
- ): RoadmapMilestone {
17
- return {
18
- id,
19
- roadmapId,
20
- title: id,
21
- description: `${id} description`,
22
- orderIndex,
23
- createdAt,
24
- updatedAt: createdAt,
25
- };
26
- }
27
-
28
- function createFeature(
29
- id: string,
30
- milestoneId: string,
31
- orderIndex: number,
32
- createdAt: string,
33
- ): RoadmapFeature {
34
- return {
35
- id,
36
- milestoneId,
37
- title: id,
38
- description: `${id} description`,
39
- orderIndex,
40
- createdAt,
41
- updatedAt: createdAt,
42
- };
43
- }
44
-
45
- describe("roadmap-ordering", () => {
46
- describe("normalizeRoadmapMilestoneOrder", () => {
47
- it("repairs milestone ordering deterministically using createdAt and id tiebreakers", () => {
48
- const milestones = [
49
- createMilestone("RMS-C", "RM-1", 2, "2026-04-13T00:00:02.000Z"),
50
- createMilestone("RMS-B", "RM-1", 1, "2026-04-13T00:00:01.000Z"),
51
- createMilestone("RMS-A", "RM-1", 1, "2026-04-13T00:00:01.000Z"),
52
- ];
53
-
54
- const normalized = normalizeRoadmapMilestoneOrder(milestones);
55
-
56
- expect(normalized.map((milestone) => milestone.id)).toEqual([
57
- "RMS-A",
58
- "RMS-B",
59
- "RMS-C",
60
- ]);
61
- expect(normalized.map((milestone) => milestone.orderIndex)).toEqual([0, 1, 2]);
62
- expect(milestones.map((milestone) => milestone.orderIndex)).toEqual([2, 1, 1]);
63
- });
64
-
65
- it("rejects mixed-roadmap milestone scopes", () => {
66
- const milestones = [
67
- createMilestone("RMS-1", "RM-1", 0, "2026-04-13T00:00:00.000Z"),
68
- createMilestone("RMS-2", "RM-2", 1, "2026-04-13T00:00:01.000Z"),
69
- ];
70
-
71
- expect(() => normalizeRoadmapMilestoneOrder(milestones)).toThrow(
72
- "Milestone RMS-2 does not belong to roadmap RM-1",
73
- );
74
- });
75
- });
76
-
77
- describe("applyRoadmapMilestoneReorder", () => {
78
- it("reorders milestones and rewrites contiguous order indexes", () => {
79
- const milestones = [
80
- createMilestone("RMS-1", "RM-1", 0, "2026-04-13T00:00:00.000Z"),
81
- createMilestone("RMS-2", "RM-1", 1, "2026-04-13T00:00:01.000Z"),
82
- createMilestone("RMS-3", "RM-1", 2, "2026-04-13T00:00:02.000Z"),
83
- ];
84
-
85
- const reordered = applyRoadmapMilestoneReorder(milestones, {
86
- roadmapId: "RM-1",
87
- orderedMilestoneIds: ["RMS-3", "RMS-1", "RMS-2"],
88
- });
89
-
90
- expect(reordered.map((milestone) => milestone.id)).toEqual([
91
- "RMS-3",
92
- "RMS-1",
93
- "RMS-2",
94
- ]);
95
- expect(reordered.map((milestone) => milestone.orderIndex)).toEqual([0, 1, 2]);
96
- });
97
-
98
- it("rejects duplicate milestone ids in reorder input", () => {
99
- const milestones = [
100
- createMilestone("RMS-1", "RM-1", 0, "2026-04-13T00:00:00.000Z"),
101
- createMilestone("RMS-2", "RM-1", 1, "2026-04-13T00:00:01.000Z"),
102
- ];
103
-
104
- expect(() =>
105
- applyRoadmapMilestoneReorder(milestones, {
106
- roadmapId: "RM-1",
107
- orderedMilestoneIds: ["RMS-2", "RMS-2"],
108
- }),
109
- ).toThrow("Duplicate milestone id in requested order: RMS-2");
110
- });
111
- });
112
-
113
- describe("normalizeRoadmapFeatureOrder", () => {
114
- it("repairs feature ordering deterministically using createdAt and id tiebreakers", () => {
115
- const features = [
116
- createFeature("RF-C", "RMS-1", 3, "2026-04-13T00:00:03.000Z"),
117
- createFeature("RF-B", "RMS-1", 1, "2026-04-13T00:00:01.000Z"),
118
- createFeature("RF-A", "RMS-1", 1, "2026-04-13T00:00:01.000Z"),
119
- ];
120
-
121
- const normalized = normalizeRoadmapFeatureOrder(features);
122
-
123
- expect(normalized.map((feature) => feature.id)).toEqual([
124
- "RF-A",
125
- "RF-B",
126
- "RF-C",
127
- ]);
128
- expect(normalized.map((feature) => feature.orderIndex)).toEqual([0, 1, 2]);
129
- });
130
- });
131
-
132
- describe("applyRoadmapFeatureReorder", () => {
133
- it("reorders features within a milestone and rewrites contiguous order indexes", () => {
134
- const features = [
135
- createFeature("RF-1", "RMS-1", 0, "2026-04-13T00:00:00.000Z"),
136
- createFeature("RF-2", "RMS-1", 1, "2026-04-13T00:00:01.000Z"),
137
- createFeature("RF-3", "RMS-1", 2, "2026-04-13T00:00:02.000Z"),
138
- ];
139
-
140
- const reordered = applyRoadmapFeatureReorder(features, {
141
- roadmapId: "RM-1",
142
- milestoneId: "RMS-1",
143
- orderedFeatureIds: ["RF-2", "RF-3", "RF-1"],
144
- });
145
-
146
- expect(reordered.map((feature) => feature.id)).toEqual([
147
- "RF-2",
148
- "RF-3",
149
- "RF-1",
150
- ]);
151
- expect(reordered.map((feature) => feature.orderIndex)).toEqual([0, 1, 2]);
152
- });
153
-
154
- it("rejects partial feature reorder payloads", () => {
155
- const features = [
156
- createFeature("RF-1", "RMS-1", 0, "2026-04-13T00:00:00.000Z"),
157
- createFeature("RF-2", "RMS-1", 1, "2026-04-13T00:00:01.000Z"),
158
- ];
159
-
160
- expect(() =>
161
- applyRoadmapFeatureReorder(features, {
162
- roadmapId: "RM-1",
163
- milestoneId: "RMS-1",
164
- orderedFeatureIds: ["RF-2"],
165
- }),
166
- ).toThrow("Expected 2 feature ids but received 1");
167
- });
168
- });
169
-
170
- describe("moveRoadmapFeature", () => {
171
- it("moves a feature across milestones and normalizes both milestone orders", () => {
172
- const features = [
173
- createFeature("RF-1", "RMS-SOURCE", 0, "2026-04-13T00:00:00.000Z"),
174
- createFeature("RF-2", "RMS-SOURCE", 1, "2026-04-13T00:00:01.000Z"),
175
- createFeature("RF-3", "RMS-TARGET", 0, "2026-04-13T00:00:02.000Z"),
176
- createFeature("RF-4", "RMS-TARGET", 1, "2026-04-13T00:00:03.000Z"),
177
- ];
178
-
179
- const result = moveRoadmapFeature(features, {
180
- roadmapId: "RM-1",
181
- featureId: "RF-2",
182
- fromMilestoneId: "RMS-SOURCE",
183
- toMilestoneId: "RMS-TARGET",
184
- targetOrderIndex: 1,
185
- });
186
-
187
- expect(result.movedFeature).toMatchObject({
188
- id: "RF-2",
189
- milestoneId: "RMS-TARGET",
190
- orderIndex: 1,
191
- });
192
- expect(result.sourceMilestoneFeatures.map((feature) => feature.id)).toEqual([
193
- "RF-1",
194
- ]);
195
- expect(result.sourceMilestoneFeatures.map((feature) => feature.orderIndex)).toEqual([0]);
196
- expect(result.targetMilestoneFeatures.map((feature) => feature.id)).toEqual([
197
- "RF-3",
198
- "RF-2",
199
- "RF-4",
200
- ]);
201
- expect(result.targetMilestoneFeatures.map((feature) => feature.orderIndex)).toEqual([
202
- 0,
203
- 1,
204
- 2,
205
- ]);
206
- expect(result.affectedFeatures).toHaveLength(4);
207
- });
208
-
209
- it("clamps same-milestone moves into range and returns a single normalized list", () => {
210
- const features = [
211
- createFeature("RF-1", "RMS-1", 0, "2026-04-13T00:00:00.000Z"),
212
- createFeature("RF-2", "RMS-1", 1, "2026-04-13T00:00:01.000Z"),
213
- createFeature("RF-3", "RMS-1", 2, "2026-04-13T00:00:02.000Z"),
214
- ];
215
-
216
- const result = moveRoadmapFeature(features, {
217
- roadmapId: "RM-1",
218
- featureId: "RF-1",
219
- fromMilestoneId: "RMS-1",
220
- toMilestoneId: "RMS-1",
221
- targetOrderIndex: 99,
222
- });
223
-
224
- expect(result.sourceMilestoneFeatures.map((feature) => feature.id)).toEqual([
225
- "RF-2",
226
- "RF-3",
227
- "RF-1",
228
- ]);
229
- expect(result.targetMilestoneFeatures).toEqual(result.sourceMilestoneFeatures);
230
- expect(result.movedFeature.orderIndex).toBe(2);
231
- });
232
-
233
- it("rejects features outside the affected milestone scope", () => {
234
- const features = [
235
- createFeature("RF-1", "RMS-SOURCE", 0, "2026-04-13T00:00:00.000Z"),
236
- createFeature("RF-2", "RMS-OTHER", 0, "2026-04-13T00:00:01.000Z"),
237
- ];
238
-
239
- expect(() =>
240
- moveRoadmapFeature(features, {
241
- roadmapId: "RM-1",
242
- featureId: "RF-1",
243
- fromMilestoneId: "RMS-SOURCE",
244
- toMilestoneId: "RMS-TARGET",
245
- targetOrderIndex: 0,
246
- }),
247
- ).toThrow(
248
- "Feature RF-2 is outside the affected milestone scope (RMS-SOURCE → RMS-TARGET)",
249
- );
250
- });
251
-
252
- it("clamps negative targetOrderIndex to 0", () => {
253
- const features = [
254
- createFeature("RF-1", "RMS-1", 0, "2026-04-13T00:00:00.000Z"),
255
- createFeature("RF-2", "RMS-1", 1, "2026-04-13T00:00:01.000Z"),
256
- ];
257
-
258
- const result = moveRoadmapFeature(features, {
259
- roadmapId: "RM-1",
260
- featureId: "RF-2",
261
- fromMilestoneId: "RMS-1",
262
- toMilestoneId: "RMS-1",
263
- targetOrderIndex: -5,
264
- });
265
-
266
- // RF-2 should be moved to index 0, RF-1 to index 1
267
- expect(result.movedFeature.orderIndex).toBe(0);
268
- expect(result.sourceMilestoneFeatures.map((f) => f.id)).toEqual(["RF-2", "RF-1"]);
269
- });
270
-
271
- it("clamps NaN targetOrderIndex to end", () => {
272
- const features = [
273
- createFeature("RF-1", "RMS-1", 0, "2026-04-13T00:00:00.000Z"),
274
- createFeature("RF-2", "RMS-1", 1, "2026-04-13T00:00:01.000Z"),
275
- ];
276
-
277
- const result = moveRoadmapFeature(features, {
278
- roadmapId: "RM-1",
279
- featureId: "RF-1",
280
- fromMilestoneId: "RMS-1",
281
- toMilestoneId: "RMS-1",
282
- targetOrderIndex: NaN,
283
- });
284
-
285
- // NaN is clamped to the end (length of the remaining list)
286
- expect(result.movedFeature.orderIndex).toBe(1);
287
- });
288
-
289
- it("clamps Infinity targetOrderIndex to end", () => {
290
- const features = [
291
- createFeature("RF-1", "RMS-1", 0, "2026-04-13T00:00:00.000Z"),
292
- createFeature("RF-2", "RMS-1", 1, "2026-04-13T00:00:01.000Z"),
293
- ];
294
-
295
- const result = moveRoadmapFeature(features, {
296
- roadmapId: "RM-1",
297
- featureId: "RF-1",
298
- fromMilestoneId: "RMS-1",
299
- toMilestoneId: "RMS-1",
300
- targetOrderIndex: Infinity,
301
- });
302
-
303
- // Infinity is clamped to the end
304
- expect(result.movedFeature.orderIndex).toBe(1);
305
- });
306
-
307
- it("produces strictly contiguous orderIndex values after move", () => {
308
- const features = [
309
- createFeature("RF-1", "RMS-SOURCE", 0, "2026-04-13T00:00:00.000Z"),
310
- createFeature("RF-2", "RMS-SOURCE", 1, "2026-04-13T00:00:01.000Z"),
311
- createFeature("RF-3", "RMS-SOURCE", 2, "2026-04-13T00:00:02.000Z"),
312
- createFeature("RF-4", "RMS-TARGET", 0, "2026-04-13T00:00:03.000Z"),
313
- ];
314
-
315
- const result = moveRoadmapFeature(features, {
316
- roadmapId: "RM-1",
317
- featureId: "RF-2",
318
- fromMilestoneId: "RMS-SOURCE",
319
- toMilestoneId: "RMS-TARGET",
320
- targetOrderIndex: 0,
321
- });
322
-
323
- // Verify contiguous orderIndex for source
324
- const sourceOrderIndices = result.sourceMilestoneFeatures.map((f) => f.orderIndex);
325
- expect(sourceOrderIndices).toEqual([0, 1]);
326
- expect(new Set(sourceOrderIndices).size).toBe(sourceOrderIndices.length);
327
-
328
- // Verify contiguous orderIndex for target
329
- const targetOrderIndices = result.targetMilestoneFeatures.map((f) => f.orderIndex);
330
- expect(targetOrderIndices).toEqual([0, 1]);
331
- expect(new Set(targetOrderIndices).size).toBe(targetOrderIndices.length);
332
- });
333
- });
334
- });