03a4410272
主要工作是共享同一套“画布内核与通用 UI 源码”,网站和 Tauri 只分别实现宿主适配层。 --------- Co-authored-by: 段舒康 <kdletters@qq.com> Co-authored-by: kdletters <kdletters@qq.com> Reviewed-on: http://192.168.35.82/git/GenarrativeAI/Genarrative/pulls/136 Co-authored-by: menghao <mh18530625731@163.com> Co-committed-by: menghao <mh18530625731@163.com>
200 lines
4.7 KiB
TypeScript
200 lines
4.7 KiB
TypeScript
import type { GameCreationAppManifest } from '../../../../../packages/shared/src/contracts/gameCreationApp';
|
|
|
|
export type ProjectManifestSnapshotSource =
|
|
| 'initial'
|
|
| 'supervisor'
|
|
| 'asset-command'
|
|
| 'asset-event'
|
|
| 'poll';
|
|
|
|
export type ProjectManifestSnapshot = {
|
|
projectPath: string;
|
|
projectId: string;
|
|
revision: number;
|
|
manifest: GameCreationAppManifest;
|
|
source: ProjectManifestSnapshotSource;
|
|
commitId?: string;
|
|
eventId?: string;
|
|
};
|
|
|
|
export type ProjectManifestSnapshotMetadata = Omit<
|
|
ProjectManifestSnapshot,
|
|
'projectPath' | 'manifest'
|
|
>;
|
|
|
|
export type ProjectManifestMergeState = {
|
|
projectPath: string;
|
|
projectId: string;
|
|
revision: number;
|
|
manifestFingerprint: string;
|
|
seenCommitRevisions: string[];
|
|
seenEventIds: string[];
|
|
};
|
|
|
|
export type ProjectManifestMergeDecision =
|
|
| 'accepted'
|
|
| 'duplicate'
|
|
| 'stale-revision'
|
|
| 'scope-mismatch'
|
|
| 'revision-conflict';
|
|
|
|
const MAX_DEDUPE_IDENTITIES = 256;
|
|
|
|
function appendBounded(values: string[], value: string | undefined) {
|
|
if (!value || values.includes(value)) {
|
|
return values;
|
|
}
|
|
return [...values, value].slice(-MAX_DEDUPE_IDENTITIES);
|
|
}
|
|
|
|
function manifestFingerprint(manifest: GameCreationAppManifest) {
|
|
return JSON.stringify(manifest);
|
|
}
|
|
|
|
function commitRevisionIdentity(snapshot: ProjectManifestSnapshot) {
|
|
return snapshot.commitId
|
|
? `${snapshot.projectId}:${snapshot.commitId}:${snapshot.revision}`
|
|
: undefined;
|
|
}
|
|
|
|
function withDedupeIdentities(
|
|
state: ProjectManifestMergeState,
|
|
snapshot: ProjectManifestSnapshot,
|
|
) {
|
|
return {
|
|
...state,
|
|
seenCommitRevisions: appendBounded(
|
|
state.seenCommitRevisions,
|
|
commitRevisionIdentity(snapshot),
|
|
),
|
|
seenEventIds: appendBounded(state.seenEventIds, snapshot.eventId),
|
|
};
|
|
}
|
|
|
|
export function createProjectManifestMergeState(
|
|
snapshot: ProjectManifestSnapshot,
|
|
): ProjectManifestMergeState {
|
|
return withDedupeIdentities(
|
|
{
|
|
projectPath: snapshot.projectPath,
|
|
projectId: snapshot.projectId,
|
|
revision: snapshot.revision,
|
|
manifestFingerprint: manifestFingerprint(snapshot.manifest),
|
|
seenCommitRevisions: [],
|
|
seenEventIds: [],
|
|
},
|
|
snapshot,
|
|
);
|
|
}
|
|
|
|
export function mergeProjectManifestSnapshot(
|
|
current: ProjectManifestMergeState,
|
|
snapshot: ProjectManifestSnapshot,
|
|
): {
|
|
decision: ProjectManifestMergeDecision;
|
|
state: ProjectManifestMergeState;
|
|
} {
|
|
if (
|
|
snapshot.projectPath !== current.projectPath ||
|
|
snapshot.projectId !== current.projectId ||
|
|
snapshot.manifest.projectId !== snapshot.projectId
|
|
) {
|
|
return { decision: 'scope-mismatch', state: current };
|
|
}
|
|
if (snapshot.revision < current.revision) {
|
|
return { decision: 'stale-revision', state: current };
|
|
}
|
|
|
|
const fingerprint = manifestFingerprint(snapshot.manifest);
|
|
if (snapshot.revision === current.revision) {
|
|
if (fingerprint !== current.manifestFingerprint) {
|
|
return { decision: 'revision-conflict', state: current };
|
|
}
|
|
return {
|
|
decision: 'duplicate',
|
|
state: withDedupeIdentities(current, snapshot),
|
|
};
|
|
}
|
|
|
|
return {
|
|
decision: 'accepted',
|
|
state: withDedupeIdentities(
|
|
{
|
|
...current,
|
|
revision: snapshot.revision,
|
|
manifestFingerprint: fingerprint,
|
|
},
|
|
snapshot,
|
|
),
|
|
};
|
|
}
|
|
|
|
export type ResourceFocusIntent = {
|
|
flowId: string;
|
|
saveAttemptId: string;
|
|
sessionId: string;
|
|
draftId: string;
|
|
commitId: string;
|
|
projectPath: string;
|
|
projectId: string;
|
|
focusGeneration: number;
|
|
resourceId: string | null;
|
|
completed: boolean;
|
|
};
|
|
|
|
export type ResourceFocusResolution =
|
|
| 'invalid'
|
|
| 'wait-projection'
|
|
| 'wait-layout'
|
|
| 'hidden'
|
|
| 'wait-dom'
|
|
| 'focus'
|
|
| 'completed';
|
|
|
|
export function resolveResourceFocusIntent(
|
|
intent: ResourceFocusIntent,
|
|
input: {
|
|
projectPath: string;
|
|
projectId: string;
|
|
flowId: string | null;
|
|
focusGeneration: number;
|
|
projected: boolean;
|
|
dependencyLayoutSettled: boolean;
|
|
dependencyPositioned: boolean;
|
|
typeLayoutSettled: boolean;
|
|
typePositioned: boolean;
|
|
visible: boolean;
|
|
domRendered: boolean;
|
|
},
|
|
): ResourceFocusResolution {
|
|
if (intent.completed) {
|
|
return 'completed';
|
|
}
|
|
if (
|
|
intent.projectPath !== input.projectPath ||
|
|
intent.projectId !== input.projectId ||
|
|
intent.flowId !== input.flowId ||
|
|
intent.focusGeneration !== input.focusGeneration
|
|
) {
|
|
return 'invalid';
|
|
}
|
|
if (!intent.resourceId || !input.projected) {
|
|
return 'wait-projection';
|
|
}
|
|
if (
|
|
!input.dependencyLayoutSettled ||
|
|
!input.typeLayoutSettled ||
|
|
!input.dependencyPositioned ||
|
|
!input.typePositioned
|
|
) {
|
|
return 'wait-layout';
|
|
}
|
|
if (!input.visible) {
|
|
return 'hidden';
|
|
}
|
|
if (!input.domRendered) {
|
|
return 'wait-dom';
|
|
}
|
|
return 'focus';
|
|
}
|