合并编辑器素材库分支

合并 codex/editor-asset-library 到 AI 游戏创作 App 分支。

保留 AI 游戏创作客户端配置决策,并合入素材库分支新增文档。

排除素材库分支误带的 .env.local 本机密钥改动。
This commit is contained in:
AIGameCreator App
2026-06-30 15:23:41 +08:00
197 changed files with 18543 additions and 4560 deletions
@@ -544,7 +544,10 @@ import type {
} from './platformEntryTypes';
import { PlatformEntryWorldDetailView } from './PlatformEntryWorldDetailView';
import { PlatformErrorDialog } from './PlatformErrorDialog';
import { buildExternalGenerationQueueStatus } from './platformExternalGenerationQueueStatusModel';
import {
buildExternalGenerationQueueStatus,
shouldUseFastExternalGenerationTaskPolling,
} from './platformExternalGenerationQueueStatusModel';
import { resolvePlatformGenerationProgressTickDecision } from './platformGenerationProgressTickModel';
import {
sendPlatformHostDraftNotificationToHost,
@@ -707,6 +710,7 @@ type PuzzleBackgroundCompileTask = {
generationState: MiniGameDraftGenerationState;
error: string | null;
};
const EXTERNAL_GENERATION_TASK_FAST_POLL_INTERVAL_MS = 4_000;
function isUnacknowledgedExternalGenerationTerminalTask(
task: ExternalGenerationTaskRecord,
@@ -4969,6 +4973,15 @@ export function PlatformEntryFlowShellImpl({
woodenFishGenerationState,
);
const isHostNetworkOnline = useHostNetworkOnline();
const shouldFastPollKnownExternalGenerationTask =
puzzleOperation?.queueState?.status === 'queued' ||
puzzleOperation?.queueState?.status === 'running' ||
jumpHopQueueState?.status === 'queued' ||
jumpHopQueueState?.status === 'running' ||
puzzleClearQueueState?.status === 'queued' ||
puzzleClearQueueState?.status === 'running' ||
woodenFishQueueState?.status === 'queued' ||
woodenFishQueueState?.status === 'running';
const shouldPollExternalGenerationTasks =
platformBootstrap.canReadProtectedData && Boolean(authUi?.user?.id);
const externalGenerationQueueOwnerKey =
@@ -4993,6 +5006,21 @@ export function PlatformEntryFlowShellImpl({
let disposed = false;
let controller: AbortController | null = null;
let timerId: number | null = null;
const scheduleNextRefresh = (delayMs: number) => {
if (disposed) {
return;
}
if (timerId != null) {
window.clearTimeout(timerId);
timerId = null;
}
if (delayMs <= 0) {
return;
}
timerId = window.setTimeout(refreshTaskList, delayMs);
};
const refreshTaskList = () => {
controller?.abort();
@@ -5012,6 +5040,18 @@ export function PlatformEntryFlowShellImpl({
),
);
setExternalGenerationTaskOverview(response.overview);
scheduleNextRefresh(
shouldFastPollKnownExternalGenerationTask ||
shouldUseFastExternalGenerationTaskPolling(
buildExternalGenerationQueueStatus(
response.overview,
null,
response.tasks,
),
)
? EXTERNAL_GENERATION_TASK_FAST_POLL_INTERVAL_MS
: 0,
);
}
})
.catch(() => {
@@ -5023,16 +5063,28 @@ export function PlatformEntryFlowShellImpl({
};
refreshTaskList();
const intervalId = window.setInterval(refreshTaskList, 4000);
const handleResume = () => {
if (document.visibilityState === 'hidden') {
return;
}
refreshTaskList();
};
window.addEventListener('focus', handleResume);
document.addEventListener('visibilitychange', handleResume);
return () => {
disposed = true;
controller?.abort();
window.clearInterval(intervalId);
if (timerId != null) {
window.clearTimeout(timerId);
}
window.removeEventListener('focus', handleResume);
document.removeEventListener('visibilitychange', handleResume);
};
}, [
externalGenerationQueueOwnerKey,
isHostNetworkOnline,
shouldFastPollKnownExternalGenerationTask,
shouldPollExternalGenerationTasks,
]);
const activeExternalGenerationJobState = useMemo(() => {