@playdrop/playdrop-cli 0.10.20 → 0.11.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 +5 -1
- package/dist/appUrls.d.ts +3 -0
- package/dist/appUrls.js +12 -0
- package/dist/apps/build.js +3 -2
- package/dist/apps/launchCheck.d.ts +8 -1
- package/dist/apps/launchCheck.js +96 -10
- package/dist/apps/upload.js +5 -0
- package/dist/catalogue.d.ts +3 -1
- package/dist/catalogue.js +12 -0
- package/dist/commands/agents.js +30 -3
- package/dist/commands/clients.js +98 -1
- package/dist/commands/doctor.d.ts +8 -0
- package/dist/commands/doctor.js +50 -0
- package/dist/commands/generation.js +3 -0
- package/dist/commands/upload.js +346 -101
- package/dist/commands/worker/runtime.js +6 -0
- package/dist/commands/worker.d.ts +17 -1
- package/dist/commands/worker.js +155 -21
- package/dist/commands/workspaces.js +2 -1
- package/node_modules/@playdrop/config/client-meta.json +5 -1
- package/node_modules/@playdrop/config/dist/test/validateClientEnvironment.test.js +39 -0
- package/node_modules/@playdrop/config/dist/tsconfig.tsbuildinfo +1 -1
- package/node_modules/@playdrop/types/dist/api.d.ts +7 -2
- package/node_modules/@playdrop/types/dist/api.d.ts.map +1 -1
- package/node_modules/@playdrop/types/dist/api.js +2 -1
- package/node_modules/@playdrop/types/dist/version.d.ts +22 -0
- package/node_modules/@playdrop/types/dist/version.d.ts.map +1 -1
- package/node_modules/@playdrop/types/dist/version.js +108 -0
- package/package.json +5 -5
|
@@ -525,6 +525,12 @@ function normalizeClaudePermissionPath(value) {
|
|
|
525
525
|
if (!trimmed) {
|
|
526
526
|
return null;
|
|
527
527
|
}
|
|
528
|
+
if (/^\/[^/]/.test(trimmed)) {
|
|
529
|
+
return node_path_1.default.posix.resolve(trimmed).replace(/\/+$/, '');
|
|
530
|
+
}
|
|
531
|
+
if (/^[A-Za-z]:[\\/]/.test(trimmed) || /^\\\\/.test(trimmed)) {
|
|
532
|
+
return node_path_1.default.win32.resolve(trimmed).replace(/\\/g, '/').replace(/\/+$/, '');
|
|
533
|
+
}
|
|
528
534
|
return node_path_1.default.resolve(trimmed).replace(/\\/g, '/').replace(/\/+$/, '');
|
|
529
535
|
}
|
|
530
536
|
function buildClaudePermissionSettings(denyReadRoots = []) {
|
|
@@ -5,7 +5,7 @@ import { type LoggedProcessResult, type LoggedProcessTranscriptChunk } from './w
|
|
|
5
5
|
export { DEFAULT_CODEX_TIMEOUT_MS, DEFAULT_WORKER_TOKEN_CAP, assertWorkerTokenUsageWithinCap, buildCodexExecArgs, buildClaudeExecArgs, buildClaudePermissionSettings, buildWorkerChildEnv, extractAgentTokenUsage, extractCodexRolloutTokenUsage, extractCodexThreadId, extractCodexTokensUsed, readEnvBoolean, readCodexSandboxMode, readCodexRolloutTokenUsageForThread, runLoggedProcess, } from './worker/runtime';
|
|
6
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 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/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;
|
|
@@ -31,6 +31,7 @@ type WorkerLocalStatus = {
|
|
|
31
31
|
playwright: {
|
|
32
32
|
version?: string;
|
|
33
33
|
chromiumInstalled?: boolean;
|
|
34
|
+
executablePath?: string;
|
|
34
35
|
} | null;
|
|
35
36
|
plugin: {
|
|
36
37
|
ready: boolean;
|
|
@@ -40,6 +41,13 @@ type WorkerLocalStatus = {
|
|
|
40
41
|
};
|
|
41
42
|
agents: AgentWorkerCapabilities['agents'];
|
|
42
43
|
capabilities: AgentWorkerCapabilities | null;
|
|
44
|
+
setupActions: WorkerSetupAction[];
|
|
45
|
+
};
|
|
46
|
+
type WorkerSetupAction = {
|
|
47
|
+
reason: string;
|
|
48
|
+
label: string;
|
|
49
|
+
command?: string;
|
|
50
|
+
message: string;
|
|
43
51
|
};
|
|
44
52
|
type WorkerStatusPayload = {
|
|
45
53
|
schemaVersion: 1;
|
|
@@ -205,6 +213,14 @@ export declare function createLocalPlaydropShim(input: {
|
|
|
205
213
|
attempt: number;
|
|
206
214
|
devPort: number;
|
|
207
215
|
}): Promise<string>;
|
|
216
|
+
export declare function buildWorkerSetupActions(input: {
|
|
217
|
+
degradedReasons: string[];
|
|
218
|
+
playwright?: {
|
|
219
|
+
version?: string;
|
|
220
|
+
chromiumInstalled?: boolean;
|
|
221
|
+
executablePath?: string;
|
|
222
|
+
} | null;
|
|
223
|
+
}): WorkerSetupAction[];
|
|
208
224
|
type WorkerRuntimeState = {
|
|
209
225
|
schemaVersion: 1;
|
|
210
226
|
pid: number;
|
package/dist/commands/worker.js
CHANGED
|
@@ -38,6 +38,7 @@ exports.assertWorkerProjectVersionBumped = assertWorkerProjectVersionBumped;
|
|
|
38
38
|
exports.buildAgentFailureCode = buildAgentFailureCode;
|
|
39
39
|
exports.describeAgentFailureForEvent = describeAgentFailureForEvent;
|
|
40
40
|
exports.createLocalPlaydropShim = createLocalPlaydropShim;
|
|
41
|
+
exports.buildWorkerSetupActions = buildWorkerSetupActions;
|
|
41
42
|
exports.readActivePersonalWorkerRuntimeState = readActivePersonalWorkerRuntimeState;
|
|
42
43
|
exports.parseLaunchAgentProgramArguments = parseLaunchAgentProgramArguments;
|
|
43
44
|
exports.assertLaunchAgentPlistCompatible = assertLaunchAgentPlistCompatible;
|
|
@@ -124,12 +125,13 @@ const WORKER_CONTEXT_ALLOWED_COMMANDS = [
|
|
|
124
125
|
['versions', 'browse'],
|
|
125
126
|
['documentation', 'browse'],
|
|
126
127
|
['documentation', 'read'],
|
|
128
|
+
['help'],
|
|
127
129
|
['ai', 'create'],
|
|
128
130
|
['ai', 'jobs', 'browse'],
|
|
129
131
|
['ai', 'jobs', 'detail'],
|
|
130
132
|
['ai', 'generations'],
|
|
131
133
|
];
|
|
132
|
-
exports.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 catalogue/documentation lookup, and PlayDrop AI generation are permitted.';
|
|
134
|
+
exports.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.';
|
|
133
135
|
function allocateWorkerDevPort(input) {
|
|
134
136
|
const basePort = input.basePort ?? DEFAULT_WORKER_DEV_PORT_BASE;
|
|
135
137
|
const maxParallelTasks = input.maxParallelTasks ?? DEFAULT_WORKER_MAX_PARALLEL_TASKS;
|
|
@@ -181,6 +183,28 @@ function normalizeRemixFlagValue(argv) {
|
|
|
181
183
|
}
|
|
182
184
|
return null;
|
|
183
185
|
}
|
|
186
|
+
function normalizeTemplateKeyRef(value) {
|
|
187
|
+
const trimmed = value.trim();
|
|
188
|
+
const match = /^([^/]+)\/(?:template|app)\/([^/]+)$/.exec(trimmed);
|
|
189
|
+
if (!match) {
|
|
190
|
+
return trimmed || null;
|
|
191
|
+
}
|
|
192
|
+
return `${match[1]}/template/${match[2]}`;
|
|
193
|
+
}
|
|
194
|
+
function normalizeTemplateFlagValue(argv) {
|
|
195
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
196
|
+
const arg = argv[index];
|
|
197
|
+
if (arg === '--template') {
|
|
198
|
+
const value = argv[index + 1]?.trim() ?? '';
|
|
199
|
+
return value ? normalizeTemplateKeyRef(value) : null;
|
|
200
|
+
}
|
|
201
|
+
if (arg.startsWith('--template=')) {
|
|
202
|
+
const value = arg.slice('--template='.length).trim();
|
|
203
|
+
return value ? normalizeTemplateKeyRef(value) : null;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
return null;
|
|
207
|
+
}
|
|
184
208
|
function isAssignedAppScaffoldCommandAllowed(argv) {
|
|
185
209
|
if (argv[0] !== 'project' || argv[1] !== 'create' || argv[2] !== 'app') {
|
|
186
210
|
return false;
|
|
@@ -198,7 +222,11 @@ function isAssignedAppScaffoldCommandAllowed(argv) {
|
|
|
198
222
|
|| requestedAppName !== context.outputAppName) {
|
|
199
223
|
return false;
|
|
200
224
|
}
|
|
201
|
-
|
|
225
|
+
const templateKey = normalizeTemplateFlagValue(argv);
|
|
226
|
+
const allowedTemplateKeys = new Set((context.allowedTemplateKeys ?? []).map((key) => normalizeTemplateKeyRef(key)).filter(Boolean));
|
|
227
|
+
return normalizeRemixFlagValue(argv) === null
|
|
228
|
+
&& templateKey !== null
|
|
229
|
+
&& allowedTemplateKeys.has(templateKey);
|
|
202
230
|
}
|
|
203
231
|
return normalizeRemixFlagValue(argv) === context.remixSourceRef;
|
|
204
232
|
}
|
|
@@ -301,6 +329,9 @@ function resolveWorkerClaimTaskAssignment(claim) {
|
|
|
301
329
|
baseSource: inputs.baseSource ?? null,
|
|
302
330
|
remixSource: inputs.remixSource ?? null,
|
|
303
331
|
reviewTarget: inputs.reviewTarget ?? null,
|
|
332
|
+
allowedTemplateKeys: Array.isArray(inputs.allowedTemplateKeys)
|
|
333
|
+
? Array.from(new Set(inputs.allowedTemplateKeys.map((value) => (typeof value === 'string' ? value.trim() : '')).filter(Boolean)))
|
|
334
|
+
: [],
|
|
304
335
|
},
|
|
305
336
|
output: {
|
|
306
337
|
appId: typeof output.appId === 'number' && Number.isInteger(output.appId) && output.appId > 0 ? output.appId : null,
|
|
@@ -382,6 +413,9 @@ function buildWorkerTaskContext(claim, assignment) {
|
|
|
382
413
|
}
|
|
383
414
|
remixSourceRef = parsedRemixSourceRef;
|
|
384
415
|
}
|
|
416
|
+
const allowedTemplateKeys = Array.isArray(assignment.inputs.allowedTemplateKeys)
|
|
417
|
+
? Array.from(new Set(assignment.inputs.allowedTemplateKeys.map((value) => (typeof value === 'string' ? value.trim() : '')).filter(Boolean)))
|
|
418
|
+
: [];
|
|
385
419
|
const creatorRequest = assignment.inputs.request.prompt.trim();
|
|
386
420
|
if (!creatorRequest) {
|
|
387
421
|
throw new Error('agent_task_context_creator_request_missing');
|
|
@@ -397,6 +431,7 @@ function buildWorkerTaskContext(claim, assignment) {
|
|
|
397
431
|
outputAppName,
|
|
398
432
|
outputVersion,
|
|
399
433
|
remixSourceRef,
|
|
434
|
+
allowedTemplateKeys,
|
|
400
435
|
reviewAppVersionId,
|
|
401
436
|
};
|
|
402
437
|
}
|
|
@@ -454,6 +489,9 @@ function readTaskContextFile(startDir = node_process_1.default.cwd()) {
|
|
|
454
489
|
const remixSourceRef = typeof parsed.remixSourceRef === 'string' && parsed.remixSourceRef.trim()
|
|
455
490
|
? parsed.remixSourceRef.trim()
|
|
456
491
|
: null;
|
|
492
|
+
const allowedTemplateKeys = Array.isArray(parsed.allowedTemplateKeys)
|
|
493
|
+
? Array.from(new Set(parsed.allowedTemplateKeys.map((value) => (typeof value === 'string' ? value.trim() : '')).filter(Boolean)))
|
|
494
|
+
: [];
|
|
457
495
|
let reviewAppVersionId = null;
|
|
458
496
|
if (parsed.reviewAppVersionId !== null && parsed.reviewAppVersionId !== undefined) {
|
|
459
497
|
const parsedReviewAppVersionId = Number(parsed.reviewAppVersionId);
|
|
@@ -487,6 +525,7 @@ function readTaskContextFile(startDir = node_process_1.default.cwd()) {
|
|
|
487
525
|
outputAppName: typeof parsed.outputAppName === 'string' && parsed.outputAppName.trim() ? parsed.outputAppName.trim() : null,
|
|
488
526
|
outputVersion,
|
|
489
527
|
remixSourceRef,
|
|
528
|
+
allowedTemplateKeys,
|
|
490
529
|
reviewAppVersionId,
|
|
491
530
|
devPort,
|
|
492
531
|
env,
|
|
@@ -676,6 +715,15 @@ async function readTaskNextStepsFileForCommand(input) {
|
|
|
676
715
|
return NEXT_STEPS_READ_FAILED;
|
|
677
716
|
}
|
|
678
717
|
}
|
|
718
|
+
function isFinalOwnerRouteLaunchCheckFailure(error) {
|
|
719
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
720
|
+
return message.startsWith('hosted_launch_check_failed:')
|
|
721
|
+
&& message.includes('final owner play route');
|
|
722
|
+
}
|
|
723
|
+
function formatTerminalFinalOwnerRouteFailure(error) {
|
|
724
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
725
|
+
return `agent_task_final_owner_route_failed: final owner play route validation failed after the task version was created. Task uploads have a fixed outputVersion and cannot be retried by bumping catalogue.json. ${message}`;
|
|
726
|
+
}
|
|
679
727
|
function assertTaskUploadResultMatchesContext(input) {
|
|
680
728
|
if (input.uploadResult.taskId !== input.taskContext.taskId) {
|
|
681
729
|
throw new Error('task_upload_result_task_mismatch');
|
|
@@ -1181,9 +1229,9 @@ function probePlaywrightChromium() {
|
|
|
1181
1229
|
const version = typeof packageJson.version === 'string' && packageJson.version.trim() ? packageJson.version.trim() : 'unknown';
|
|
1182
1230
|
const chromiumInstalled = (0, node_fs_1.existsSync)(executablePath);
|
|
1183
1231
|
if (!chromiumInstalled) {
|
|
1184
|
-
|
|
1232
|
+
return { version, chromiumInstalled: false, executablePath };
|
|
1185
1233
|
}
|
|
1186
|
-
return { version, chromiumInstalled };
|
|
1234
|
+
return { version, chromiumInstalled: true, executablePath };
|
|
1187
1235
|
}
|
|
1188
1236
|
function readWorkerModelList(agent, envName) {
|
|
1189
1237
|
const raw = node_process_1.default.env[envName];
|
|
@@ -1260,7 +1308,10 @@ function buildWorkerCapabilities(input) {
|
|
|
1260
1308
|
const cursorVersion = typeof input === 'string' ? null : input.cursorVersion?.trim() || null;
|
|
1261
1309
|
const cursorAuthenticated = typeof input === 'string' ? false : input.cursorAuthenticated === true;
|
|
1262
1310
|
const npmVersion = typeof input === 'string' ? null : input.npmVersion?.trim() || null;
|
|
1263
|
-
const
|
|
1311
|
+
const rawPlaywright = typeof input === 'string' ? null : input.playwright ?? null;
|
|
1312
|
+
const playwright = rawPlaywright
|
|
1313
|
+
? { version: rawPlaywright.version, chromiumInstalled: rawPlaywright.chromiumInstalled }
|
|
1314
|
+
: null;
|
|
1264
1315
|
const maxParallelTasks = typeof input === 'string'
|
|
1265
1316
|
? DEFAULT_WORKER_MAX_PARALLEL_TASKS
|
|
1266
1317
|
: input.maxParallelTasks ?? DEFAULT_WORKER_MAX_PARALLEL_TASKS;
|
|
@@ -1954,6 +2005,9 @@ function probeCodexInstallation() {
|
|
|
1954
2005
|
const versionResult = (0, shellProbe_1.runShell)('codex --version');
|
|
1955
2006
|
const match = /(\d+\.\d+\.\d+\S*)/.exec(versionResult.output);
|
|
1956
2007
|
if (!match?.[1]) {
|
|
2008
|
+
if (versionResult.exitCode !== 0) {
|
|
2009
|
+
return null;
|
|
2010
|
+
}
|
|
1957
2011
|
throw new Error(`codex_version_check_failed: "codex --version" exited with code ${versionResult.exitCode} and reported no version. Output: ${versionResult.output.slice(0, 200)}`);
|
|
1958
2012
|
}
|
|
1959
2013
|
if (versionResult.exitCode !== 0) {
|
|
@@ -1970,7 +2024,13 @@ function probeClaudeInstallation() {
|
|
|
1970
2024
|
}
|
|
1971
2025
|
const versionResult = (0, shellProbe_1.runShell)('claude --version');
|
|
1972
2026
|
const match = /(\d+\.\d+\.\d+\S*)/.exec(versionResult.output);
|
|
1973
|
-
if (!match?.[1]
|
|
2027
|
+
if (!match?.[1]) {
|
|
2028
|
+
if (versionResult.exitCode !== 0) {
|
|
2029
|
+
return null;
|
|
2030
|
+
}
|
|
2031
|
+
throw new Error(`claude_version_check_failed: "claude --version" exited with code ${versionResult.exitCode} and reported no version. Output: ${versionResult.output.slice(0, 200)}`);
|
|
2032
|
+
}
|
|
2033
|
+
if (versionResult.exitCode !== 0) {
|
|
1974
2034
|
throw new Error(`claude_version_check_failed: "claude --version" exited with code ${versionResult.exitCode} and reported no version. Output: ${versionResult.output.slice(0, 200)}`);
|
|
1975
2035
|
}
|
|
1976
2036
|
return { claudeVersion: match[1] };
|
|
@@ -2076,6 +2136,9 @@ function collectWorkerLocalStatus() {
|
|
|
2076
2136
|
}
|
|
2077
2137
|
try {
|
|
2078
2138
|
playwright = probePlaywrightChromium();
|
|
2139
|
+
if (!playwright.chromiumInstalled) {
|
|
2140
|
+
degradedReasons.push('worker_preflight_chromium_missing');
|
|
2141
|
+
}
|
|
2079
2142
|
}
|
|
2080
2143
|
catch (error) {
|
|
2081
2144
|
degradedReasons.push(errorCode(error));
|
|
@@ -2143,8 +2206,53 @@ function collectWorkerLocalStatus() {
|
|
|
2143
2206
|
},
|
|
2144
2207
|
agents: capabilities?.agents ?? [],
|
|
2145
2208
|
capabilities,
|
|
2209
|
+
setupActions: buildWorkerSetupActions({
|
|
2210
|
+
degradedReasons: uniqueReasons,
|
|
2211
|
+
playwright,
|
|
2212
|
+
}),
|
|
2146
2213
|
};
|
|
2147
2214
|
}
|
|
2215
|
+
function buildWorkerSetupActions(input) {
|
|
2216
|
+
const reasons = new Set(input.degradedReasons);
|
|
2217
|
+
const actions = [];
|
|
2218
|
+
if (reasons.has('worker_preflight_chromium_missing')) {
|
|
2219
|
+
const version = input.playwright?.version && input.playwright.version !== 'unknown'
|
|
2220
|
+
? `@${input.playwright.version}`
|
|
2221
|
+
: '';
|
|
2222
|
+
actions.push({
|
|
2223
|
+
reason: 'worker_preflight_chromium_missing',
|
|
2224
|
+
label: 'Install Playwright Chromium',
|
|
2225
|
+
command: `npx playwright${version} install chromium`,
|
|
2226
|
+
message: input.playwright?.executablePath
|
|
2227
|
+
? `Chromium is required for PlayDrop launch checks. Expected browser path: ${input.playwright.executablePath}.`
|
|
2228
|
+
: 'Chromium is required for PlayDrop launch checks.',
|
|
2229
|
+
});
|
|
2230
|
+
}
|
|
2231
|
+
if (reasons.has('worker_preflight_playwright_missing')) {
|
|
2232
|
+
actions.push({
|
|
2233
|
+
reason: 'worker_preflight_playwright_missing',
|
|
2234
|
+
label: 'Repair the PlayDrop CLI install',
|
|
2235
|
+
command: 'npm install -g @playdrop/playdrop-cli@latest',
|
|
2236
|
+
message: 'The PlayDrop CLI package could not load playwright-core from its installed dependencies.',
|
|
2237
|
+
});
|
|
2238
|
+
}
|
|
2239
|
+
if (reasons.has('playdrop_plugin_staging_manifest_missing')) {
|
|
2240
|
+
actions.push({
|
|
2241
|
+
reason: 'playdrop_plugin_staging_manifest_missing',
|
|
2242
|
+
label: 'Install or update the PlayDrop agent plugin',
|
|
2243
|
+
command: 'playdrop agents status --json',
|
|
2244
|
+
message: 'Run the CLI-reported nextAction.command for a supported local agent so playdrop-worker-staging.json is available.',
|
|
2245
|
+
});
|
|
2246
|
+
}
|
|
2247
|
+
if (reasons.has('agent_cli_not_found')) {
|
|
2248
|
+
actions.push({
|
|
2249
|
+
reason: 'agent_cli_not_found',
|
|
2250
|
+
label: 'Install a supported agent CLI',
|
|
2251
|
+
message: 'Install and authenticate Codex or Claude Code, then rerun playdrop agents status --json.',
|
|
2252
|
+
});
|
|
2253
|
+
}
|
|
2254
|
+
return actions;
|
|
2255
|
+
}
|
|
2148
2256
|
function getWorkerStateDir() {
|
|
2149
2257
|
return node_path_1.default.join(node_os_1.default.homedir(), '.playdrop', 'worker');
|
|
2150
2258
|
}
|
|
@@ -2782,6 +2890,13 @@ function printWorkerStatus(payload) {
|
|
|
2782
2890
|
if (payload.local.degradedReasons.length > 0) {
|
|
2783
2891
|
console.log(` Reasons: ${payload.local.degradedReasons.join(', ')}`);
|
|
2784
2892
|
}
|
|
2893
|
+
if (payload.local.setupActions.length > 0) {
|
|
2894
|
+
console.log(' Setup actions:');
|
|
2895
|
+
for (const action of payload.local.setupActions) {
|
|
2896
|
+
console.log(` ${action.label}${action.command ? `: ${action.command}` : ''}`);
|
|
2897
|
+
console.log(` ${action.message}`);
|
|
2898
|
+
}
|
|
2899
|
+
}
|
|
2785
2900
|
if (!payload.server.authenticated) {
|
|
2786
2901
|
console.log('Server worker: not authenticated');
|
|
2787
2902
|
}
|
|
@@ -3771,21 +3886,40 @@ async function uploadTask(options = {}) {
|
|
|
3771
3886
|
return;
|
|
3772
3887
|
}
|
|
3773
3888
|
const projectDir = discoverWorkerProjectRoot(node_process_1.default.cwd());
|
|
3774
|
-
|
|
3775
|
-
|
|
3776
|
-
|
|
3777
|
-
|
|
3778
|
-
|
|
3779
|
-
|
|
3780
|
-
|
|
3781
|
-
|
|
3782
|
-
|
|
3783
|
-
|
|
3784
|
-
|
|
3785
|
-
|
|
3786
|
-
|
|
3787
|
-
|
|
3788
|
-
|
|
3889
|
+
let published;
|
|
3890
|
+
try {
|
|
3891
|
+
published = await (0, upload_1.publishWorkerAppProject)({
|
|
3892
|
+
client: ctx.client,
|
|
3893
|
+
taskId: taskContext.taskId,
|
|
3894
|
+
kind: taskContext.kind,
|
|
3895
|
+
expectedAppName: taskContext.outputAppName ?? undefined,
|
|
3896
|
+
remixSourceRef: taskContext.remixSourceRef ?? null,
|
|
3897
|
+
playdropAssetRequirement: resolvePlaydropAssetRequirementFromTaskRequest(taskContext.creatorRequest),
|
|
3898
|
+
creatorRequest: taskContext.creatorRequest,
|
|
3899
|
+
projectDir,
|
|
3900
|
+
creatorUsername: taskContext.creatorUsername,
|
|
3901
|
+
apiBase: ctx.envConfig.apiBase,
|
|
3902
|
+
webBase: ctx.envConfig.webBase ?? null,
|
|
3903
|
+
token: ctx.token,
|
|
3904
|
+
user: ctx.user,
|
|
3905
|
+
});
|
|
3906
|
+
}
|
|
3907
|
+
catch (error) {
|
|
3908
|
+
if (isFinalOwnerRouteLaunchCheckFailure(error)) {
|
|
3909
|
+
const terminalError = formatTerminalFinalOwnerRouteFailure(error);
|
|
3910
|
+
await ctx.client.workerFailAgentTask(taskContext.taskId, {
|
|
3911
|
+
taskToken: taskContext.taskToken,
|
|
3912
|
+
error: terminalError,
|
|
3913
|
+
result: {
|
|
3914
|
+
failedBy: 'worker_upload_final_owner_route',
|
|
3915
|
+
finalOwnerRouteFailure: true,
|
|
3916
|
+
originalError: error instanceof Error ? error.message : String(error),
|
|
3917
|
+
},
|
|
3918
|
+
});
|
|
3919
|
+
throw new Error(terminalError);
|
|
3920
|
+
}
|
|
3921
|
+
throw error;
|
|
3922
|
+
}
|
|
3789
3923
|
const result = {
|
|
3790
3924
|
taskId: taskContext.taskId,
|
|
3791
3925
|
appId: published.appId,
|
|
@@ -307,7 +307,8 @@ function isMacProtectedWorkspaceRoot(rootPath, homeDir = node_os_1.default.homed
|
|
|
307
307
|
return protectedRoots.some((protectedRoot) => absoluteRoot === protectedRoot || isPathInside(absoluteRoot, protectedRoot));
|
|
308
308
|
}
|
|
309
309
|
function isPathInside(candidate, parent) {
|
|
310
|
-
|
|
310
|
+
const relativePath = (0, node_path_1.relative)(parent, candidate);
|
|
311
|
+
return Boolean(relativePath) && !relativePath.startsWith('..') && !(0, node_path_1.isAbsolute)(relativePath);
|
|
311
312
|
}
|
|
312
313
|
function isAllowedProtectedPath(candidate, allowedProtectedRoots) {
|
|
313
314
|
return allowedProtectedRoots.some((allowedRoot) => candidate === allowedRoot || isPathInside(candidate, allowedRoot));
|
|
@@ -80,6 +80,45 @@ function runtime(overrides = {}) {
|
|
|
80
80
|
const result = (0, index_1.validateClientEnvironment)(info);
|
|
81
81
|
strict_1.default.equal(result.ok, true);
|
|
82
82
|
});
|
|
83
|
+
(0, node_test_1.default)('accepts windows-playdrop as a first-class Windows client identity', () => {
|
|
84
|
+
const meta = (0, index_1.loadClientMeta)();
|
|
85
|
+
const windowsRule = meta.clients['windows-playdrop'];
|
|
86
|
+
strict_1.default.ok(windowsRule, 'windows-playdrop metadata must be explicit');
|
|
87
|
+
const requiredVersion = windowsRule.minimumVersion ?? meta.version;
|
|
88
|
+
const requiredBuild = windowsRule.minimumBuild ?? meta.build;
|
|
89
|
+
const info = runtime({
|
|
90
|
+
client: 'windows-playdrop',
|
|
91
|
+
clientVersion: requiredVersion,
|
|
92
|
+
clientBuild: requiredBuild,
|
|
93
|
+
platform: 'windows',
|
|
94
|
+
platformVersion: '10.0.22631',
|
|
95
|
+
});
|
|
96
|
+
const result = (0, index_1.validateClientEnvironment)(info);
|
|
97
|
+
strict_1.default.equal(result.ok, true);
|
|
98
|
+
});
|
|
99
|
+
(0, node_test_1.default)('enforces the windows-playdrop alpha build floor', () => {
|
|
100
|
+
const meta = (0, index_1.loadClientMeta)();
|
|
101
|
+
const windowsRule = meta.clients['windows-playdrop'];
|
|
102
|
+
strict_1.default.ok(windowsRule?.minimumVersion, 'windows-playdrop requires an explicit minimum version');
|
|
103
|
+
const requiredBuild = windowsRule.minimumBuild;
|
|
104
|
+
if (typeof requiredBuild !== 'number') {
|
|
105
|
+
strict_1.default.fail('windows-playdrop requires an explicit minimum build');
|
|
106
|
+
}
|
|
107
|
+
const info = runtime({
|
|
108
|
+
client: 'windows-playdrop',
|
|
109
|
+
clientVersion: windowsRule.minimumVersion,
|
|
110
|
+
clientBuild: Math.max(requiredBuild - 1, 0),
|
|
111
|
+
platform: 'windows',
|
|
112
|
+
platformVersion: '10.0.22631',
|
|
113
|
+
});
|
|
114
|
+
const result = (0, index_1.validateClientEnvironment)(info);
|
|
115
|
+
strict_1.default.equal(result.ok, false);
|
|
116
|
+
if (!result.ok) {
|
|
117
|
+
strict_1.default.equal(result.code, 'unsupported_client_build');
|
|
118
|
+
strict_1.default.equal(result.requiredVersion, windowsRule.minimumVersion);
|
|
119
|
+
strict_1.default.equal(result.requiredBuild, requiredBuild);
|
|
120
|
+
}
|
|
121
|
+
});
|
|
83
122
|
(0, node_test_1.default)('keeps accepting the legacy Apple client id during rollout', () => {
|
|
84
123
|
const meta = (0, index_1.loadClientMeta)();
|
|
85
124
|
const requiredVersion = meta.clients['all']?.minimumVersion ?? meta.version;
|