@pygmalionjs/pygmalion 0.6.33 → 0.6.34
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/dist-lib/pygmalion.js +5851 -5777
- package/dist-lib/types/editor/captureSupply.d.ts +2 -0
- package/dist-lib/types/editor/projectBootGate.d.ts +15 -0
- package/dist-lib/types/editor/routePreviewStatus.d.ts +2 -1
- package/node/dev-mirror.mjs +3 -0
- package/node/preview-artifact-plugin.mjs +25 -4
- package/node/preview-artifact-store.mjs +14 -2
- package/package.json +1 -1
|
@@ -27,6 +27,8 @@ export interface CaptureSupplyFrame {
|
|
|
27
27
|
recipe?: RoutePreviewFrameRecipe;
|
|
28
28
|
}
|
|
29
29
|
export interface CaptureSupplyPlan {
|
|
30
|
+
/** Canvas that owned the viewport when this plan was built. */
|
|
31
|
+
activeCanvas?: string;
|
|
30
32
|
/** Chunks of the active canvas, nearest first. */
|
|
31
33
|
active: CaptureSupplyFrame[][];
|
|
32
34
|
/** Chunks of the other canvases, in the order the frames were given. */
|
|
@@ -27,6 +27,21 @@ export declare function mirrorBootRetryDelayMs(attempt: number): number;
|
|
|
27
27
|
export interface MirrorGateStatus {
|
|
28
28
|
state: string;
|
|
29
29
|
}
|
|
30
|
+
/** The idle status fields that can identify an immutable source before checkout. */
|
|
31
|
+
export interface IdleMirrorSourceStatus extends MirrorGateStatus {
|
|
32
|
+
sourceRef: string | null;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Returns an immutable source revision that can safely create the first lazy
|
|
36
|
+
* preview demand.
|
|
37
|
+
*
|
|
38
|
+
* An idle mirror has no checked-out `commit` yet. When it was configured with
|
|
39
|
+
* a full Git object id, however, that ref already names the exact revision the
|
|
40
|
+
* catalog endpoint will verify after preparation. Named refs, worktree mode,
|
|
41
|
+
* and abbreviated ids can move or be ambiguous, so they remain pending until
|
|
42
|
+
* the server reports the resolved commit.
|
|
43
|
+
*/
|
|
44
|
+
export declare function idleMirrorSourceRevision(status: IdleMirrorSourceStatus): string | null;
|
|
30
45
|
export interface SettleMirrorStatusOptions<S extends MirrorGateStatus> {
|
|
31
46
|
/** Status of the initial request; returned as-is when already settled. */
|
|
32
47
|
initial: S;
|
|
@@ -5,6 +5,7 @@ export interface RoutePreviewArtifactStatusInput {
|
|
|
5
5
|
resolution: RoutePreviewArtifactResolution;
|
|
6
6
|
captureStatus?: RoutePreviewArtifactV3Status;
|
|
7
7
|
diagnostic?: string;
|
|
8
|
+
liveInteractionReady?: boolean;
|
|
8
9
|
}
|
|
9
10
|
export interface RoutePreviewArtifactStatusPresentation {
|
|
10
11
|
title: string;
|
|
@@ -45,4 +46,4 @@ export declare function resolveStaticRoutePreviewSurface({ hasScreenshot, hasDom
|
|
|
45
46
|
preferDom?: boolean;
|
|
46
47
|
}): StaticRoutePreviewSurface;
|
|
47
48
|
/** Turns artifact freshness and capture state into one unambiguous frame badge. */
|
|
48
|
-
export declare function resolveRoutePreviewArtifactStatus({ stale, resolution, captureStatus, diagnostic, }: RoutePreviewArtifactStatusInput): RoutePreviewArtifactStatusPresentation | null;
|
|
49
|
+
export declare function resolveRoutePreviewArtifactStatus({ stale, resolution, captureStatus, diagnostic, liveInteractionReady, }: RoutePreviewArtifactStatusInput): RoutePreviewArtifactStatusPresentation | null;
|
package/node/dev-mirror.mjs
CHANGED
|
@@ -843,6 +843,9 @@ export async function acquireExactDevMirrorSourceLease({
|
|
|
843
843
|
return {
|
|
844
844
|
sourceRoot: exactSourceRoot,
|
|
845
845
|
sourceRevision: expectedRevision,
|
|
846
|
+
// Synchronization and reaping honor the heartbeat lease until release,
|
|
847
|
+
// so retention may safely inspect this root while the caller holds it.
|
|
848
|
+
sourceRootStable: true,
|
|
846
849
|
release,
|
|
847
850
|
};
|
|
848
851
|
} catch (error) {
|
|
@@ -788,6 +788,12 @@ export function pygmalionPreviewArtifactPlugin({
|
|
|
788
788
|
return { sourceRevision, sourceRoot: lease.sourceRoot };
|
|
789
789
|
}
|
|
790
790
|
|
|
791
|
+
function retentionSourceContextFromLease(lease, sourceRevision) {
|
|
792
|
+
return lease?.sourceRootStable === true
|
|
793
|
+
? sourceContextFromLease(lease, sourceRevision)
|
|
794
|
+
: undefined;
|
|
795
|
+
}
|
|
796
|
+
|
|
791
797
|
/**
|
|
792
798
|
* Refines a conservative cache decision only while the requested checkout is
|
|
793
799
|
* pinned. Fingerprint hits, recipe mismatches, and frames without observed
|
|
@@ -872,6 +878,11 @@ export function pygmalionPreviewArtifactPlugin({
|
|
|
872
878
|
const progress = startCaptureProgress();
|
|
873
879
|
try {
|
|
874
880
|
const generated = await withCaptureLease(sourceRevision, async (lease) => {
|
|
881
|
+
const sourceContext = sourceContextFromLease(lease, sourceRevision);
|
|
882
|
+
const retentionSourceContext = retentionSourceContextFromLease(
|
|
883
|
+
lease,
|
|
884
|
+
sourceRevision,
|
|
885
|
+
);
|
|
875
886
|
const captured = await generateArtifact(
|
|
876
887
|
{
|
|
877
888
|
namespace,
|
|
@@ -889,10 +900,10 @@ export function pygmalionPreviewArtifactPlugin({
|
|
|
889
900
|
'Generated preview artifact identity does not match the request.',
|
|
890
901
|
);
|
|
891
902
|
}
|
|
892
|
-
const observedDependenciesByFrame =
|
|
903
|
+
const observedDependenciesByFrame = sourceContext
|
|
893
904
|
? await artifactStore.observeArtifactDependencies(
|
|
894
905
|
captured,
|
|
895
|
-
|
|
906
|
+
sourceContext.sourceRoot,
|
|
896
907
|
)
|
|
897
908
|
: undefined;
|
|
898
909
|
await validateSourceLease(lease, sourceRevision);
|
|
@@ -900,6 +911,9 @@ export function pygmalionPreviewArtifactPlugin({
|
|
|
900
911
|
await artifactStore.publishArtifact(captured, {
|
|
901
912
|
sourceRevision,
|
|
902
913
|
recordRevision: true,
|
|
914
|
+
...(retentionSourceContext
|
|
915
|
+
? { sourceContext: retentionSourceContext }
|
|
916
|
+
: {}),
|
|
903
917
|
...(observedDependenciesByFrame
|
|
904
918
|
? { observedDependenciesByFrame }
|
|
905
919
|
: {}),
|
|
@@ -941,6 +955,10 @@ export function pygmalionPreviewArtifactPlugin({
|
|
|
941
955
|
try {
|
|
942
956
|
return await withCaptureLease(sourceRevision, async (lease) => {
|
|
943
957
|
const sourceContext = sourceContextFromLease(lease, sourceRevision);
|
|
958
|
+
const retentionSourceContext = retentionSourceContextFromLease(
|
|
959
|
+
lease,
|
|
960
|
+
sourceRevision,
|
|
961
|
+
);
|
|
944
962
|
const before = await artifactStore.readFrameSelection(
|
|
945
963
|
namespace,
|
|
946
964
|
sourceRevision,
|
|
@@ -976,10 +994,10 @@ export function pygmalionPreviewArtifactPlugin({
|
|
|
976
994
|
'Generated preview artifact frames do not match the request.',
|
|
977
995
|
);
|
|
978
996
|
}
|
|
979
|
-
const observedDependenciesByFrame =
|
|
997
|
+
const observedDependenciesByFrame = sourceContext
|
|
980
998
|
? await artifactStore.observeArtifactDependencies(
|
|
981
999
|
captured,
|
|
982
|
-
|
|
1000
|
+
sourceContext.sourceRoot,
|
|
983
1001
|
)
|
|
984
1002
|
: undefined;
|
|
985
1003
|
await validateSourceLease(lease, sourceRevision);
|
|
@@ -988,6 +1006,9 @@ export function pygmalionPreviewArtifactPlugin({
|
|
|
988
1006
|
sourceRevision,
|
|
989
1007
|
recordRevision: false,
|
|
990
1008
|
frameRequests: remaining,
|
|
1009
|
+
...(retentionSourceContext
|
|
1010
|
+
? { sourceContext: retentionSourceContext }
|
|
1011
|
+
: {}),
|
|
991
1012
|
...(observedDependenciesByFrame
|
|
992
1013
|
? { observedDependenciesByFrame }
|
|
993
1014
|
: {}),
|
|
@@ -596,7 +596,10 @@ export function createPreviewArtifactStore({
|
|
|
596
596
|
* is what keeps a concurrent reader from losing a bundle it is about to
|
|
597
597
|
* fetch.
|
|
598
598
|
*/
|
|
599
|
-
const evictToBudget = async (
|
|
599
|
+
const evictToBudget = async (
|
|
600
|
+
manifest,
|
|
601
|
+
{ at, sourceContext, admittedFrameObjects = new Set() } = {},
|
|
602
|
+
) => {
|
|
600
603
|
const referenced = new Map();
|
|
601
604
|
const remember = async (hash) => {
|
|
602
605
|
if (!referenced.has(hash)) referenced.set(hash, await objectByteSize(hash));
|
|
@@ -627,7 +630,13 @@ export function createPreviewArtifactStore({
|
|
|
627
630
|
candidates.push({
|
|
628
631
|
kind: 'frame',
|
|
629
632
|
entry,
|
|
630
|
-
|
|
633
|
+
// A caller that supplied normalized observations recorded from the
|
|
634
|
+
// artifact's own snapshot has already paid to produce this object.
|
|
635
|
+
// Protect that admission from older unknown entries without rereading
|
|
636
|
+
// a source root that may not be physically pinned.
|
|
637
|
+
rank: admittedFrameObjects.has(entry.object)
|
|
638
|
+
? EVICTION_RANK.valid
|
|
639
|
+
: EVICTION_RANK[await classifyFrameEntry(entry, sourceContext)],
|
|
631
640
|
// Protection within a rank, never across it: the last copy of a frame
|
|
632
641
|
// is worth more than a surplus copy, but an invalid sole entry is still
|
|
633
642
|
// garbage and goes before a valid one.
|
|
@@ -872,6 +881,7 @@ export function createPreviewArtifactStore({
|
|
|
872
881
|
...(stored?.frames ?? []),
|
|
873
882
|
].map((entry) => entry.object),
|
|
874
883
|
);
|
|
884
|
+
const admittedFrameObjects = new Set();
|
|
875
885
|
if (recordRevision && sourceRevision) {
|
|
876
886
|
const wholeObject = await writeObject(artifact);
|
|
877
887
|
const nextRevision = {
|
|
@@ -922,6 +932,7 @@ export function createPreviewArtifactStore({
|
|
|
922
932
|
generation,
|
|
923
933
|
...(observed ? { sourceFiles: observed } : {}),
|
|
924
934
|
};
|
|
935
|
+
if (observed) admittedFrameObjects.add(object);
|
|
925
936
|
const alreadyRecorded = frames.some(
|
|
926
937
|
(entry) =>
|
|
927
938
|
entry.id === nextFrame.id &&
|
|
@@ -941,6 +952,7 @@ export function createPreviewArtifactStore({
|
|
|
941
952
|
const trimmed = await evictToBudget(manifest, {
|
|
942
953
|
at,
|
|
943
954
|
sourceContext: exactSourceContext,
|
|
955
|
+
admittedFrameObjects,
|
|
944
956
|
});
|
|
945
957
|
manifest = trimmed.dropped
|
|
946
958
|
? { ...trimmed.manifest, lastEviction: trimmed.dropped }
|