@playdrop/playdrop-cli 0.15.6 → 0.15.9
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/config/client-meta.json +2 -2
- package/dist/apps/index.d.ts +0 -1
- package/dist/apps/index.js +0 -1
- package/dist/apps/loadCheck.d.ts +2 -1
- package/dist/apps/loadCheck.js +15 -7
- package/dist/apps/staticHtml.js +1 -0
- package/dist/apps/upload.d.ts +0 -1
- package/dist/apps/upload.js +19 -12
- package/dist/catalogue.d.ts +3 -0
- package/dist/catalogue.js +26 -0
- package/dist/commands/create.js +45 -16
- package/dist/commands/devRuntimeAssets.d.ts +1 -0
- package/dist/commands/devRuntimeAssets.js +2 -0
- package/dist/commands/review.js +0 -3
- package/dist/commands/upload.d.ts +2 -3
- package/dist/commands/upload.js +22 -42
- package/dist/commands/validate.js +0 -4
- package/dist/commands/worker.d.ts +7 -1
- package/dist/commands/worker.js +65 -57
- package/dist/index.js +1 -1
- package/dist/listingPreflight.d.ts +1 -24
- package/dist/listingPreflight.js +3 -288
- package/node_modules/@playdrop/api-client/dist/client.d.ts +29 -1
- package/node_modules/@playdrop/api-client/dist/client.d.ts.map +1 -1
- package/node_modules/@playdrop/api-client/dist/domains/admin.d.ts +4 -1
- package/node_modules/@playdrop/api-client/dist/domains/admin.d.ts.map +1 -1
- package/node_modules/@playdrop/api-client/dist/domains/admin.js +31 -2
- package/node_modules/@playdrop/api-client/dist/domains/agent-tasks.d.ts +2 -1
- package/node_modules/@playdrop/api-client/dist/domains/agent-tasks.d.ts.map +1 -1
- package/node_modules/@playdrop/api-client/dist/domains/agent-tasks.js +12 -0
- package/node_modules/@playdrop/api-client/dist/domains/apps.d.ts +9 -1
- package/node_modules/@playdrop/api-client/dist/domains/apps.d.ts.map +1 -1
- package/node_modules/@playdrop/api-client/dist/domains/apps.js +66 -0
- package/node_modules/@playdrop/api-client/dist/domains/asset-packs.d.ts +1 -0
- package/node_modules/@playdrop/api-client/dist/domains/asset-packs.d.ts.map +1 -1
- package/node_modules/@playdrop/api-client/dist/domains/asset-packs.js +3 -0
- package/node_modules/@playdrop/api-client/dist/domains/assets.d.ts +1 -0
- package/node_modules/@playdrop/api-client/dist/domains/assets.d.ts.map +1 -1
- package/node_modules/@playdrop/api-client/dist/domains/assets.js +3 -0
- package/node_modules/@playdrop/api-client/dist/domains/payments.d.ts +15 -1
- package/node_modules/@playdrop/api-client/dist/domains/payments.d.ts.map +1 -1
- package/node_modules/@playdrop/api-client/dist/domains/payments.js +58 -0
- package/node_modules/@playdrop/api-client/dist/index.d.ts +30 -1
- package/node_modules/@playdrop/api-client/dist/index.d.ts.map +1 -1
- package/node_modules/@playdrop/api-client/dist/index.js +65 -0
- package/node_modules/@playdrop/config/client-meta.json +2 -2
- package/node_modules/@playdrop/config/dist/src/creator-plans.d.ts +18 -0
- package/node_modules/@playdrop/config/dist/src/creator-plans.d.ts.map +1 -0
- package/node_modules/@playdrop/config/dist/src/creator-plans.js +117 -0
- package/node_modules/@playdrop/config/dist/src/game-arena.d.ts +1 -1
- package/node_modules/@playdrop/config/dist/src/game-arena.js +1 -1
- package/node_modules/@playdrop/config/dist/src/index.d.ts +1 -0
- package/node_modules/@playdrop/config/dist/src/index.d.ts.map +1 -1
- package/node_modules/@playdrop/config/dist/src/index.js +1 -0
- package/node_modules/@playdrop/config/dist/test/creator-plans.test.d.ts +2 -0
- package/node_modules/@playdrop/config/dist/test/creator-plans.test.d.ts.map +1 -0
- package/node_modules/@playdrop/config/dist/test/creator-plans.test.js +28 -0
- package/node_modules/@playdrop/config/dist/test/game-arena.test.js +3 -3
- package/node_modules/@playdrop/config/dist/tsconfig.tsbuildinfo +1 -1
- package/node_modules/@playdrop/types/dist/api.d.ts +133 -14
- package/node_modules/@playdrop/types/dist/api.d.ts.map +1 -1
- package/node_modules/@playdrop/types/dist/api.js +20 -2
- package/node_modules/@playdrop/types/dist/app-review.d.ts +2 -0
- package/node_modules/@playdrop/types/dist/app-review.d.ts.map +1 -1
- package/node_modules/@playdrop/types/dist/app-review.js +31 -2
- package/node_modules/@playdrop/types/dist/index.d.ts +1 -0
- package/node_modules/@playdrop/types/dist/index.d.ts.map +1 -1
- package/node_modules/@playdrop/types/dist/index.js +3 -1
- package/node_modules/@playdrop/types/dist/release-smoke.d.ts +3 -0
- package/node_modules/@playdrop/types/dist/release-smoke.d.ts.map +1 -0
- package/node_modules/@playdrop/types/dist/release-smoke.js +35 -0
- package/node_modules/@playdrop/types/dist/version.d.ts +5 -0
- package/node_modules/@playdrop/types/dist/version.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/commands/worker.js
CHANGED
|
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.WORKER_TASK_WORKSPACE_RETENTION = exports.WORKER_CONTEXT_COMMAND_NOT_ALLOWED_MESSAGE = exports.WORKER_SESSION_EXPIRED_MESSAGE = exports.runLoggedProcess = exports.readEnvBoolean = exports.readCodexSandboxMode = exports.readCodexRolloutTokenUsageForThread = exports.extractCodexTokensUsed = exports.extractCodexThreadId = exports.extractClaudeSessionId = exports.extractCodexRolloutTokenUsage = exports.extractAgentTokenUsage = exports.DEFAULT_WORKER_TOKEN_CAP = exports.DEFAULT_CREATOR_UPLOAD_RECOVERY_TIMEOUT_MS = exports.DEFAULT_CREATOR_AGENT_TIMEOUT_MS = exports.DEFAULT_CODEX_TIMEOUT_MS = exports.buildWorkerChildEnv = exports.buildPlaywrightMcpCommand = exports.buildCodexExecArgs = exports.buildCleanRoomChildEnv = exports.buildClaudePermissionSettings = exports.buildClaudeExecArgs = exports.assertWorkerTokenUsageWithinCap = void 0;
|
|
7
7
|
exports.usesCreatorRecovery = usesCreatorRecovery;
|
|
8
|
+
exports.buildDeterministicReleaseSmokeArtifact = buildDeterministicReleaseSmokeArtifact;
|
|
8
9
|
exports.buildCreatorRecoveryPrompt = buildCreatorRecoveryPrompt;
|
|
9
10
|
exports.buildGameEvalRetryPrompt = buildGameEvalRetryPrompt;
|
|
10
11
|
exports.resolveInitialCreatorProgress = resolveInitialCreatorProgress;
|
|
@@ -17,6 +18,7 @@ exports.claimBackoffDelayMs = claimBackoffDelayMs;
|
|
|
17
18
|
exports.resolveWorkerHomeDir = resolveWorkerHomeDir;
|
|
18
19
|
exports.pruneWorkerTaskWorkspaces = pruneWorkerTaskWorkspaces;
|
|
19
20
|
exports.prepareClaimedTaskWorkspace = prepareClaimedTaskWorkspace;
|
|
21
|
+
exports.buildWorkerTaskContextV2 = buildWorkerTaskContextV2;
|
|
20
22
|
exports.resolveWorkerInstrumentSurface = resolveWorkerInstrumentSurface;
|
|
21
23
|
exports.hasAgentTaskUploadedArtifact = hasAgentTaskUploadedArtifact;
|
|
22
24
|
exports.appendWorkerTranscriptChunks = appendWorkerTranscriptChunks;
|
|
@@ -111,7 +113,6 @@ const commandContext_1 = require("../commandContext");
|
|
|
111
113
|
const config_1 = require("../config");
|
|
112
114
|
const messages_1 = require("../messages");
|
|
113
115
|
const output_1 = require("../output");
|
|
114
|
-
const recorderRelease_1 = require("../recorderRelease");
|
|
115
116
|
const shellProbe_1 = require("../shellProbe");
|
|
116
117
|
const review_1 = require("./review");
|
|
117
118
|
const upload_1 = require("./upload");
|
|
@@ -152,7 +153,7 @@ const FAIL_REPORT_RETRY_DELAY_MS = 2000;
|
|
|
152
153
|
const WORKER_TRANSCRIPT_CHUNK_BATCH_SIZE = 100;
|
|
153
154
|
const SLACK_API_BASE_URL = 'https://slack.com/api';
|
|
154
155
|
const WORKER_WRAPPER_CONTRACT_VERSION = 3;
|
|
155
|
-
const WORKER_SUPPORTED_KINDS = ['NEW_GAME', 'STATIC_GAME', 'REMIX_GAME', 'GAME_UPDATE', 'GAME_REVIEW', 'GAME_EVAL'];
|
|
156
|
+
const WORKER_SUPPORTED_KINDS = ['NEW_GAME', 'STATIC_GAME', 'REMIX_GAME', 'GAME_UPDATE', 'GAME_REVIEW', 'GAME_EVAL', 'RELEASE_SMOKE'];
|
|
156
157
|
const GAME_CREATION_TASK_KINDS = new Set(['NEW_GAME', 'STATIC_GAME', 'REMIX_GAME', 'GAME_UPDATE']);
|
|
157
158
|
const AGENT_MANAGED_UPLOAD_TASK_KINDS = new Set(['NEW_GAME', 'REMIX_GAME', 'GAME_UPDATE']);
|
|
158
159
|
const requireFromWorker = (0, node_module_1.createRequire)(__filename);
|
|
@@ -168,6 +169,14 @@ const execFileAsync = (0, node_util_1.promisify)(node_child_process_1.execFile);
|
|
|
168
169
|
function usesCreatorRecovery(kind) {
|
|
169
170
|
return GAME_CREATION_TASK_KINDS.has(kind);
|
|
170
171
|
}
|
|
172
|
+
function buildDeterministicReleaseSmokeArtifact() {
|
|
173
|
+
const content = Buffer.from(types_1.RELEASE_SMOKE_HTML, 'utf8');
|
|
174
|
+
return {
|
|
175
|
+
fileName: types_1.RELEASE_SMOKE_FILE_NAME,
|
|
176
|
+
content,
|
|
177
|
+
sha256: (0, node_crypto_1.createHash)('sha256').update(content).digest('hex'),
|
|
178
|
+
};
|
|
179
|
+
}
|
|
171
180
|
function buildCreatorRecoveryPrompt(input) {
|
|
172
181
|
const prompt = input.prompt.trim();
|
|
173
182
|
if (!prompt) {
|
|
@@ -610,7 +619,7 @@ function buildWorkerTaskContext(input) {
|
|
|
610
619
|
}
|
|
611
620
|
const metadata = playdrop;
|
|
612
621
|
const kind = metadata.kind;
|
|
613
|
-
if (kind !== 'NEW_GAME' && kind !== 'STATIC_GAME' && kind !== 'REMIX_GAME' && kind !== 'GAME_UPDATE' && kind !== 'GAME_REVIEW' && kind !== 'GAME_EVAL') {
|
|
622
|
+
if (kind !== 'NEW_GAME' && kind !== 'STATIC_GAME' && kind !== 'REMIX_GAME' && kind !== 'GAME_UPDATE' && kind !== 'GAME_REVIEW' && kind !== 'GAME_EVAL' && kind !== 'RELEASE_SMOKE') {
|
|
614
623
|
throw new Error('agent_task_context_kind_missing');
|
|
615
624
|
}
|
|
616
625
|
const creatorUsername = typeof metadata.creatorUsername === 'string'
|
|
@@ -3004,45 +3013,6 @@ function collectWorkerInfrastructureFailures() {
|
|
|
3004
3013
|
catch (error) {
|
|
3005
3014
|
failures.push(errorCode(error));
|
|
3006
3015
|
}
|
|
3007
|
-
if (node_process_1.default.platform !== 'darwin') {
|
|
3008
|
-
return failures;
|
|
3009
|
-
}
|
|
3010
|
-
if (node_process_1.default.arch !== recorderRelease_1.MAC_WORKER_RECORDER_RELEASE.architecture) {
|
|
3011
|
-
failures.push('worker_preflight_recorder_architecture_unsupported');
|
|
3012
|
-
return failures;
|
|
3013
|
-
}
|
|
3014
|
-
if (!workerCommandExists('ffmpeg')) {
|
|
3015
|
-
failures.push('worker_preflight_ffmpeg_missing');
|
|
3016
|
-
}
|
|
3017
|
-
if (!workerCommandExists('ffprobe')) {
|
|
3018
|
-
failures.push('worker_preflight_ffprobe_missing');
|
|
3019
|
-
}
|
|
3020
|
-
const guiSession = (0, shellProbe_1.runShell)('/bin/launchctl print "gui/$(/usr/bin/id -u)"');
|
|
3021
|
-
if (guiSession.exitCode !== 0) {
|
|
3022
|
-
failures.push('worker_preflight_gui_session_missing');
|
|
3023
|
-
}
|
|
3024
|
-
const recorderPath = (0, recorderRelease_1.resolveMacWorkerRecorderPath)();
|
|
3025
|
-
if (!(0, node_fs_1.existsSync)(recorderPath)) {
|
|
3026
|
-
failures.push('worker_preflight_recorder_missing');
|
|
3027
|
-
return failures;
|
|
3028
|
-
}
|
|
3029
|
-
const recorderStat = (0, node_fs_1.statSync)(recorderPath);
|
|
3030
|
-
if (!recorderStat.isFile() || (recorderStat.mode & 0o111) === 0) {
|
|
3031
|
-
failures.push('worker_preflight_recorder_not_executable');
|
|
3032
|
-
return failures;
|
|
3033
|
-
}
|
|
3034
|
-
const installedSha256 = (0, recorderRelease_1.recorderSha256)((0, node_fs_1.readFileSync)(recorderPath));
|
|
3035
|
-
if (installedSha256 !== recorderRelease_1.MAC_WORKER_RECORDER_RELEASE.sha256) {
|
|
3036
|
-
failures.push('worker_preflight_recorder_hash_mismatch');
|
|
3037
|
-
return failures;
|
|
3038
|
-
}
|
|
3039
|
-
const permission = (0, node_child_process_1.spawnSync)(recorderPath, ['--check-permission'], {
|
|
3040
|
-
encoding: 'utf8',
|
|
3041
|
-
timeout: 10000,
|
|
3042
|
-
});
|
|
3043
|
-
if (permission.status !== 0) {
|
|
3044
|
-
failures.push('worker_preflight_screen_recording_permission_missing');
|
|
3045
|
-
}
|
|
3046
3016
|
return failures;
|
|
3047
3017
|
}
|
|
3048
3018
|
function describeWorkerPreflightReason(reason) {
|
|
@@ -4218,20 +4188,6 @@ async function startWorker(options = {}) {
|
|
|
4218
4188
|
try {
|
|
4219
4189
|
await removeStaleAgentRunCredentials();
|
|
4220
4190
|
const startupFailures = [];
|
|
4221
|
-
if (node_process_1.default.platform === 'darwin') {
|
|
4222
|
-
try {
|
|
4223
|
-
const recorder = await (0, recorderRelease_1.ensureMacWorkerRecorderInstalled)();
|
|
4224
|
-
if (recorder.downloaded) {
|
|
4225
|
-
console.log(`Installed PlayDrop macOS recorder ${recorderRelease_1.MAC_WORKER_RECORDER_RELEASE.version} at ${recorder.path}.`);
|
|
4226
|
-
}
|
|
4227
|
-
}
|
|
4228
|
-
catch (error) {
|
|
4229
|
-
startupFailures.push(`worker_preflight_recorder_download_failed:${errorMessage(error)}`);
|
|
4230
|
-
}
|
|
4231
|
-
}
|
|
4232
|
-
else if (node_process_1.default.platform === 'win32') {
|
|
4233
|
-
console.warn('Native listing recording is not available on Windows yet.');
|
|
4234
|
-
}
|
|
4235
4191
|
const local = collectWorkerLocalStatus();
|
|
4236
4192
|
startupFailures.push(...local.degradedReasons);
|
|
4237
4193
|
if (startupFailures.length > 0 || !local.ready || !local.capabilities || !local.playwright?.chromiumInstalled) {
|
|
@@ -4548,6 +4504,55 @@ async function startWorker(options = {}) {
|
|
|
4548
4504
|
})
|
|
4549
4505
|
: null;
|
|
4550
4506
|
availableSkillPaths = listPluginSkillPaths(assignmentPluginRoot);
|
|
4507
|
+
if (task.kind === 'RELEASE_SMOKE') {
|
|
4508
|
+
if (!assignment.plugin || !assignmentPluginRoot) {
|
|
4509
|
+
throw new Error('release_smoke_bundle_missing');
|
|
4510
|
+
}
|
|
4511
|
+
const artifact = buildDeterministicReleaseSmokeArtifact();
|
|
4512
|
+
const artifactPath = node_path_1.default.join(agentWorkspaceDir, artifact.fileName);
|
|
4513
|
+
await (0, promises_1.writeFile)(artifactPath, artifact.content);
|
|
4514
|
+
const storedArtifact = (0, node_fs_1.readFileSync)(artifactPath);
|
|
4515
|
+
if ((0, node_crypto_1.createHash)('sha256').update(storedArtifact).digest('hex') !== artifact.sha256) {
|
|
4516
|
+
throw new Error('release_smoke_workspace_verification_failed');
|
|
4517
|
+
}
|
|
4518
|
+
if (!envConfig.cdnBase) {
|
|
4519
|
+
throw new Error('release_smoke_publish_cdn_base_missing');
|
|
4520
|
+
}
|
|
4521
|
+
const taskClient = (0, apiClient_1.createCliApiClient)({
|
|
4522
|
+
baseUrl: envConfig.apiBase,
|
|
4523
|
+
token,
|
|
4524
|
+
onBehalfCreatorUsername: taskContext.creatorUsername,
|
|
4525
|
+
agentTaskToken: assignment.task.token,
|
|
4526
|
+
agentTaskId: task.id,
|
|
4527
|
+
agentTaskAttempt: taskContext.attempt,
|
|
4528
|
+
});
|
|
4529
|
+
const published = await (0, upload_1.publishStaticHtmlProject)({
|
|
4530
|
+
client: taskClient,
|
|
4531
|
+
taskId: task.id,
|
|
4532
|
+
taskToken: assignment.task.token,
|
|
4533
|
+
projectDir: agentWorkspaceDir,
|
|
4534
|
+
creatorUsername: taskContext.creatorUsername,
|
|
4535
|
+
primarySurface: 'DESKTOP',
|
|
4536
|
+
apiBase: envConfig.apiBase,
|
|
4537
|
+
webBase: envConfig.webBase ?? null,
|
|
4538
|
+
cdnBase: envConfig.cdnBase,
|
|
4539
|
+
devRouterPort: devPort,
|
|
4540
|
+
token,
|
|
4541
|
+
user: me.user,
|
|
4542
|
+
skipReview: true,
|
|
4543
|
+
});
|
|
4544
|
+
await client.workerCompleteReleaseSmoke(task.id, {
|
|
4545
|
+
workerKey,
|
|
4546
|
+
leaseToken,
|
|
4547
|
+
appId: published.appId,
|
|
4548
|
+
appVersionId: published.appVersionId,
|
|
4549
|
+
sourceSha256: published.sourceHash,
|
|
4550
|
+
runtimeSha256: published.runtimeHash,
|
|
4551
|
+
});
|
|
4552
|
+
retainWorkspace = false;
|
|
4553
|
+
console.log(`Worker release smoke ${task.id} completed without an AI agent.`);
|
|
4554
|
+
return;
|
|
4555
|
+
}
|
|
4551
4556
|
if (cleanRoom) {
|
|
4552
4557
|
const playdropMetadata = assignment.task.metadata.playdrop;
|
|
4553
4558
|
const postAgentAction = playdropMetadata && typeof playdropMetadata === 'object' && !Array.isArray(playdropMetadata)
|
|
@@ -5538,6 +5543,9 @@ async function uploadTask(options = {}) {
|
|
|
5538
5543
|
if (taskContext.kind === 'GAME_REVIEW' || taskContext.kind === 'GAME_EVAL') {
|
|
5539
5544
|
throw new Error('task_upload_not_allowed_for_game_review');
|
|
5540
5545
|
}
|
|
5546
|
+
if (taskContext.kind === 'RELEASE_SMOKE') {
|
|
5547
|
+
throw new Error('task_upload_not_allowed_for_release_smoke');
|
|
5548
|
+
}
|
|
5541
5549
|
const uploadKind = taskContext.kind;
|
|
5542
5550
|
const workspaceDir = resolveTaskWorkspaceDir();
|
|
5543
5551
|
if (options.preflightOnly) {
|
|
@@ -5567,7 +5575,7 @@ async function uploadTask(options = {}) {
|
|
|
5567
5575
|
for (const warning of result.warnings) {
|
|
5568
5576
|
console.error(`Preflight warning: ${warning}`);
|
|
5569
5577
|
}
|
|
5570
|
-
(0, output_1.printSuccess)(`Task upload preflight passed for ${result.creatorUsername}/${result.appName}.
|
|
5578
|
+
(0, output_1.printSuccess)(`Task upload preflight passed for ${result.creatorUsername}/${result.appName}. Upload can start.`);
|
|
5571
5579
|
return;
|
|
5572
5580
|
}
|
|
5573
5581
|
if ((0, node_fs_1.existsSync)(workerTaskUploadResultPath(workspaceDir))) {
|
package/dist/index.js
CHANGED
|
@@ -273,7 +273,7 @@ task
|
|
|
273
273
|
task
|
|
274
274
|
.command('upload')
|
|
275
275
|
.description('Upload the active agent task project as a private draft')
|
|
276
|
-
.option('--preflight-only', 'Run non-mutating
|
|
276
|
+
.option('--preflight-only', 'Run non-mutating checks without uploading')
|
|
277
277
|
.option('--env <env>', 'Environment override')
|
|
278
278
|
.action(async (opts) => {
|
|
279
279
|
await (0, worker_1.uploadTask)(opts);
|
|
@@ -1,35 +1,12 @@
|
|
|
1
|
-
import type { RecordAppUploadMediaCaptureRequest } from '@playdrop/types';
|
|
2
|
-
import type { AppTask } from './catalogue';
|
|
3
|
-
export type ListingMediaFile = {
|
|
4
|
-
fileKey: string;
|
|
5
|
-
sha256: string;
|
|
6
|
-
};
|
|
7
1
|
export type WorkerUploadPreflightContext = {
|
|
8
2
|
kind: 'NEW_GAME' | 'REMIX_GAME' | 'GAME_UPDATE';
|
|
9
3
|
target: 'FIRST_PARTY' | 'PERSONAL';
|
|
10
4
|
creatorUsername: string;
|
|
11
5
|
creatorRequest: string;
|
|
6
|
+
outputVersion?: string;
|
|
12
7
|
tweaks?: {
|
|
13
8
|
id: string;
|
|
14
9
|
values: Record<string, string | number | boolean>;
|
|
15
10
|
};
|
|
16
11
|
};
|
|
17
|
-
export declare function readMediaCaptureProof(input: {
|
|
18
|
-
task: AppTask;
|
|
19
|
-
preparedSessionFiles: ListingMediaFile[];
|
|
20
|
-
expectedRuntimeBundleHash?: string;
|
|
21
|
-
}): RecordAppUploadMediaCaptureRequest;
|
|
22
12
|
export declare function readWorkerUploadPreflightContext(projectDir: string): WorkerUploadPreflightContext | null;
|
|
23
|
-
export declare function assertAgentGameHeroListingPreflight(task: AppTask): void;
|
|
24
|
-
export declare function assertAgentGameIconListingPreflight(task: AppTask): void;
|
|
25
|
-
export declare function assertAgentGameVideoListingPreflight(task: AppTask): void;
|
|
26
|
-
export declare function assertAgentGamePreviewListingPreflight(task: AppTask): void;
|
|
27
|
-
export declare function assertAgentGameScreenshotListingPreflight(task: AppTask): void;
|
|
28
|
-
export declare function assertAgentGameCaptureReportPreflight(task: AppTask, options: {
|
|
29
|
-
requireCaptureReport: boolean;
|
|
30
|
-
expectedRuntimeBundleHash?: string;
|
|
31
|
-
}): void;
|
|
32
|
-
export declare function assertAgentGameListingPreflight(task: AppTask, options: {
|
|
33
|
-
requireCaptureReport: boolean;
|
|
34
|
-
}): void;
|
|
35
|
-
export declare function assertProjectListingPreflight(task: AppTask): void;
|
package/dist/listingPreflight.js
CHANGED
|
@@ -1,253 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.readMediaCaptureProof = readMediaCaptureProof;
|
|
4
3
|
exports.readWorkerUploadPreflightContext = readWorkerUploadPreflightContext;
|
|
5
|
-
exports.assertAgentGameHeroListingPreflight = assertAgentGameHeroListingPreflight;
|
|
6
|
-
exports.assertAgentGameIconListingPreflight = assertAgentGameIconListingPreflight;
|
|
7
|
-
exports.assertAgentGameVideoListingPreflight = assertAgentGameVideoListingPreflight;
|
|
8
|
-
exports.assertAgentGamePreviewListingPreflight = assertAgentGamePreviewListingPreflight;
|
|
9
|
-
exports.assertAgentGameScreenshotListingPreflight = assertAgentGameScreenshotListingPreflight;
|
|
10
|
-
exports.assertAgentGameCaptureReportPreflight = assertAgentGameCaptureReportPreflight;
|
|
11
|
-
exports.assertAgentGameListingPreflight = assertAgentGameListingPreflight;
|
|
12
|
-
exports.assertProjectListingPreflight = assertProjectListingPreflight;
|
|
13
|
-
const node_crypto_1 = require("node:crypto");
|
|
14
4
|
const node_fs_1 = require("node:fs");
|
|
15
5
|
const node_path_1 = require("node:path");
|
|
16
|
-
const MIN_HERO_PORTRAIT_WIDTH = 512;
|
|
17
|
-
const MIN_HERO_PORTRAIT_HEIGHT = 768;
|
|
18
|
-
const MIN_HERO_LANDSCAPE_WIDTH = 768;
|
|
19
|
-
const MIN_HERO_LANDSCAPE_HEIGHT = 432;
|
|
20
|
-
function readPngDimensions(filePath, errorCode = 'agent_task_listing_hero_art_invalid') {
|
|
21
|
-
const buffer = (0, node_fs_1.readFileSync)(filePath);
|
|
22
|
-
if (buffer.length < 24) {
|
|
23
|
-
throw new Error(`${errorCode}: ${filePath} is too small to be a valid PNG.`);
|
|
24
|
-
}
|
|
25
|
-
const isPng = (buffer[0] === 0x89
|
|
26
|
-
&& buffer[1] === 0x50
|
|
27
|
-
&& buffer[2] === 0x4e
|
|
28
|
-
&& buffer[3] === 0x47
|
|
29
|
-
&& buffer[4] === 0x0d
|
|
30
|
-
&& buffer[5] === 0x0a
|
|
31
|
-
&& buffer[6] === 0x1a
|
|
32
|
-
&& buffer[7] === 0x0a);
|
|
33
|
-
if (!isPng || buffer.toString('ascii', 12, 16) !== 'IHDR') {
|
|
34
|
-
throw new Error(`${errorCode}: ${filePath} must be a PNG with an IHDR header.`);
|
|
35
|
-
}
|
|
36
|
-
const width = buffer.readUInt32BE(16);
|
|
37
|
-
const height = buffer.readUInt32BE(20);
|
|
38
|
-
if (!Number.isInteger(width) || !Number.isInteger(height) || width <= 0 || height <= 0) {
|
|
39
|
-
throw new Error(`${errorCode}: ${filePath} has invalid PNG dimensions.`);
|
|
40
|
-
}
|
|
41
|
-
return { width, height };
|
|
42
|
-
}
|
|
43
|
-
function assertListingIcon(task, required = false) {
|
|
44
|
-
const iconPath = task.listing?.iconPath;
|
|
45
|
-
if (!iconPath) {
|
|
46
|
-
if (required) {
|
|
47
|
-
throw new Error('agent_task_listing_icon_missing: agent game listings must include a dedicated square PNG through listing.icon.');
|
|
48
|
-
}
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
|
-
const icon = readPngDimensions(iconPath, 'listing_icon_invalid');
|
|
52
|
-
if (icon.width !== icon.height) {
|
|
53
|
-
throw new Error(`listing_icon_not_square: listing.icon is ${icon.width}x${icon.height}; app icons must use a 1:1 aspect ratio.`);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
function readCatalogueApp(task) {
|
|
57
|
-
let data;
|
|
58
|
-
try {
|
|
59
|
-
data = JSON.parse((0, node_fs_1.readFileSync)(task.catalogueAbsolutePath, 'utf8'));
|
|
60
|
-
}
|
|
61
|
-
catch (error) {
|
|
62
|
-
const reason = error instanceof Error ? error.message : String(error);
|
|
63
|
-
throw new Error(`agent_task_catalogue_invalid_json: ${task.cataloguePath} must be valid JSON. ${reason}`);
|
|
64
|
-
}
|
|
65
|
-
const apps = Array.isArray(data?.apps) ? data.apps : [];
|
|
66
|
-
const app = apps.find((entry) => entry && typeof entry === 'object' && entry.name === task.name);
|
|
67
|
-
if (!app || typeof app !== 'object') {
|
|
68
|
-
throw new Error(`agent_task_catalogue_app_missing: ${task.cataloguePath} must contain apps[] entry "${task.name}".`);
|
|
69
|
-
}
|
|
70
|
-
return app;
|
|
71
|
-
}
|
|
72
|
-
function assertHeroListingKeys(task) {
|
|
73
|
-
const listing = readCatalogueApp(task).listing;
|
|
74
|
-
if (!listing || typeof listing !== 'object' || Array.isArray(listing)) {
|
|
75
|
-
return;
|
|
76
|
-
}
|
|
77
|
-
const hasLegacyPortrait = typeof listing.heroPortraitPath === 'string' && listing.heroPortraitPath.trim().length > 0;
|
|
78
|
-
const hasLegacyLandscape = typeof listing.heroLandscapePath === 'string' && listing.heroLandscapePath.trim().length > 0;
|
|
79
|
-
if (hasLegacyPortrait || hasLegacyLandscape) {
|
|
80
|
-
throw new Error('agent_task_listing_hero_art_legacy_keys: new game tasks must reference hero art through listing.heroPortrait and listing.heroLandscape, not listing.heroPortraitPath or listing.heroLandscapePath.');
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
function assertHeroListingPath(task, filePath, field) {
|
|
84
|
-
const relativePath = (0, node_path_1.relative)((0, node_path_1.resolve)(task.projectDir), (0, node_path_1.resolve)(filePath)).replace(/\\/g, '/');
|
|
85
|
-
if (relativePath === '' || relativePath === '..' || relativePath.startsWith('../') || relativePath.startsWith('/')) {
|
|
86
|
-
throw new Error(`agent_task_listing_hero_art_path_invalid: ${field} must point to a PNG inside the project under assets/marketing/playdrop/.`);
|
|
87
|
-
}
|
|
88
|
-
if (!relativePath.startsWith('assets/marketing/playdrop/') || (0, node_path_1.extname)(relativePath).toLowerCase() !== '.png') {
|
|
89
|
-
throw new Error(`agent_task_listing_hero_art_path_invalid: ${field} must point to a PNG under assets/marketing/playdrop/.`);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
function assertHeroListingArt(task) {
|
|
93
|
-
const heroPortraitPath = task.listing?.heroPortraitPath;
|
|
94
|
-
const heroLandscapePath = task.listing?.heroLandscapePath;
|
|
95
|
-
if (!heroPortraitPath || !heroLandscapePath) {
|
|
96
|
-
throw new Error('agent_task_listing_hero_art_missing: new game tasks must include listing.heroPortrait and listing.heroLandscape PNG assets.');
|
|
97
|
-
}
|
|
98
|
-
assertHeroListingKeys(task);
|
|
99
|
-
assertHeroListingPath(task, heroPortraitPath, 'listing.heroPortrait');
|
|
100
|
-
assertHeroListingPath(task, heroLandscapePath, 'listing.heroLandscape');
|
|
101
|
-
const portrait = readPngDimensions(heroPortraitPath);
|
|
102
|
-
if (portrait.width < MIN_HERO_PORTRAIT_WIDTH || portrait.height < MIN_HERO_PORTRAIT_HEIGHT || portrait.height <= portrait.width) {
|
|
103
|
-
throw new Error(`agent_task_listing_hero_art_invalid: listing.heroPortrait must be a portrait PNG at least ${MIN_HERO_PORTRAIT_WIDTH}x${MIN_HERO_PORTRAIT_HEIGHT}.`);
|
|
104
|
-
}
|
|
105
|
-
const landscape = readPngDimensions(heroLandscapePath);
|
|
106
|
-
if (landscape.width < MIN_HERO_LANDSCAPE_WIDTH || landscape.height < MIN_HERO_LANDSCAPE_HEIGHT || landscape.width <= landscape.height) {
|
|
107
|
-
throw new Error(`agent_task_listing_hero_art_invalid: listing.heroLandscape must be a landscape PNG at least ${MIN_HERO_LANDSCAPE_WIDTH}x${MIN_HERO_LANDSCAPE_HEIGHT}.`);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
function assertScreenshotPath(task, filePath, field) {
|
|
111
|
-
const relativePath = (0, node_path_1.relative)((0, node_path_1.resolve)(task.projectDir), (0, node_path_1.resolve)(filePath)).replace(/\\/g, '/');
|
|
112
|
-
const requiredPrefix = field === 'listing.screenshotsPortrait'
|
|
113
|
-
? 'assets/marketing/playdrop/screenshots/portrait/'
|
|
114
|
-
: 'assets/marketing/playdrop/screenshots/landscape/';
|
|
115
|
-
if (relativePath === '' || relativePath === '..' || relativePath.startsWith('../') || relativePath.startsWith('/')) {
|
|
116
|
-
throw new Error(`agent_task_listing_screenshots_path_invalid: ${field} entries must point to PNG files inside the project under ${requiredPrefix}.`);
|
|
117
|
-
}
|
|
118
|
-
if (!relativePath.startsWith(requiredPrefix) || (0, node_path_1.extname)(relativePath).toLowerCase() !== '.png') {
|
|
119
|
-
throw new Error(`agent_task_listing_screenshots_path_invalid: ${field} entries must point to PNG files under ${requiredPrefix}.`);
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
function assertListingScreenshots(task) {
|
|
123
|
-
const portraitPaths = task.listing?.screenshotPortraitPaths ?? [];
|
|
124
|
-
const landscapePaths = task.listing?.screenshotLandscapePaths ?? [];
|
|
125
|
-
for (const filePath of portraitPaths) {
|
|
126
|
-
assertScreenshotPath(task, filePath, 'listing.screenshotsPortrait');
|
|
127
|
-
readPngDimensions(filePath);
|
|
128
|
-
}
|
|
129
|
-
for (const filePath of landscapePaths) {
|
|
130
|
-
assertScreenshotPath(task, filePath, 'listing.screenshotsLandscape');
|
|
131
|
-
readPngDimensions(filePath);
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
function assertListingGameplayVideo(task) {
|
|
135
|
-
const videoCount = (task.listing?.videoPortraitPaths?.length ?? 0)
|
|
136
|
-
+ (task.listing?.videoLandscapePaths?.length ?? 0);
|
|
137
|
-
if (videoCount === 0) {
|
|
138
|
-
throw new Error('agent_task_listing_video_missing: agent game listings must include at least one real gameplay video through listing.videosPortrait or listing.videosLandscape.');
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
function assertListingPreviewMode(task) {
|
|
142
|
-
if (task.previewable !== true) {
|
|
143
|
-
throw new Error('agent_task_listing_preview_missing: agent game listings must set previewable: true and implement the real gameplay preview contract before capture.');
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
function isSha256Hex(value) {
|
|
147
|
-
return typeof value === 'string' && /^[a-f0-9]{64}$/i.test(value.trim());
|
|
148
|
-
}
|
|
149
|
-
function isCaptureVideoFileKey(fileKey) {
|
|
150
|
-
return fileKey.startsWith('videosPortrait:')
|
|
151
|
-
|| fileKey.startsWith('videosLandscape:');
|
|
152
|
-
}
|
|
153
|
-
function readMediaCaptureProof(input) {
|
|
154
|
-
const reportPath = input.task.listing?.captureReportPath;
|
|
155
|
-
if (!reportPath) {
|
|
156
|
-
throw new Error(`agent_task_media_capture_report_missing: ${input.task.name} must include listing.captureReport from "playdrop project capture".`);
|
|
157
|
-
}
|
|
158
|
-
let report;
|
|
159
|
-
try {
|
|
160
|
-
report = JSON.parse((0, node_fs_1.readFileSync)(reportPath, 'utf8'));
|
|
161
|
-
}
|
|
162
|
-
catch (error) {
|
|
163
|
-
const reason = error instanceof Error ? error.message : String(error);
|
|
164
|
-
throw new Error(`agent_task_media_capture_report_invalid: ${reportPath} must be valid JSON. ${reason}`);
|
|
165
|
-
}
|
|
166
|
-
const binding = report?.binding;
|
|
167
|
-
if (!binding || typeof binding !== 'object' || Array.isArray(binding)) {
|
|
168
|
-
throw new Error(`agent_task_media_capture_report_invalid: ${reportPath} is missing binding.`);
|
|
169
|
-
}
|
|
170
|
-
if (report.appName !== input.task.name) {
|
|
171
|
-
throw new Error(`agent_task_media_capture_wrong_app: listing.captureReport is for ${String(report.appName || 'unknown')}, not ${input.task.name}; rerun "playdrop project capture".`);
|
|
172
|
-
}
|
|
173
|
-
if (binding.pixelValidation !== 'passed') {
|
|
174
|
-
throw new Error(`agent_task_media_capture_pixels_unvalidated: ${reportPath} must come from a capture that passed wrong-game, black-frame, and motion checks.`);
|
|
175
|
-
}
|
|
176
|
-
if (input.expectedRuntimeBundleHash) {
|
|
177
|
-
const capturedRuntimeBundleHash = typeof binding.runtimeBundleHash === 'string'
|
|
178
|
-
? binding.runtimeBundleHash.trim().toLowerCase()
|
|
179
|
-
: '';
|
|
180
|
-
if (!isSha256Hex(capturedRuntimeBundleHash)) {
|
|
181
|
-
throw new Error(`agent_task_media_capture_report_invalid: ${reportPath} binding.runtimeBundleHash must be a SHA-256 hash.`);
|
|
182
|
-
}
|
|
183
|
-
if (capturedRuntimeBundleHash !== input.expectedRuntimeBundleHash.trim().toLowerCase()) {
|
|
184
|
-
throw new Error(`agent_task_media_capture_runtime_changed: ${input.task.name} changed after listing.captureReport was recorded; rerun "playdrop project capture".`);
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
const rawArtifactHashes = binding.artifactHashes;
|
|
188
|
-
if (!rawArtifactHashes || typeof rawArtifactHashes !== 'object' || Array.isArray(rawArtifactHashes)) {
|
|
189
|
-
throw new Error(`agent_task_media_capture_report_invalid: ${reportPath} binding.artifactHashes must be an object.`);
|
|
190
|
-
}
|
|
191
|
-
const captureArtifactHashEntries = Object.entries(rawArtifactHashes)
|
|
192
|
-
.filter(([artifactKey]) => (0, node_path_1.extname)(artifactKey).toLowerCase() === '.mp4')
|
|
193
|
-
.map(([, value]) => typeof value === 'string' ? value.trim().toLowerCase() : '')
|
|
194
|
-
.filter((value) => isSha256Hex(value));
|
|
195
|
-
const captureArtifactHashes = new Set(captureArtifactHashEntries);
|
|
196
|
-
if (captureArtifactHashEntries.length === 0) {
|
|
197
|
-
throw new Error(`agent_task_media_capture_report_invalid: ${reportPath} binding.artifactHashes must include at least one MP4 gameplay video.`);
|
|
198
|
-
}
|
|
199
|
-
const captureArtifactHashCounts = new Map();
|
|
200
|
-
for (const hash of captureArtifactHashEntries) {
|
|
201
|
-
captureArtifactHashCounts.set(hash, (captureArtifactHashCounts.get(hash) ?? 0) + 1);
|
|
202
|
-
}
|
|
203
|
-
const mediaFiles = input.preparedSessionFiles.filter((file) => isCaptureVideoFileKey(file.fileKey));
|
|
204
|
-
if (mediaFiles.length === 0) {
|
|
205
|
-
throw new Error(`agent_task_media_capture_artifacts_missing: ${input.task.name} must upload recorder gameplay video in listing.videos*.`);
|
|
206
|
-
}
|
|
207
|
-
const uploadedMediaHashCounts = new Map();
|
|
208
|
-
for (const file of mediaFiles) {
|
|
209
|
-
uploadedMediaHashCounts.set(file.sha256, (uploadedMediaHashCounts.get(file.sha256) ?? 0) + 1);
|
|
210
|
-
}
|
|
211
|
-
const missingUploadedCaptureArtifacts = [...captureArtifactHashCounts.entries()]
|
|
212
|
-
.filter(([hash, expectedCount]) => (uploadedMediaHashCounts.get(hash) ?? 0) < expectedCount);
|
|
213
|
-
if (missingUploadedCaptureArtifacts.length > 0) {
|
|
214
|
-
throw new Error(`agent_task_media_capture_artifact_missing_from_listing: ${input.task.name} must list every recorder gameplay video from listing.captureReport in catalogue.json.`);
|
|
215
|
-
}
|
|
216
|
-
let hasVideo = false;
|
|
217
|
-
const artifactHashes = {};
|
|
218
|
-
for (const file of mediaFiles) {
|
|
219
|
-
if (!captureArtifactHashes.has(file.sha256)) {
|
|
220
|
-
throw new Error(`agent_task_media_capture_artifact_mismatch: ${file.fileKey} was not produced by listing.captureReport for ${input.task.name}.`);
|
|
221
|
-
}
|
|
222
|
-
hasVideo = hasVideo || file.fileKey.startsWith('videos');
|
|
223
|
-
artifactHashes[file.fileKey] = file.sha256;
|
|
224
|
-
}
|
|
225
|
-
if (!hasVideo) {
|
|
226
|
-
throw new Error(`agent_task_media_capture_artifacts_missing: ${input.task.name} must upload at least one recorder gameplay video.`);
|
|
227
|
-
}
|
|
228
|
-
const capturedSurfaces = Array.isArray(binding.capturedSurfaces)
|
|
229
|
-
? Array.from(new Set(binding.capturedSurfaces
|
|
230
|
-
.map((surface) => typeof surface === 'string' ? surface.trim().toUpperCase() : '')
|
|
231
|
-
.filter((surface) => input.task.surfaceTargets.includes(surface))))
|
|
232
|
-
: [];
|
|
233
|
-
const capturedSurfaceSet = new Set(capturedSurfaces);
|
|
234
|
-
const missingSurfaces = input.task.surfaceTargets.filter((surface) => !capturedSurfaceSet.has(surface));
|
|
235
|
-
if (missingSurfaces.length > 0) {
|
|
236
|
-
throw new Error(`agent_task_media_capture_surface_missing: listing.captureReport did not capture ${missingSurfaces.join(', ')} for ${input.task.name}.`);
|
|
237
|
-
}
|
|
238
|
-
return { artifactHashes, capturedSurfaces };
|
|
239
|
-
}
|
|
240
|
-
function listingMediaFiles(task) {
|
|
241
|
-
const entries = [];
|
|
242
|
-
task.listing?.screenshotPortraitPaths.forEach((path, index) => entries.push([`screenshotsPortrait:${index}`, path]));
|
|
243
|
-
task.listing?.screenshotLandscapePaths.forEach((path, index) => entries.push([`screenshotsLandscape:${index}`, path]));
|
|
244
|
-
task.listing?.videoPortraitPaths.forEach((path, index) => entries.push([`videosPortrait:${index}`, path]));
|
|
245
|
-
task.listing?.videoLandscapePaths.forEach((path, index) => entries.push([`videosLandscape:${index}`, path]));
|
|
246
|
-
return entries.map(([fileKey, path]) => ({
|
|
247
|
-
fileKey,
|
|
248
|
-
sha256: (0, node_crypto_1.createHash)('sha256').update((0, node_fs_1.readFileSync)(path)).digest('hex'),
|
|
249
|
-
}));
|
|
250
|
-
}
|
|
251
6
|
function findWorkerTaskContextPath(projectDir) {
|
|
252
7
|
let current = (0, node_path_1.resolve)(projectDir);
|
|
253
8
|
while (true) {
|
|
@@ -303,6 +58,9 @@ function readWorkerUploadPreflightContext(projectDir) {
|
|
|
303
58
|
target,
|
|
304
59
|
creatorUsername: typeof playdrop.creatorUsername === 'string' ? playdrop.creatorUsername.trim() : '',
|
|
305
60
|
creatorRequest: typeof request.prompt === 'string' ? request.prompt.trim() : '',
|
|
61
|
+
...(typeof playdrop.output?.version === 'string' && playdrop.output.version.trim()
|
|
62
|
+
? { outputVersion: playdrop.output.version.trim() }
|
|
63
|
+
: {}),
|
|
306
64
|
...(playdrop.tweaks
|
|
307
65
|
&& typeof playdrop.tweaks === 'object'
|
|
308
66
|
&& !Array.isArray(playdrop.tweaks)
|
|
@@ -338,46 +96,3 @@ function readWorkerUploadPreflightContext(projectDir) {
|
|
|
338
96
|
: {}),
|
|
339
97
|
};
|
|
340
98
|
}
|
|
341
|
-
function assertAgentGameHeroListingPreflight(task) {
|
|
342
|
-
assertHeroListingArt(task);
|
|
343
|
-
}
|
|
344
|
-
function assertAgentGameIconListingPreflight(task) {
|
|
345
|
-
assertListingIcon(task, true);
|
|
346
|
-
}
|
|
347
|
-
function assertAgentGameVideoListingPreflight(task) {
|
|
348
|
-
assertListingGameplayVideo(task);
|
|
349
|
-
}
|
|
350
|
-
function assertAgentGamePreviewListingPreflight(task) {
|
|
351
|
-
assertListingPreviewMode(task);
|
|
352
|
-
}
|
|
353
|
-
function assertAgentGameScreenshotListingPreflight(task) {
|
|
354
|
-
assertListingScreenshots(task);
|
|
355
|
-
}
|
|
356
|
-
function assertAgentGameCaptureReportPreflight(task, options) {
|
|
357
|
-
if (options.requireCaptureReport || task.listing?.captureReportPath) {
|
|
358
|
-
readMediaCaptureProof({
|
|
359
|
-
task,
|
|
360
|
-
preparedSessionFiles: listingMediaFiles(task),
|
|
361
|
-
expectedRuntimeBundleHash: options.expectedRuntimeBundleHash,
|
|
362
|
-
});
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
|
-
function assertAgentGameListingPreflight(task, options) {
|
|
366
|
-
assertAgentGameIconListingPreflight(task);
|
|
367
|
-
assertAgentGameHeroListingPreflight(task);
|
|
368
|
-
assertAgentGamePreviewListingPreflight(task);
|
|
369
|
-
assertAgentGameVideoListingPreflight(task);
|
|
370
|
-
assertAgentGameScreenshotListingPreflight(task);
|
|
371
|
-
assertAgentGameCaptureReportPreflight(task, options);
|
|
372
|
-
}
|
|
373
|
-
function assertProjectListingPreflight(task) {
|
|
374
|
-
assertListingIcon(task);
|
|
375
|
-
const context = readWorkerUploadPreflightContext(task.projectDir);
|
|
376
|
-
if (context?.kind === 'NEW_GAME' || context?.kind === 'REMIX_GAME') {
|
|
377
|
-
assertAgentGameListingPreflight(task, { requireCaptureReport: context.target === 'FIRST_PARTY' });
|
|
378
|
-
return;
|
|
379
|
-
}
|
|
380
|
-
if (task.listing?.captureReportPath) {
|
|
381
|
-
readMediaCaptureProof({ task, preparedSessionFiles: listingMediaFiles(task) });
|
|
382
|
-
}
|
|
383
|
-
}
|