@playdrop/playdrop-cli 0.11.8 → 0.12.0
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/build.d.ts +1 -1
- package/dist/apps/build.js +4 -6
- package/dist/apps/index.d.ts +4 -5
- package/dist/apps/index.js +14 -16
- package/dist/apps/loadCheck.d.ts +76 -0
- package/dist/apps/loadCheck.js +874 -0
- package/dist/apps/upload.d.ts +3 -2
- package/dist/apps/upload.js +112 -9
- package/dist/assetSpecs.js +2 -5
- package/dist/catalogue-utils.d.ts +1 -0
- package/dist/catalogue-utils.js +1 -0
- package/dist/catalogue.d.ts +3 -1
- package/dist/catalogue.js +19 -3
- package/dist/commands/browse.js +2 -2
- package/dist/commands/build.js +4 -1
- package/dist/commands/captureListing.d.ts +30 -1
- package/dist/commands/captureListing.js +308 -125
- package/dist/commands/check.d.ts +8 -0
- package/dist/commands/check.js +188 -0
- package/dist/commands/create.js +17 -15
- package/dist/commands/createRemixContent.js +2 -2
- package/dist/commands/detail.js +2 -2
- package/dist/commands/dev.js +9 -12
- package/dist/commands/devServer.d.ts +2 -2
- package/dist/commands/devServer.js +3 -4
- package/dist/commands/marketing.js +10 -11
- package/dist/commands/play.js +2 -2
- package/dist/commands/review.d.ts +20 -0
- package/dist/commands/review.js +112 -0
- package/dist/commands/upload-content.d.ts +1 -1
- package/dist/commands/upload-content.js +1 -1
- package/dist/commands/upload.d.ts +2 -1
- package/dist/commands/upload.js +9 -52
- package/dist/commands/validate.js +4 -161
- package/dist/commands/worker/runtime.d.ts +1 -0
- package/dist/commands/worker/runtime.js +48 -5
- package/dist/commands/worker.d.ts +5 -6
- package/dist/commands/worker.js +42 -92
- package/dist/config.js +1 -2
- package/dist/index.js +33 -49
- package/dist/playwright.d.ts +5 -0
- package/dist/playwright.js +60 -1
- package/node_modules/@playdrop/api-client/dist/client.d.ts +5 -3
- package/node_modules/@playdrop/api-client/dist/client.d.ts.map +1 -1
- package/node_modules/@playdrop/api-client/dist/client.js +10 -27
- package/node_modules/@playdrop/api-client/dist/domains/admin.d.ts +1 -1
- package/node_modules/@playdrop/api-client/dist/domains/admin.d.ts.map +1 -1
- package/node_modules/@playdrop/api-client/dist/domains/apps.d.ts +2 -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 +11 -0
- package/node_modules/@playdrop/api-client/dist/domains/assets.d.ts +1 -1
- package/node_modules/@playdrop/api-client/dist/domains/assets.d.ts.map +1 -1
- package/node_modules/@playdrop/api-client/dist/domains/auth.d.ts +3 -1
- package/node_modules/@playdrop/api-client/dist/domains/auth.d.ts.map +1 -1
- package/node_modules/@playdrop/api-client/dist/domains/auth.js +22 -0
- package/node_modules/@playdrop/api-client/dist/domains/payments.d.ts +1 -1
- package/node_modules/@playdrop/api-client/dist/domains/payments.d.ts.map +1 -1
- package/node_modules/@playdrop/api-client/dist/index.d.ts +7 -6
- package/node_modules/@playdrop/api-client/dist/index.d.ts.map +1 -1
- package/node_modules/@playdrop/api-client/dist/index.js +11 -6
- package/node_modules/@playdrop/boxel-core/dist/src/entity-cleaner.js +0 -7
- package/node_modules/@playdrop/boxel-core/dist/src/entity-cleaner.js.map +1 -1
- package/node_modules/@playdrop/boxel-core/dist/src/humanoid/r15/textured-builder.js +2 -46
- package/node_modules/@playdrop/boxel-core/dist/src/humanoid/r15/textured-builder.js.map +1 -1
- package/node_modules/@playdrop/boxel-core/dist/src/humanoid/r15/voxel-builder.js +2 -22
- package/node_modules/@playdrop/boxel-core/dist/src/humanoid/r15/voxel-builder.js.map +1 -1
- package/node_modules/@playdrop/boxel-core/dist/src/palette_tools.js.map +1 -1
- package/node_modules/@playdrop/boxel-core/dist/src/serialization.js +1 -1
- package/node_modules/@playdrop/boxel-core/dist/src/serialization.js.map +1 -1
- package/node_modules/@playdrop/boxel-core/dist/src/transforms/textured-boxes/infer-face.js.map +1 -1
- package/node_modules/@playdrop/boxel-core/dist/src/transforms/textured-boxes/layer-mode.js +2 -2
- package/node_modules/@playdrop/boxel-core/dist/src/transforms/textured-boxes/layer-mode.js.map +1 -1
- package/node_modules/@playdrop/boxel-core/dist/src/transforms/textured-boxes/slice.js +0 -11
- package/node_modules/@playdrop/boxel-core/dist/src/transforms/textured-boxes/slice.js.map +1 -1
- package/node_modules/@playdrop/boxel-core/dist/src/transforms/upscale.js.map +1 -1
- package/node_modules/@playdrop/boxel-core/dist/src/validation.d.ts +1 -1
- package/node_modules/@playdrop/boxel-core/dist/src/validation.js +0 -20
- package/node_modules/@playdrop/boxel-core/dist/src/validation.js.map +1 -1
- package/node_modules/@playdrop/boxel-three/dist/src/exporters/glb.d.ts +2 -2
- package/node_modules/@playdrop/boxel-three/dist/src/exporters/glb.js +2 -12
- package/node_modules/@playdrop/boxel-three/dist/src/voxels/faces.js +1 -125
- package/node_modules/@playdrop/config/client-meta.json +2 -2
- package/node_modules/@playdrop/config/dist/src/client-meta.d.ts +8 -0
- package/node_modules/@playdrop/config/dist/src/client-meta.d.ts.map +1 -0
- package/node_modules/@playdrop/config/dist/src/client-meta.js +51 -0
- package/node_modules/@playdrop/config/dist/src/deployment.d.ts.map +1 -1
- package/node_modules/@playdrop/config/dist/src/deployment.js +2 -32
- package/node_modules/@playdrop/config/dist/src/index.d.ts +2 -2
- package/node_modules/@playdrop/config/dist/src/index.d.ts.map +1 -1
- package/node_modules/@playdrop/config/dist/src/index.js +3 -29
- package/node_modules/@playdrop/config/dist/src/runtime-service-origins.d.ts +0 -1
- package/node_modules/@playdrop/config/dist/src/runtime-service-origins.d.ts.map +1 -1
- package/node_modules/@playdrop/config/dist/src/runtime-service-origins.js +21 -5
- package/node_modules/@playdrop/config/dist/src/server/fastify.d.ts +2 -2
- package/node_modules/@playdrop/config/dist/src/server/fastify.d.ts.map +1 -1
- package/node_modules/@playdrop/config/dist/src/server/fastify.js +0 -1
- package/node_modules/@playdrop/config/dist/test/runtime-service-origins.test.js +8 -0
- package/node_modules/@playdrop/config/dist/tsconfig.tsbuildinfo +1 -1
- package/node_modules/@playdrop/types/dist/api.d.ts +25 -24
- package/node_modules/@playdrop/types/dist/api.d.ts.map +1 -1
- package/node_modules/@playdrop/types/dist/api.js +5 -10
- package/node_modules/@playdrop/types/dist/version.d.ts +14 -0
- package/node_modules/@playdrop/types/dist/version.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/apps/launchCheck.d.ts +0 -39
- package/dist/apps/launchCheck.js +0 -414
- package/dist/captureRuntime.d.ts +0 -73
- package/dist/captureRuntime.js +0 -1021
- package/dist/commands/capture.d.ts +0 -14
- package/dist/commands/capture.js +0 -550
- package/dist/commands/captureRemote.d.ts +0 -17
- package/dist/commands/captureRemote.js +0 -394
- package/node_modules/@playdrop/types/dist/entity.d.ts +0 -31
- package/node_modules/@playdrop/types/dist/entity.d.ts.map +0 -1
- package/node_modules/@playdrop/types/dist/entity.js +0 -67
|
@@ -8,10 +8,10 @@ exports.buildAssetPackUploadPlans = buildAssetPackUploadPlans;
|
|
|
8
8
|
exports.uploadAssetTask = uploadAssetTask;
|
|
9
9
|
exports.uploadAssetSpecTask = uploadAssetSpecTask;
|
|
10
10
|
exports.uploadAssetPackTask = uploadAssetPackTask;
|
|
11
|
+
const types_1 = require("@playdrop/types");
|
|
11
12
|
const node_crypto_1 = require("node:crypto");
|
|
12
13
|
const node_fs_1 = require("node:fs");
|
|
13
14
|
const node_path_1 = require("node:path");
|
|
14
|
-
const types_1 = require("@playdrop/types");
|
|
15
15
|
const model_artifacts_1 = require("../assets/model-artifacts");
|
|
16
16
|
const assetSpecs_1 = require("../assetSpecs");
|
|
17
17
|
const EXTENSION_TO_FORMAT = {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ApiClient } from '@playdrop/api-client';
|
|
2
|
-
import type { UserResponse } from '@playdrop/types';
|
|
2
|
+
import type { AgentExecutionTarget, UserResponse } from '@playdrop/types';
|
|
3
3
|
export type UploadCommandOptions = {
|
|
4
4
|
env?: string;
|
|
5
5
|
skipReview?: boolean;
|
|
@@ -10,6 +10,7 @@ export type WorkerAppPublishInput = {
|
|
|
10
10
|
client: ApiClient;
|
|
11
11
|
taskId: number;
|
|
12
12
|
kind: 'NEW_GAME' | 'REMIX_GAME' | 'GAME_UPDATE';
|
|
13
|
+
executionTarget?: AgentExecutionTarget;
|
|
13
14
|
expectedAppName?: string | null;
|
|
14
15
|
remixSourceRef?: string | null;
|
|
15
16
|
playdropAssetRequirement?: WorkerPlaydropAssetRequirement | null;
|
package/dist/commands/upload.js
CHANGED
|
@@ -50,7 +50,6 @@ const taskUtils_1 = require("../taskUtils");
|
|
|
50
50
|
const uploadLog_1 = require("../uploadLog");
|
|
51
51
|
const upload_content_1 = require("./upload-content");
|
|
52
52
|
const appUrls_1 = require("../appUrls");
|
|
53
|
-
const launchCheck_1 = require("../apps/launchCheck");
|
|
54
53
|
const devRuntimeAssets_1 = require("./devRuntimeAssets");
|
|
55
54
|
const upload_graph_1 = require("./upload-graph");
|
|
56
55
|
function normalizeSavedItemKinds(kinds) {
|
|
@@ -856,8 +855,6 @@ async function uploadAppTask(state, task, taskCreator, options) {
|
|
|
856
855
|
webBase: state.portalBase,
|
|
857
856
|
token: state.token,
|
|
858
857
|
user: state.currentUser,
|
|
859
|
-
runLocalLaunchCheck: true,
|
|
860
|
-
runStagedUploadLaunchCheck: true,
|
|
861
858
|
ensureRegisteredAppShell: true,
|
|
862
859
|
});
|
|
863
860
|
if (!upload.versionCreated || !upload.version) {
|
|
@@ -2137,7 +2134,7 @@ function assertNewGameListingScreenshots(task) {
|
|
|
2137
2134
|
function readPlaytestEvidenceManifest(task) {
|
|
2138
2135
|
const manifestPath = (0, node_path_1.join)(task.projectDir, 'playtest-evidence.json');
|
|
2139
2136
|
if (!(0, node_fs_1.existsSync)(manifestPath)) {
|
|
2140
|
-
throw new Error(formatMissingPlaytestEvidenceManifestError('
|
|
2137
|
+
throw new Error(formatMissingPlaytestEvidenceManifestError('task uploads must include playtest-evidence.json before upload.'));
|
|
2141
2138
|
}
|
|
2142
2139
|
try {
|
|
2143
2140
|
const value = JSON.parse((0, node_fs_1.readFileSync)(manifestPath, 'utf8'));
|
|
@@ -2183,7 +2180,7 @@ function assertPlaytestCapturePaths(task, captures) {
|
|
|
2183
2180
|
}
|
|
2184
2181
|
}
|
|
2185
2182
|
}
|
|
2186
|
-
function
|
|
2183
|
+
function assertTaskPlaytestEvidenceManifest(task) {
|
|
2187
2184
|
const manifest = readPlaytestEvidenceManifest(task);
|
|
2188
2185
|
const entries = Array.isArray(manifest.entries) ? manifest.entries : [];
|
|
2189
2186
|
if (entries.length === 0) {
|
|
@@ -2222,28 +2219,6 @@ function assertNewGamePlaytestEvidenceManifest(task) {
|
|
|
2222
2219
|
throw new Error(formatPlaytestEvidenceManifestError(`playtest-evidence.json must include a non-final self-playtest checkedAt after the last source change${sourceLastModifiedAt ? ` (${sourceLastModifiedAt})` : ''}.`));
|
|
2223
2220
|
}
|
|
2224
2221
|
}
|
|
2225
|
-
function writeFinalPublishedRouteEvidence(input) {
|
|
2226
|
-
const manifest = readPlaytestEvidenceManifest(input.task);
|
|
2227
|
-
const entries = Array.isArray(manifest.entries) ? manifest.entries : [];
|
|
2228
|
-
const finalEntry = {
|
|
2229
|
-
environment: 'final',
|
|
2230
|
-
url: input.url,
|
|
2231
|
-
surface: 'DESKTOP',
|
|
2232
|
-
captures: [],
|
|
2233
|
-
actions: ['open owner draft play URL'],
|
|
2234
|
-
statesObserved: input.status === 'PASSED' ? ['ready', 'nonblank-first-frame'] : [],
|
|
2235
|
-
consoleErrors: input.message ? [input.message] : [],
|
|
2236
|
-
checkedAt: input.checkedAt,
|
|
2237
|
-
sourceLastModifiedAt: readRuntimeSourceLastModifiedAt(input.task.projectDir),
|
|
2238
|
-
};
|
|
2239
|
-
const nextManifest = {
|
|
2240
|
-
...manifest,
|
|
2241
|
-
version: 1,
|
|
2242
|
-
entries: [...entries, finalEntry],
|
|
2243
|
-
finalPublishedRoute: finalEntry,
|
|
2244
|
-
};
|
|
2245
|
-
(0, node_fs_1.writeFileSync)((0, node_path_1.join)(input.task.projectDir, 'playtest-evidence.json'), `${JSON.stringify(nextManifest, null, 2)}\n`, 'utf8');
|
|
2246
|
-
}
|
|
2247
2222
|
function readRuntimeSourceLastModifiedAt(rootDir) {
|
|
2248
2223
|
const root = (0, node_path_1.resolve)(rootDir);
|
|
2249
2224
|
let latest = 0;
|
|
@@ -2313,6 +2288,9 @@ async function publishWorkerAppProject(input) {
|
|
|
2313
2288
|
throw new Error(`agent_task_remix_ref_mismatch:${catalogueRemixRef}:${expectedRemixRef}`);
|
|
2314
2289
|
}
|
|
2315
2290
|
}
|
|
2291
|
+
if (input.kind === 'GAME_UPDATE') {
|
|
2292
|
+
assertTaskPlaytestEvidenceManifest(task);
|
|
2293
|
+
}
|
|
2316
2294
|
if (input.kind === 'NEW_GAME' || input.kind === 'REMIX_GAME') {
|
|
2317
2295
|
assertNewGameHeroListingArt(task);
|
|
2318
2296
|
}
|
|
@@ -2355,7 +2333,7 @@ async function publishWorkerAppProject(input) {
|
|
|
2355
2333
|
}
|
|
2356
2334
|
if (input.kind === 'NEW_GAME' || input.kind === 'REMIX_GAME') {
|
|
2357
2335
|
assertNewGameListingScreenshots(task);
|
|
2358
|
-
|
|
2336
|
+
assertTaskPlaytestEvidenceManifest(task);
|
|
2359
2337
|
}
|
|
2360
2338
|
const { upload: uploadResult, warnings } = await (0, apps_1.runAppPipeline)(input.client, task, {
|
|
2361
2339
|
creatorUsername,
|
|
@@ -2363,10 +2341,11 @@ async function publishWorkerAppProject(input) {
|
|
|
2363
2341
|
webBase: normalizePortalBase(input.webBase ?? undefined),
|
|
2364
2342
|
token: input.token,
|
|
2365
2343
|
user: input.user,
|
|
2366
|
-
|
|
2367
|
-
|
|
2344
|
+
runLocalLoadCheck: true,
|
|
2345
|
+
runStagedUploadLoadCheck: true,
|
|
2368
2346
|
ensureRegisteredAppShell: true,
|
|
2369
2347
|
agentTaskId: input.taskId,
|
|
2348
|
+
mediaCaptureRequired: input.executionTarget === 'FIRST_PARTY',
|
|
2370
2349
|
});
|
|
2371
2350
|
if (!uploadResult.versionCreated || !uploadResult.version) {
|
|
2372
2351
|
throw new Error(`App "${task.name}" upload did not return a created version.`);
|
|
@@ -2377,28 +2356,6 @@ async function publishWorkerAppProject(input) {
|
|
|
2377
2356
|
if (typeof uploadResult.versionNodeId !== 'string' || uploadResult.versionNodeId.trim().length === 0) {
|
|
2378
2357
|
throw new Error(`App "${task.name}" upload did not return versionNodeId.`);
|
|
2379
2358
|
}
|
|
2380
|
-
const finalPlayUrl = (0, appUrls_1.buildPlatformPrivateDraftPlayUrl)(input.webBase ?? null, {
|
|
2381
|
-
creatorUsername,
|
|
2382
|
-
appName: task.name,
|
|
2383
|
-
appType: task.type ?? 'GAME',
|
|
2384
|
-
version: uploadResult.version,
|
|
2385
|
-
});
|
|
2386
|
-
const finalPlayCheck = await (0, launchCheck_1.runPublishedHostedPlayCheck)({
|
|
2387
|
-
targetUrl: finalPlayUrl,
|
|
2388
|
-
surfaceTargets: task.surfaceTargets,
|
|
2389
|
-
token: input.token,
|
|
2390
|
-
currentUser: input.user,
|
|
2391
|
-
});
|
|
2392
|
-
writeFinalPublishedRouteEvidence({
|
|
2393
|
-
task,
|
|
2394
|
-
url: finalPlayUrl,
|
|
2395
|
-
checkedAt: finalPlayCheck.checkedAt,
|
|
2396
|
-
status: finalPlayCheck.status,
|
|
2397
|
-
message: finalPlayCheck.message,
|
|
2398
|
-
});
|
|
2399
|
-
if (finalPlayCheck.status !== 'PASSED') {
|
|
2400
|
-
throw new Error((0, launchCheck_1.formatHostedLaunchCheckFailure)(task.name, finalPlayCheck, 'final'));
|
|
2401
|
-
}
|
|
2402
2359
|
return {
|
|
2403
2360
|
appId: app.id,
|
|
2404
2361
|
appVersionId: uploadResult.versionId,
|
|
@@ -1,107 +1,15 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.validate = validate;
|
|
4
|
-
const node_fs_1 = require("node:fs");
|
|
5
|
-
const node_path_1 = require("node:path");
|
|
6
4
|
const types_1 = require("@playdrop/types");
|
|
7
|
-
const
|
|
5
|
+
const apps_1 = require("../apps");
|
|
6
|
+
const assetSpecs_1 = require("../assetSpecs");
|
|
8
7
|
const commandContext_1 = require("../commandContext");
|
|
8
|
+
const externalAssetPackValidation_1 = require("../externalAssetPackValidation");
|
|
9
9
|
const taskSelection_1 = require("../taskSelection");
|
|
10
10
|
const taskUtils_1 = require("../taskUtils");
|
|
11
11
|
const uploadLog_1 = require("../uploadLog");
|
|
12
|
-
const apps_1 = require("../apps");
|
|
13
|
-
const assetSpecs_1 = require("../assetSpecs");
|
|
14
|
-
const externalAssetPackValidation_1 = require("../externalAssetPackValidation");
|
|
15
|
-
const dev_1 = require("./dev");
|
|
16
12
|
const upload_content_1 = require("./upload-content");
|
|
17
|
-
function normalizePositivePort(value) {
|
|
18
|
-
const parsed = typeof value === 'number' ? value : Number.parseInt(String(value ?? ''), 10);
|
|
19
|
-
return Number.isInteger(parsed) && parsed > 0 && parsed <= 65535 ? parsed : null;
|
|
20
|
-
}
|
|
21
|
-
function findWorkspaceMetadataFile(startPath) {
|
|
22
|
-
let current = (0, node_path_1.resolve)(startPath);
|
|
23
|
-
if ((0, node_fs_1.existsSync)(current) && (0, node_fs_1.statSync)(current).isFile()) {
|
|
24
|
-
current = (0, node_path_1.dirname)(current);
|
|
25
|
-
}
|
|
26
|
-
while (true) {
|
|
27
|
-
const workspacePinPath = (0, node_path_1.join)(current, '.playdrop.json');
|
|
28
|
-
if ((0, node_fs_1.existsSync)(workspacePinPath) && (0, node_fs_1.statSync)(workspacePinPath).isFile()) {
|
|
29
|
-
return workspacePinPath;
|
|
30
|
-
}
|
|
31
|
-
const taskContextPath = (0, node_path_1.join)(current, '.playdrop', 'task.json');
|
|
32
|
-
if ((0, node_fs_1.existsSync)(taskContextPath) && (0, node_fs_1.statSync)(taskContextPath).isFile()) {
|
|
33
|
-
return taskContextPath;
|
|
34
|
-
}
|
|
35
|
-
const parent = (0, node_path_1.dirname)(current);
|
|
36
|
-
if (parent === current) {
|
|
37
|
-
return null;
|
|
38
|
-
}
|
|
39
|
-
current = parent;
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
function readTaskScopedDevRouterPort(workspacePath) {
|
|
43
|
-
const metadataPath = findWorkspaceMetadataFile(workspacePath);
|
|
44
|
-
if (!metadataPath) {
|
|
45
|
-
throw new Error('project_validate_task_dev_port_missing');
|
|
46
|
-
}
|
|
47
|
-
let parsed;
|
|
48
|
-
try {
|
|
49
|
-
parsed = JSON.parse((0, node_fs_1.readFileSync)(metadataPath, 'utf8'));
|
|
50
|
-
}
|
|
51
|
-
catch {
|
|
52
|
-
throw new Error(`project_validate_task_dev_port_invalid_json:${metadataPath}`);
|
|
53
|
-
}
|
|
54
|
-
const port = normalizePositivePort(parsed?.devPort);
|
|
55
|
-
if (!port) {
|
|
56
|
-
throw new Error(`project_validate_task_dev_port_missing:${metadataPath}`);
|
|
57
|
-
}
|
|
58
|
-
return { file: metadataPath, port };
|
|
59
|
-
}
|
|
60
|
-
function readWorkerTaskDevRouterPort() {
|
|
61
|
-
if (process.env.PLAYDROP_WORKER_CONTEXT !== '1') {
|
|
62
|
-
return null;
|
|
63
|
-
}
|
|
64
|
-
const workerPortRaw = process.env.PLAYDROP_WORKER_TASK_DEV_PORT;
|
|
65
|
-
if (!workerPortRaw?.trim()) {
|
|
66
|
-
throw new Error('project_validate_worker_dev_port_missing');
|
|
67
|
-
}
|
|
68
|
-
const workerPort = normalizePositivePort(workerPortRaw);
|
|
69
|
-
if (!workerPort) {
|
|
70
|
-
throw new Error(`project_validate_worker_dev_port_invalid:${workerPortRaw}`);
|
|
71
|
-
}
|
|
72
|
-
const devRouterPortRaw = process.env.PLAYDROP_DEV_ROUTER_PORT;
|
|
73
|
-
if (devRouterPortRaw?.trim()) {
|
|
74
|
-
const devRouterPort = normalizePositivePort(devRouterPortRaw);
|
|
75
|
-
if (!devRouterPort) {
|
|
76
|
-
throw new Error(`project_validate_env_dev_port_invalid:${devRouterPortRaw}`);
|
|
77
|
-
}
|
|
78
|
-
if (devRouterPort !== workerPort) {
|
|
79
|
-
throw new Error(`project_validate_worker_dev_port_mismatch:env=${devRouterPort}:worker=${workerPort}`);
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
return workerPort;
|
|
83
|
-
}
|
|
84
|
-
function resolveValidationDevRouterPort(workspacePath, taskScoped) {
|
|
85
|
-
if (!taskScoped) {
|
|
86
|
-
return (0, dev_1.resolveCliDevRouterPort)();
|
|
87
|
-
}
|
|
88
|
-
const workerPort = readWorkerTaskDevRouterPort();
|
|
89
|
-
if (workerPort !== null) {
|
|
90
|
-
return workerPort;
|
|
91
|
-
}
|
|
92
|
-
const taskPort = readTaskScopedDevRouterPort(workspacePath);
|
|
93
|
-
const envPortRaw = process.env.PLAYDROP_DEV_ROUTER_PORT;
|
|
94
|
-
if (envPortRaw !== undefined && envPortRaw.trim()) {
|
|
95
|
-
const envPort = normalizePositivePort(envPortRaw);
|
|
96
|
-
if (!envPort) {
|
|
97
|
-
throw new Error(`project_validate_env_dev_port_invalid:${envPortRaw}`);
|
|
98
|
-
}
|
|
99
|
-
if (envPort !== taskPort.port) {
|
|
100
|
-
throw new Error(`project_validate_worker_dev_port_mismatch:env=${envPort}:task=${taskPort.port}:${taskPort.file}`);
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
return taskPort.port;
|
|
104
|
-
}
|
|
105
13
|
function buildLocalAssetSpecLookups(tasks) {
|
|
106
14
|
const exactByRef = new Map();
|
|
107
15
|
const uniqueByNameVersion = new Map();
|
|
@@ -127,7 +35,7 @@ function resolveLocalAssetSpecTask(task, lookups) {
|
|
|
127
35
|
if (direct) {
|
|
128
36
|
return direct;
|
|
129
37
|
}
|
|
130
|
-
const parsed = (0,
|
|
38
|
+
const parsed = (0, types_1.parseAssetSpecVersionRef)(task.assetSpec);
|
|
131
39
|
if (!parsed) {
|
|
132
40
|
return null;
|
|
133
41
|
}
|
|
@@ -173,42 +81,6 @@ async function loadAuthenticatedValidationContext(workspacePath, envOverride) {
|
|
|
173
81
|
return null;
|
|
174
82
|
}
|
|
175
83
|
}
|
|
176
|
-
async function loadHostedLaunchValidationContext(workspacePath, envOverride) {
|
|
177
|
-
const ctx = await (0, commandContext_1.resolveAuthenticatedEnvironmentContext)('project validate', 'run hosted app launch validation', {
|
|
178
|
-
env: envOverride,
|
|
179
|
-
workspacePath,
|
|
180
|
-
});
|
|
181
|
-
if (!ctx) {
|
|
182
|
-
return null;
|
|
183
|
-
}
|
|
184
|
-
const username = typeof ctx.account?.username === 'string' ? ctx.account.username.trim() : '';
|
|
185
|
-
if (!username) {
|
|
186
|
-
process.exitCode = 1;
|
|
187
|
-
return null;
|
|
188
|
-
}
|
|
189
|
-
let currentUserRole = null;
|
|
190
|
-
let currentUser = null;
|
|
191
|
-
try {
|
|
192
|
-
const me = await ctx.client.me();
|
|
193
|
-
currentUserRole = me.user.role ?? null;
|
|
194
|
-
currentUser = me.user ?? null;
|
|
195
|
-
}
|
|
196
|
-
catch {
|
|
197
|
-
currentUserRole = null;
|
|
198
|
-
currentUser = null;
|
|
199
|
-
}
|
|
200
|
-
return {
|
|
201
|
-
client: ctx.client,
|
|
202
|
-
currentUserRole,
|
|
203
|
-
currentUser,
|
|
204
|
-
username,
|
|
205
|
-
apiBase: ctx.envConfig.apiBase,
|
|
206
|
-
webBase: ctx.envConfig.webBase ?? null,
|
|
207
|
-
token: ctx.token,
|
|
208
|
-
devRouterPort: resolveValidationDevRouterPort(workspacePath, Boolean(ctx.workspaceAuth?.config.taskToken)),
|
|
209
|
-
taskScoped: Boolean(ctx.workspaceAuth?.config.taskToken),
|
|
210
|
-
};
|
|
211
|
-
}
|
|
212
84
|
function printResolvedValidationAccount(ctx) {
|
|
213
85
|
const username = typeof ctx.account?.username === 'string' && ctx.account.username.trim().length > 0
|
|
214
86
|
? ctx.account.username.trim()
|
|
@@ -222,7 +94,6 @@ function formatLiveTagClearWarning(input) {
|
|
|
222
94
|
const countLabel = input.liveTagCount === 1 ? '1 existing live tag' : `${input.liveTagCount} existing live tags`;
|
|
223
95
|
return `${input.entityLabel} "${input.displayName}" would remove ${countLabel} on publish. Add a tags field or pass --clear-tags to confirm.`;
|
|
224
96
|
}
|
|
225
|
-
// eslint-disable-next-line complexity
|
|
226
97
|
async function collectLiveTagClearWarnings(tasks, workspacePath, envOverride) {
|
|
227
98
|
const context = await loadAuthenticatedValidationContext(workspacePath, envOverride);
|
|
228
99
|
if (!context) {
|
|
@@ -316,40 +187,12 @@ async function validate(pathOrName, options = {}) {
|
|
|
316
187
|
const assetSpecTasks = tasks.filter((task) => task.kind === 'asset-spec');
|
|
317
188
|
const assetSpecLookups = buildLocalAssetSpecLookups(assetSpecTasks);
|
|
318
189
|
const sortedTasks = (0, taskUtils_1.sortTasks)(tasks);
|
|
319
|
-
const hostedLaunchValidationRequired = sortedTasks.some((task) => task.kind === 'app' && task.hostingMode !== 'EXTERNAL' && !task.externalUrl);
|
|
320
|
-
const hostedLaunchValidationContext = hostedLaunchValidationRequired
|
|
321
|
-
? await loadHostedLaunchValidationContext(workspacePath, options.env)
|
|
322
|
-
: null;
|
|
323
|
-
if (hostedLaunchValidationRequired && !hostedLaunchValidationContext) {
|
|
324
|
-
return;
|
|
325
|
-
}
|
|
326
190
|
for (const task of sortedTasks) {
|
|
327
191
|
const entityId = task.name;
|
|
328
192
|
try {
|
|
329
193
|
if (task.kind === 'app') {
|
|
330
194
|
await (0, apps_1.validateAppTask)(task);
|
|
331
195
|
(0, apps_1.collectAppValidationWarnings)(task, 'source').forEach((warning) => warnings.add(warning));
|
|
332
|
-
if (task.hostingMode !== 'EXTERNAL' && !task.externalUrl) {
|
|
333
|
-
const launchContext = hostedLaunchValidationContext;
|
|
334
|
-
const creatorResult = (0, upload_content_1.getTaskCreatorResult)(task, launchContext.username, launchContext.currentUserRole);
|
|
335
|
-
if (creatorResult.creatorTargetError) {
|
|
336
|
-
throw new Error(creatorResult.creatorTargetError);
|
|
337
|
-
}
|
|
338
|
-
const launchCheck = await (0, apps_1.runLocalHostedLaunchCheck)({
|
|
339
|
-
client: launchContext.client,
|
|
340
|
-
apiBase: launchContext.apiBase,
|
|
341
|
-
webBase: launchContext.webBase,
|
|
342
|
-
creatorUsername: creatorResult.taskCreator,
|
|
343
|
-
task,
|
|
344
|
-
token: launchContext.token,
|
|
345
|
-
currentUser: launchContext.currentUser,
|
|
346
|
-
devRouterPort: launchContext.devRouterPort,
|
|
347
|
-
allowUnregisteredViewerLaunch: launchContext.taskScoped,
|
|
348
|
-
});
|
|
349
|
-
if (launchCheck.status !== 'PASSED') {
|
|
350
|
-
throw new Error((0, apps_1.formatHostedLaunchCheckFailure)(task.name, launchCheck, 'local'));
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
196
|
}
|
|
354
197
|
else if (task.kind === 'asset-spec') {
|
|
355
198
|
// Parsing already validates the contract, symbol, and documentation files.
|
|
@@ -66,6 +66,7 @@ export declare function readCodexSandboxMode(env?: NodeJS.ProcessEnv): CodexSand
|
|
|
66
66
|
export declare function buildClaudeExecArgs(input: {
|
|
67
67
|
model: string;
|
|
68
68
|
effort?: string | null;
|
|
69
|
+
chrome?: boolean;
|
|
69
70
|
workspaceDir?: string | null;
|
|
70
71
|
denyReadRoots?: string[] | null;
|
|
71
72
|
pluginDir?: string | null;
|
|
@@ -34,6 +34,9 @@ function tailText(value, maxChars) {
|
|
|
34
34
|
}
|
|
35
35
|
return value.slice(value.length - maxChars);
|
|
36
36
|
}
|
|
37
|
+
function throwLoggedProcessError(error) {
|
|
38
|
+
throw error;
|
|
39
|
+
}
|
|
37
40
|
function readPositiveEnvInt(name, fallback) {
|
|
38
41
|
const raw = process.env[name]?.trim();
|
|
39
42
|
if (!raw) {
|
|
@@ -351,7 +354,7 @@ async function runLoggedProcess(input) {
|
|
|
351
354
|
return transcriptFlushPromise;
|
|
352
355
|
};
|
|
353
356
|
const handleTranscriptFlushError = (error) => {
|
|
354
|
-
transcriptFlushError = transcriptFlushError ?? error;
|
|
357
|
+
transcriptFlushError = transcriptFlushError ?? (error instanceof Error ? error : new Error(String(error)));
|
|
355
358
|
if (!closed) {
|
|
356
359
|
child.kill('SIGTERM');
|
|
357
360
|
}
|
|
@@ -403,7 +406,7 @@ async function runLoggedProcess(input) {
|
|
|
403
406
|
void (async () => {
|
|
404
407
|
await queueTranscriptFlush();
|
|
405
408
|
if (transcriptFlushError) {
|
|
406
|
-
|
|
409
|
+
throwLoggedProcessError(transcriptFlushError);
|
|
407
410
|
}
|
|
408
411
|
const outputTail = tailText(combined, input.maxOutputChars);
|
|
409
412
|
const tokenUsage = extractAgentTokenUsage(`${stdout}\n${stderr}\n${outputTail}`);
|
|
@@ -458,7 +461,13 @@ function buildClaudeExecArgs(input) {
|
|
|
458
461
|
throw new Error('agent_task_assignment_model_missing');
|
|
459
462
|
}
|
|
460
463
|
const permissionSettings = buildClaudePermissionSettings(input.denyReadRoots ?? []);
|
|
461
|
-
const
|
|
464
|
+
const permissionMode = input.chrome ? 'bypassPermissions' : 'acceptEdits';
|
|
465
|
+
const tools = input.chrome
|
|
466
|
+
? [...CLAUDE_BASE_TOOL_NAMES, ...CLAUDE_CHROME_TOOL_NAMES].join(',')
|
|
467
|
+
: CLAUDE_BASE_TOOL_NAMES.join(',');
|
|
468
|
+
const allowedTools = input.chrome
|
|
469
|
+
? [...CLAUDE_ALLOWED_PERMISSION_RULES, ...CLAUDE_CHROME_TOOL_NAMES]
|
|
470
|
+
: CLAUDE_ALLOWED_PERMISSION_RULES;
|
|
462
471
|
const args = [
|
|
463
472
|
'-p',
|
|
464
473
|
'--model',
|
|
@@ -469,16 +478,19 @@ function buildClaudeExecArgs(input) {
|
|
|
469
478
|
'--include-partial-messages',
|
|
470
479
|
'--no-session-persistence',
|
|
471
480
|
'--permission-mode',
|
|
472
|
-
|
|
481
|
+
permissionMode,
|
|
473
482
|
'--tools',
|
|
474
483
|
tools,
|
|
475
484
|
'--allowedTools',
|
|
476
|
-
...
|
|
485
|
+
...allowedTools,
|
|
477
486
|
'--disallowedTools',
|
|
478
487
|
...buildClaudeDeniedPermissionRules(input.denyReadRoots ?? []),
|
|
479
488
|
'--settings',
|
|
480
489
|
JSON.stringify(permissionSettings),
|
|
481
490
|
];
|
|
491
|
+
if (input.chrome) {
|
|
492
|
+
args.unshift('--chrome');
|
|
493
|
+
}
|
|
482
494
|
const pluginDir = typeof input.pluginDir === 'string' ? input.pluginDir.trim() : '';
|
|
483
495
|
if (pluginDir) {
|
|
484
496
|
args.push('--plugin-dir', pluginDir);
|
|
@@ -489,6 +501,37 @@ function buildClaudeExecArgs(input) {
|
|
|
489
501
|
}
|
|
490
502
|
return args;
|
|
491
503
|
}
|
|
504
|
+
const CLAUDE_BASE_TOOL_NAMES = [
|
|
505
|
+
'Bash',
|
|
506
|
+
'Edit',
|
|
507
|
+
'Write',
|
|
508
|
+
'Read',
|
|
509
|
+
'Glob',
|
|
510
|
+
'Grep',
|
|
511
|
+
];
|
|
512
|
+
const CLAUDE_CHROME_TOOL_NAMES = [
|
|
513
|
+
'mcp__claude-in-chrome__browser_batch',
|
|
514
|
+
'mcp__claude-in-chrome__computer',
|
|
515
|
+
'mcp__claude-in-chrome__file_upload',
|
|
516
|
+
'mcp__claude-in-chrome__find',
|
|
517
|
+
'mcp__claude-in-chrome__form_input',
|
|
518
|
+
'mcp__claude-in-chrome__get_page_text',
|
|
519
|
+
'mcp__claude-in-chrome__javascript_tool',
|
|
520
|
+
'mcp__claude-in-chrome__list_connected_browsers',
|
|
521
|
+
'mcp__claude-in-chrome__navigate',
|
|
522
|
+
'mcp__claude-in-chrome__read_console_messages',
|
|
523
|
+
'mcp__claude-in-chrome__read_network_requests',
|
|
524
|
+
'mcp__claude-in-chrome__read_page',
|
|
525
|
+
'mcp__claude-in-chrome__resize_window',
|
|
526
|
+
'mcp__claude-in-chrome__select_browser',
|
|
527
|
+
'mcp__claude-in-chrome__shortcuts_execute',
|
|
528
|
+
'mcp__claude-in-chrome__shortcuts_list',
|
|
529
|
+
'mcp__claude-in-chrome__switch_browser',
|
|
530
|
+
'mcp__claude-in-chrome__tabs_close_mcp',
|
|
531
|
+
'mcp__claude-in-chrome__tabs_context_mcp',
|
|
532
|
+
'mcp__claude-in-chrome__tabs_create_mcp',
|
|
533
|
+
'mcp__claude-in-chrome__upload_image',
|
|
534
|
+
];
|
|
492
535
|
const CLAUDE_ALLOWED_PERMISSION_RULES = [
|
|
493
536
|
'Read',
|
|
494
537
|
'Edit',
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type { ApiClient } from '@playdrop/api-client';
|
|
2
|
-
import { type
|
|
2
|
+
import { type AgentExecutionTarget, type AgentRuntime, type AgentTaskKind, type AgentTaskNextStepSuggestion, type AgentTaskResponse, type AgentWorkerCapabilities, type AgentWorkerResponse, type WorkerAgentTaskAssignmentResponse, type WorkerAgentTaskBaseSourceResponse, type WorkerAgentTaskWorkspaceFileResponse, type WorkerClaimAgentTaskResponse } from '@playdrop/types';
|
|
3
3
|
import { type WorkerPlaydropAssetRequirement } from './upload';
|
|
4
4
|
import { type LoggedProcessResult, type LoggedProcessTranscriptChunk } from './worker/runtime';
|
|
5
|
-
export {
|
|
6
|
-
export type { AgentTokenUsage, LoggedProcessResult, LoggedProcessTranscriptChunk
|
|
5
|
+
export { assertWorkerTokenUsageWithinCap, buildClaudeExecArgs, buildClaudePermissionSettings, buildCodexExecArgs, buildWorkerChildEnv, DEFAULT_CODEX_TIMEOUT_MS, DEFAULT_WORKER_TOKEN_CAP, extractAgentTokenUsage, extractCodexRolloutTokenUsage, extractCodexThreadId, extractCodexTokensUsed, readCodexRolloutTokenUsageForThread, readCodexSandboxMode, readEnvBoolean, runLoggedProcess } from './worker/runtime';
|
|
6
|
+
export type { AgentTokenUsage, LoggedProcessResult, LoggedProcessTranscriptChunk } from './worker/runtime';
|
|
7
7
|
export declare const WORKER_SESSION_EXPIRED_MESSAGE = "worker session expired: run \"playdrop auth login\" and start the worker again";
|
|
8
|
-
export declare const WORKER_CONTEXT_COMMAND_NOT_ALLOWED_MESSAGE = "worker_context_command_not_allowed: inside a PlayDrop worker task only task progress, task claim-slug, task upload/done/fail, assigned app scaffolding, project validation/build/dev/capture, read-only help/catalogue/documentation lookup, and PlayDrop AI generation are permitted.";
|
|
8
|
+
export declare const WORKER_CONTEXT_COMMAND_NOT_ALLOWED_MESSAGE = "worker_context_command_not_allowed: inside a PlayDrop worker task only task progress, task claim-slug, task upload/done/fail, assigned app scaffolding, project validation/build/dev/check/capture, read-only help/catalogue/documentation lookup, and PlayDrop AI generation are permitted.";
|
|
9
9
|
type WorkerStartOptions = {
|
|
10
10
|
env?: string;
|
|
11
11
|
once?: boolean;
|
|
@@ -56,7 +56,7 @@ type WorkerStatusPayload = {
|
|
|
56
56
|
server: {
|
|
57
57
|
reachable: boolean;
|
|
58
58
|
authenticated: boolean;
|
|
59
|
-
worker:
|
|
59
|
+
worker: AgentWorkerResponse | null;
|
|
60
60
|
error?: string;
|
|
61
61
|
};
|
|
62
62
|
};
|
|
@@ -190,7 +190,6 @@ export declare function buildWorkerCapabilities(input: string | {
|
|
|
190
190
|
} | null;
|
|
191
191
|
maxParallelTasks?: number | null;
|
|
192
192
|
runningTaskCount?: number | null;
|
|
193
|
-
providerAccountLabel?: string | null;
|
|
194
193
|
}): AgentWorkerCapabilities;
|
|
195
194
|
export declare function buildWorkerClaimBody(input: {
|
|
196
195
|
workerKey: string;
|