@devosurf/vynt 0.1.3 → 0.1.4
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.
- package/package.json +1 -1
- package/src/bridge.ts +52 -18
- package/src/cli.ts +44 -3
- package/web/vynt-toolbar.js +28 -6
package/package.json
CHANGED
package/src/bridge.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createServer, type IncomingMessage, type Server, type ServerResponse } from "node:http"
|
|
2
2
|
import { watch, type FSWatcher } from "node:fs"
|
|
3
|
-
import { readFile } from "node:fs/promises"
|
|
3
|
+
import { readFile, unlink } from "node:fs/promises"
|
|
4
4
|
import { dirname, resolve } from "node:path"
|
|
5
5
|
import { fileURLToPath } from "node:url"
|
|
6
6
|
import { applySelectionsToWorkspace, getLatestSnapshot, rollbackWorkspaceToSnapshot } from "./switch.js"
|
|
@@ -187,12 +187,18 @@ function markVariantSelectedInState(state: VariantStore, objectiveId: string, va
|
|
|
187
187
|
}
|
|
188
188
|
}
|
|
189
189
|
|
|
190
|
-
function finalizeVariantInObjectiveState(
|
|
190
|
+
function finalizeVariantInObjectiveState(
|
|
191
|
+
state: VariantStore,
|
|
192
|
+
objectiveId: string,
|
|
193
|
+
variantId: string,
|
|
194
|
+
): { nextState: VariantStore; removedVariants: VariantArtifact[] } {
|
|
191
195
|
const objectiveItem = findObjective(state, objectiveId)
|
|
192
|
-
findVariant(objectiveItem, variantId)
|
|
196
|
+
const winner = findVariant(objectiveItem, variantId)
|
|
193
197
|
const now = new Date().toISOString()
|
|
198
|
+
const removedVariants = objectiveItem.variants.filter((variant) => variant.id !== variantId)
|
|
194
199
|
|
|
195
200
|
return {
|
|
201
|
+
nextState: {
|
|
196
202
|
...state,
|
|
197
203
|
activeProfileId: undefined,
|
|
198
204
|
objectives: state.objectives.map((item) => {
|
|
@@ -204,23 +210,49 @@ function finalizeVariantInObjectiveState(state: VariantStore, objectiveId: strin
|
|
|
204
210
|
winnerVariantId: variantId,
|
|
205
211
|
status: "finalized" as const,
|
|
206
212
|
updatedAt: now,
|
|
207
|
-
variants:
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
status: "selected" as const,
|
|
212
|
-
updatedAt: now,
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
return {
|
|
217
|
-
...variant,
|
|
218
|
-
status: "archived" as const,
|
|
213
|
+
variants: [
|
|
214
|
+
{
|
|
215
|
+
...winner,
|
|
216
|
+
status: "selected" as const,
|
|
219
217
|
updatedAt: now,
|
|
220
|
-
}
|
|
221
|
-
|
|
218
|
+
},
|
|
219
|
+
],
|
|
222
220
|
}
|
|
223
221
|
}),
|
|
222
|
+
},
|
|
223
|
+
removedVariants,
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
function collectPatchFiles(state: VariantStore): Set<string> {
|
|
228
|
+
const files = new Set<string>()
|
|
229
|
+
for (const objective of state.objectives) {
|
|
230
|
+
for (const variant of objective.variants) {
|
|
231
|
+
files.add(variant.patchFile)
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
return files
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
async function pruneRemovedVariantPatchFiles(
|
|
238
|
+
nextState: VariantStore,
|
|
239
|
+
removedVariants: VariantArtifact[],
|
|
240
|
+
): Promise<void> {
|
|
241
|
+
if (removedVariants.length === 0) return
|
|
242
|
+
const retainedPatchFiles = collectPatchFiles(nextState)
|
|
243
|
+
const deleteCandidates = new Set<string>()
|
|
244
|
+
|
|
245
|
+
for (const variant of removedVariants) {
|
|
246
|
+
if (!retainedPatchFiles.has(variant.patchFile)) {
|
|
247
|
+
deleteCandidates.add(variant.patchFile)
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
for (const patchFile of deleteCandidates) {
|
|
252
|
+
try {
|
|
253
|
+
await unlink(patchFile)
|
|
254
|
+
} catch {
|
|
255
|
+
}
|
|
224
256
|
}
|
|
225
257
|
}
|
|
226
258
|
|
|
@@ -743,7 +775,9 @@ export async function startBridgeServer(options: StartBridgeServerOptions): Prom
|
|
|
743
775
|
},
|
|
744
776
|
])
|
|
745
777
|
|
|
746
|
-
const
|
|
778
|
+
const finalized = finalizeVariantInObjectiveState(state, target.objective.id, target.variant.id)
|
|
779
|
+
await pruneRemovedVariantPatchFiles(finalized.nextState, finalized.removedVariants)
|
|
780
|
+
const nextState = finalized.nextState
|
|
747
781
|
await saveState(projectRoot, nextState)
|
|
748
782
|
|
|
749
783
|
emitEvent("finalize.succeeded", {
|
package/src/cli.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { execFile } from "node:child_process"
|
|
2
|
-
import { access, mkdir, readFile, writeFile } from "node:fs/promises"
|
|
2
|
+
import { access, mkdir, readFile, unlink, writeFile } from "node:fs/promises"
|
|
3
3
|
import { basename, join, resolve } from "node:path"
|
|
4
4
|
import process from "node:process"
|
|
5
5
|
import { createInterface } from "node:readline/promises"
|
|
@@ -544,6 +544,38 @@ function findProfile(state: VariantStore, profileId: string): PreviewProfile {
|
|
|
544
544
|
return found
|
|
545
545
|
}
|
|
546
546
|
|
|
547
|
+
function collectPatchFiles(state: VariantStore): Set<string> {
|
|
548
|
+
const files = new Set<string>()
|
|
549
|
+
for (const objective of state.objectives) {
|
|
550
|
+
for (const variant of objective.variants) {
|
|
551
|
+
files.add(variant.patchFile)
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
return files
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
async function pruneRemovedVariantPatchFiles(
|
|
558
|
+
nextState: VariantStore,
|
|
559
|
+
removedVariants: VariantArtifact[],
|
|
560
|
+
): Promise<void> {
|
|
561
|
+
if (removedVariants.length === 0) return
|
|
562
|
+
const retainedPatchFiles = collectPatchFiles(nextState)
|
|
563
|
+
const deleteCandidates = new Set<string>()
|
|
564
|
+
|
|
565
|
+
for (const variant of removedVariants) {
|
|
566
|
+
if (!retainedPatchFiles.has(variant.patchFile)) {
|
|
567
|
+
deleteCandidates.add(variant.patchFile)
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
for (const patchFile of deleteCandidates) {
|
|
572
|
+
try {
|
|
573
|
+
await unlink(patchFile)
|
|
574
|
+
} catch {
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
|
|
547
579
|
function findVariantAcrossObjectives(
|
|
548
580
|
state: VariantStore,
|
|
549
581
|
variantId: string,
|
|
@@ -829,17 +861,26 @@ function createProgram(cwd: string): Command {
|
|
|
829
861
|
.action(async (objectiveId: string, variantId: string) => {
|
|
830
862
|
const state = requireState(await loadState(cwd))
|
|
831
863
|
const current = findObjective(state, objectiveId)
|
|
832
|
-
findVariant(current, variantId)
|
|
864
|
+
const winner = findVariant(current, variantId)
|
|
865
|
+
const removedVariants = current.variants.filter((variant) => variant.id !== variantId)
|
|
833
866
|
|
|
834
867
|
const now = new Date().toISOString()
|
|
835
868
|
const next = upsertObjective(state, {
|
|
836
869
|
...current,
|
|
837
870
|
status: "finalized",
|
|
838
871
|
winnerVariantId: variantId,
|
|
839
|
-
activeVariantId:
|
|
872
|
+
activeVariantId: variantId,
|
|
840
873
|
updatedAt: now,
|
|
874
|
+
variants: [
|
|
875
|
+
{
|
|
876
|
+
...winner,
|
|
877
|
+
status: "selected",
|
|
878
|
+
updatedAt: now,
|
|
879
|
+
},
|
|
880
|
+
],
|
|
841
881
|
})
|
|
842
882
|
|
|
883
|
+
await pruneRemovedVariantPatchFiles(next, removedVariants)
|
|
843
884
|
await saveState(cwd, next)
|
|
844
885
|
process.stdout.write(`Objective ${objectiveId} finalized with winner ${variantId}\n`)
|
|
845
886
|
})
|
package/web/vynt-toolbar.js
CHANGED
|
@@ -576,13 +576,35 @@
|
|
|
576
576
|
objectiveOverlayRoot.style.width = `${Math.max(0, width)}px`;
|
|
577
577
|
objectiveOverlayRoot.style.height = `${Math.max(0, height)}px`;
|
|
578
578
|
|
|
579
|
-
const
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
579
|
+
const panelGap = 8;
|
|
580
|
+
const panelWidth = 220;
|
|
581
|
+
const panelHeight = 40;
|
|
582
|
+
const rightSpace = window.innerWidth - (x + width);
|
|
583
|
+
const leftSpace = x;
|
|
584
|
+
const alignedTop = Math.max(0, Math.min(Math.max(0, height - panelHeight), (height - panelHeight) / 2));
|
|
585
|
+
|
|
586
|
+
objectivePanel.style.bottom = "auto";
|
|
587
|
+
objectivePanel.style.top = `${alignedTop}px`;
|
|
588
|
+
|
|
589
|
+
if (rightSpace >= panelWidth + panelGap) {
|
|
590
|
+
objectivePanel.style.left = `${width + panelGap}px`;
|
|
591
|
+
objectivePanel.style.transform = "none";
|
|
592
|
+
return;
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
if (leftSpace >= panelWidth + panelGap) {
|
|
596
|
+
objectivePanel.style.left = `${-panelGap}px`;
|
|
597
|
+
objectivePanel.style.transform = "translateX(-100%)";
|
|
598
|
+
return;
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
objectivePanel.style.left = "50%";
|
|
602
|
+
objectivePanel.style.transform = "translateX(-50%)";
|
|
603
|
+
if (y + height + panelGap + panelHeight > window.innerHeight) {
|
|
604
|
+
objectivePanel.style.top = `${-panelGap}px`;
|
|
605
|
+
objectivePanel.style.transform = "translate(-50%, -100%)";
|
|
583
606
|
} else {
|
|
584
|
-
objectivePanel.style.top =
|
|
585
|
-
objectivePanel.style.bottom = "-50px";
|
|
607
|
+
objectivePanel.style.top = `${height + panelGap}px`;
|
|
586
608
|
}
|
|
587
609
|
}
|
|
588
610
|
|