@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
package/dist/commands/worker.js
CHANGED
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.WORKER_CONTEXT_COMMAND_NOT_ALLOWED_MESSAGE = exports.WORKER_SESSION_EXPIRED_MESSAGE = exports.runLoggedProcess = exports.
|
|
6
|
+
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.extractCodexRolloutTokenUsage = exports.extractAgentTokenUsage = exports.DEFAULT_WORKER_TOKEN_CAP = exports.DEFAULT_CODEX_TIMEOUT_MS = exports.buildWorkerChildEnv = exports.buildCodexExecArgs = exports.buildClaudePermissionSettings = exports.buildClaudeExecArgs = exports.assertWorkerTokenUsageWithinCap = void 0;
|
|
7
7
|
exports.allocateWorkerDevPort = allocateWorkerDevPort;
|
|
8
8
|
exports.isWorkerContextCommandAllowed = isWorkerContextCommandAllowed;
|
|
9
9
|
exports.resolveWorkerExecutionTargetFromRole = resolveWorkerExecutionTargetFromRole;
|
|
@@ -55,40 +55,40 @@ exports.readReviewEvidenceFiles = readReviewEvidenceFiles;
|
|
|
55
55
|
exports.submitReviewTask = submitReviewTask;
|
|
56
56
|
exports.submitEvalTask = submitEvalTask;
|
|
57
57
|
exports.failTask = failTask;
|
|
58
|
-
const
|
|
58
|
+
const types_1 = require("@playdrop/types");
|
|
59
|
+
const fflate_1 = require("fflate");
|
|
60
|
+
const node_crypto_1 = require("node:crypto");
|
|
59
61
|
const node_fs_1 = require("node:fs");
|
|
62
|
+
const promises_1 = require("node:fs/promises");
|
|
63
|
+
const node_module_1 = require("node:module");
|
|
60
64
|
const node_os_1 = __importDefault(require("node:os"));
|
|
61
65
|
const node_path_1 = __importDefault(require("node:path"));
|
|
62
66
|
const node_process_1 = __importDefault(require("node:process"));
|
|
63
|
-
const
|
|
64
|
-
const node_crypto_1 = require("node:crypto");
|
|
65
|
-
const fflate_1 = require("fflate");
|
|
66
|
-
const types_1 = require("@playdrop/types");
|
|
67
|
+
const clientInfo_1 = require("../clientInfo");
|
|
67
68
|
const commandContext_1 = require("../commandContext");
|
|
68
69
|
const config_1 = require("../config");
|
|
69
|
-
const clientInfo_1 = require("../clientInfo");
|
|
70
70
|
const messages_1 = require("../messages");
|
|
71
71
|
const output_1 = require("../output");
|
|
72
72
|
const shellProbe_1 = require("../shellProbe");
|
|
73
|
-
const upload_1 = require("./upload");
|
|
74
|
-
const review_1 = require("./review");
|
|
75
73
|
const agents_1 = require("./agents");
|
|
74
|
+
const review_1 = require("./review");
|
|
75
|
+
const upload_1 = require("./upload");
|
|
76
76
|
const runtime_1 = require("./worker/runtime");
|
|
77
77
|
var runtime_2 = require("./worker/runtime");
|
|
78
|
-
Object.defineProperty(exports, "DEFAULT_CODEX_TIMEOUT_MS", { enumerable: true, get: function () { return runtime_2.DEFAULT_CODEX_TIMEOUT_MS; } });
|
|
79
|
-
Object.defineProperty(exports, "DEFAULT_WORKER_TOKEN_CAP", { enumerable: true, get: function () { return runtime_2.DEFAULT_WORKER_TOKEN_CAP; } });
|
|
80
78
|
Object.defineProperty(exports, "assertWorkerTokenUsageWithinCap", { enumerable: true, get: function () { return runtime_2.assertWorkerTokenUsageWithinCap; } });
|
|
81
|
-
Object.defineProperty(exports, "buildCodexExecArgs", { enumerable: true, get: function () { return runtime_2.buildCodexExecArgs; } });
|
|
82
79
|
Object.defineProperty(exports, "buildClaudeExecArgs", { enumerable: true, get: function () { return runtime_2.buildClaudeExecArgs; } });
|
|
83
80
|
Object.defineProperty(exports, "buildClaudePermissionSettings", { enumerable: true, get: function () { return runtime_2.buildClaudePermissionSettings; } });
|
|
81
|
+
Object.defineProperty(exports, "buildCodexExecArgs", { enumerable: true, get: function () { return runtime_2.buildCodexExecArgs; } });
|
|
84
82
|
Object.defineProperty(exports, "buildWorkerChildEnv", { enumerable: true, get: function () { return runtime_2.buildWorkerChildEnv; } });
|
|
83
|
+
Object.defineProperty(exports, "DEFAULT_CODEX_TIMEOUT_MS", { enumerable: true, get: function () { return runtime_2.DEFAULT_CODEX_TIMEOUT_MS; } });
|
|
84
|
+
Object.defineProperty(exports, "DEFAULT_WORKER_TOKEN_CAP", { enumerable: true, get: function () { return runtime_2.DEFAULT_WORKER_TOKEN_CAP; } });
|
|
85
85
|
Object.defineProperty(exports, "extractAgentTokenUsage", { enumerable: true, get: function () { return runtime_2.extractAgentTokenUsage; } });
|
|
86
86
|
Object.defineProperty(exports, "extractCodexRolloutTokenUsage", { enumerable: true, get: function () { return runtime_2.extractCodexRolloutTokenUsage; } });
|
|
87
87
|
Object.defineProperty(exports, "extractCodexThreadId", { enumerable: true, get: function () { return runtime_2.extractCodexThreadId; } });
|
|
88
88
|
Object.defineProperty(exports, "extractCodexTokensUsed", { enumerable: true, get: function () { return runtime_2.extractCodexTokensUsed; } });
|
|
89
|
-
Object.defineProperty(exports, "readEnvBoolean", { enumerable: true, get: function () { return runtime_2.readEnvBoolean; } });
|
|
90
|
-
Object.defineProperty(exports, "readCodexSandboxMode", { enumerable: true, get: function () { return runtime_2.readCodexSandboxMode; } });
|
|
91
89
|
Object.defineProperty(exports, "readCodexRolloutTokenUsageForThread", { enumerable: true, get: function () { return runtime_2.readCodexRolloutTokenUsageForThread; } });
|
|
90
|
+
Object.defineProperty(exports, "readCodexSandboxMode", { enumerable: true, get: function () { return runtime_2.readCodexSandboxMode; } });
|
|
91
|
+
Object.defineProperty(exports, "readEnvBoolean", { enumerable: true, get: function () { return runtime_2.readEnvBoolean; } });
|
|
92
92
|
Object.defineProperty(exports, "runLoggedProcess", { enumerable: true, get: function () { return runtime_2.runLoggedProcess; } });
|
|
93
93
|
const DEFAULT_POLL_INTERVAL_MS = 1000;
|
|
94
94
|
const HEARTBEAT_INTERVAL_MS = 10000;
|
|
@@ -120,11 +120,14 @@ const WORKER_CONTEXT_ALLOWED_COMMANDS = [
|
|
|
120
120
|
['task', 'submit-eval'],
|
|
121
121
|
['task', 'fail'],
|
|
122
122
|
['review', 'validate-result'],
|
|
123
|
+
['review', 'list-windows'],
|
|
124
|
+
['review', 'screenshot'],
|
|
123
125
|
['review', 'compose-evidence'],
|
|
124
126
|
['review', 'rating-card'],
|
|
125
127
|
['project', 'validate'],
|
|
126
128
|
['project', 'build'],
|
|
127
129
|
['project', 'dev'],
|
|
130
|
+
['project', 'check'],
|
|
128
131
|
['project', 'capture'],
|
|
129
132
|
['browse'],
|
|
130
133
|
['search'],
|
|
@@ -138,7 +141,7 @@ const WORKER_CONTEXT_ALLOWED_COMMANDS = [
|
|
|
138
141
|
['ai', 'jobs', 'detail'],
|
|
139
142
|
['ai', 'generations'],
|
|
140
143
|
];
|
|
141
|
-
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.';
|
|
144
|
+
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/check/capture, read-only help/catalogue/documentation lookup, and PlayDrop AI generation are permitted.';
|
|
142
145
|
function allocateWorkerDevPort(input) {
|
|
143
146
|
const basePort = input.basePort ?? DEFAULT_WORKER_DEV_PORT_BASE;
|
|
144
147
|
const maxParallelTasks = input.maxParallelTasks ?? DEFAULT_WORKER_MAX_PARALLEL_TASKS;
|
|
@@ -727,15 +730,6 @@ async function readTaskNextStepsFileForCommand(input) {
|
|
|
727
730
|
return NEXT_STEPS_READ_FAILED;
|
|
728
731
|
}
|
|
729
732
|
}
|
|
730
|
-
function isFinalOwnerRouteLaunchCheckFailure(error) {
|
|
731
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
732
|
-
return message.startsWith('hosted_launch_check_failed:')
|
|
733
|
-
&& message.includes('final owner play route');
|
|
734
|
-
}
|
|
735
|
-
function formatTerminalFinalOwnerRouteFailure(error) {
|
|
736
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
737
|
-
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}`;
|
|
738
|
-
}
|
|
739
733
|
function assertTaskUploadResultMatchesContext(input) {
|
|
740
734
|
if (input.uploadResult.taskId !== input.taskContext.taskId) {
|
|
741
735
|
throw new Error('task_upload_result_task_mismatch');
|
|
@@ -1077,11 +1071,6 @@ function discoverWorkerProjectRoot(workspaceDir) {
|
|
|
1077
1071
|
}
|
|
1078
1072
|
return roots[0];
|
|
1079
1073
|
}
|
|
1080
|
-
function writeWorkerTaskState(state) {
|
|
1081
|
-
const file = workerStateFilePath();
|
|
1082
|
-
(0, node_fs_1.mkdirSync)(node_path_1.default.dirname(file), { recursive: true });
|
|
1083
|
-
(0, node_fs_1.writeFileSync)(file, JSON.stringify(state, null, 2));
|
|
1084
|
-
}
|
|
1085
1074
|
function readWorkerTaskState() {
|
|
1086
1075
|
const file = workerStateFilePath();
|
|
1087
1076
|
let raw;
|
|
@@ -1097,9 +1086,6 @@ function readWorkerTaskState() {
|
|
|
1097
1086
|
}
|
|
1098
1087
|
return parsed;
|
|
1099
1088
|
}
|
|
1100
|
-
function clearWorkerTaskState() {
|
|
1101
|
-
(0, node_fs_1.rmSync)(workerStateFilePath(), { force: true });
|
|
1102
|
-
}
|
|
1103
1089
|
function isWorkerSlackAlertEnabled() {
|
|
1104
1090
|
const normalized = node_process_1.default.env.PLAYDROP_WORKER_SLACK_ALERTS?.trim().toLowerCase();
|
|
1105
1091
|
return normalized === '1' || normalized === 'true' || normalized === 'yes' || normalized === 'on';
|
|
@@ -1408,7 +1394,6 @@ function buildWorkerCapabilities(input) {
|
|
|
1408
1394
|
? DEFAULT_WORKER_MAX_PARALLEL_TASKS
|
|
1409
1395
|
: input.maxParallelTasks ?? DEFAULT_WORKER_MAX_PARALLEL_TASKS;
|
|
1410
1396
|
const runningTaskCount = typeof input === 'string' ? 0 : input.runningTaskCount ?? 0;
|
|
1411
|
-
const providerAccountLabel = typeof input === 'string' ? null : input.providerAccountLabel?.trim() || null;
|
|
1412
1397
|
const degradedReasons = [];
|
|
1413
1398
|
const agents = [];
|
|
1414
1399
|
if (codexVersion) {
|
|
@@ -1461,7 +1446,6 @@ function buildWorkerCapabilities(input) {
|
|
|
1461
1446
|
agents,
|
|
1462
1447
|
ready: agents.some((agent) => agent.ready === true),
|
|
1463
1448
|
degradedReasons,
|
|
1464
|
-
...(providerAccountLabel ? { providerAccountLabel } : {}),
|
|
1465
1449
|
wrapperContractVersion: (0, runtime_1.readPositiveEnvInt)('PLAYDROP_WORKER_WRAPPER_CONTRACT_VERSION', WORKER_WRAPPER_CONTRACT_VERSION),
|
|
1466
1450
|
...(npmVersion ? { npmVersion } : {}),
|
|
1467
1451
|
...(playwright ? { playwright } : {}),
|
|
@@ -1861,6 +1845,7 @@ async function runClaude(input) {
|
|
|
1861
1845
|
workspaceDir: input.workspaceDir,
|
|
1862
1846
|
denyReadRoots,
|
|
1863
1847
|
pluginDir: input.playdropPluginRoot,
|
|
1848
|
+
chrome: input.enableChrome,
|
|
1864
1849
|
}),
|
|
1865
1850
|
cwd: input.workspaceDir,
|
|
1866
1851
|
env: (0, runtime_1.buildWorkerChildEnv)({
|
|
@@ -1957,13 +1942,6 @@ function collectObservedPlaydropSkillPaths(output, availablePaths) {
|
|
|
1957
1942
|
}
|
|
1958
1943
|
return [...observed].sort();
|
|
1959
1944
|
}
|
|
1960
|
-
function readProviderAccountLabel(target) {
|
|
1961
|
-
const label = node_process_1.default.env.PLAYDROP_WORKER_AGENT_ACCOUNT_LABEL?.trim() || null;
|
|
1962
|
-
if (target === 'FIRST_PARTY' && !label) {
|
|
1963
|
-
throw new Error('missing_playdrop_worker_agent_account_label');
|
|
1964
|
-
}
|
|
1965
|
-
return label;
|
|
1966
|
-
}
|
|
1967
1945
|
function resolveTelemetryStatus(value) {
|
|
1968
1946
|
if (value === 'QUEUED') {
|
|
1969
1947
|
throw new Error('invalid_agent_task_run_status');
|
|
@@ -1983,7 +1961,6 @@ async function recordAgentRunTelemetry(input) {
|
|
|
1983
1961
|
requestedModel: input.assignment.model,
|
|
1984
1962
|
resolvedRuntimeModel: input.resolvedRuntimeModel,
|
|
1985
1963
|
reasoningEffort: input.reasoningEffort,
|
|
1986
|
-
providerAccountLabel: input.providerAccountLabel,
|
|
1987
1964
|
status: resolveTelemetryStatus(input.status),
|
|
1988
1965
|
exitCode: input.result.exitCode,
|
|
1989
1966
|
signal: input.result.signal,
|
|
@@ -2264,7 +2241,6 @@ function collectWorkerLocalStatus() {
|
|
|
2264
2241
|
playwright,
|
|
2265
2242
|
runningTaskCount: 0,
|
|
2266
2243
|
maxParallelTasks: (0, runtime_1.readPositiveEnvInt)('PLAYDROP_WORKER_MAX_PARALLEL_TASKS', DEFAULT_WORKER_MAX_PARALLEL_TASKS),
|
|
2267
|
-
providerAccountLabel: node_process_1.default.env.PLAYDROP_WORKER_AGENT_ACCOUNT_LABEL?.trim() || null,
|
|
2268
2244
|
});
|
|
2269
2245
|
if (pluginVersion) {
|
|
2270
2246
|
capabilities.pluginVersion = pluginVersion;
|
|
@@ -2418,13 +2394,6 @@ function writeManagedWorkerUpdatePolicyFile(input) {
|
|
|
2418
2394
|
function shellQuote(value) {
|
|
2419
2395
|
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
2420
2396
|
}
|
|
2421
|
-
function validatePackageVersion(value, label) {
|
|
2422
|
-
const version = typeof value === 'string' ? value.trim() : '';
|
|
2423
|
-
if (!/^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?$/.test(version)) {
|
|
2424
|
-
throw new Error(`${label}_invalid:${version || 'missing'}`);
|
|
2425
|
-
}
|
|
2426
|
-
return version;
|
|
2427
|
-
}
|
|
2428
2397
|
function verifyNpmGlobalInstallPreconditions() {
|
|
2429
2398
|
const prefixProbe = (0, shellProbe_1.runShell)('npm prefix -g');
|
|
2430
2399
|
const prefix = prefixProbe.output.trim().split(/\r?\n/)[0]?.trim() ?? '';
|
|
@@ -3108,6 +3077,9 @@ async function fetchTaskDetail(client, target, taskId) {
|
|
|
3108
3077
|
}
|
|
3109
3078
|
return await client.getAgentTask(taskId);
|
|
3110
3079
|
}
|
|
3080
|
+
function throwWorkerRuntimeError(error) {
|
|
3081
|
+
throw error;
|
|
3082
|
+
}
|
|
3111
3083
|
async function startWorker(options = {}) {
|
|
3112
3084
|
loadWorkerEnvFile(options.env);
|
|
3113
3085
|
await (0, commandContext_1.withEnvironment)('worker start', 'Starting the PlayDrop worker', async ({ client, env }) => {
|
|
@@ -3126,7 +3098,6 @@ async function startWorker(options = {}) {
|
|
|
3126
3098
|
throw new Error('worker_session_invalid: the stored session did not resolve to a user. Run "playdrop auth login" and retry.');
|
|
3127
3099
|
}
|
|
3128
3100
|
const target = resolveWorkerExecutionTargetFromRole(me.user.role);
|
|
3129
|
-
const providerAccountLabel = readProviderAccountLabel(target);
|
|
3130
3101
|
const codexVersion = probeCodexInstallation()?.codexVersion ?? null;
|
|
3131
3102
|
const claudeVersion = probeClaudeInstallation()?.claudeVersion ?? null;
|
|
3132
3103
|
const cursorVersion = probeCursorInstallation()?.cursorVersion ?? null;
|
|
@@ -3151,7 +3122,6 @@ async function startWorker(options = {}) {
|
|
|
3151
3122
|
playwright,
|
|
3152
3123
|
maxParallelTasks,
|
|
3153
3124
|
runningTaskCount: 0,
|
|
3154
|
-
providerAccountLabel,
|
|
3155
3125
|
});
|
|
3156
3126
|
if (playdropPluginVersion) {
|
|
3157
3127
|
capabilities.pluginVersion = playdropPluginVersion;
|
|
@@ -3305,7 +3275,6 @@ async function startWorker(options = {}) {
|
|
|
3305
3275
|
let availableSkillPaths = [];
|
|
3306
3276
|
const observedSkillPaths = new Set();
|
|
3307
3277
|
let assignment = null;
|
|
3308
|
-
let providerAccountLabel = null;
|
|
3309
3278
|
let resolvedRuntimeModel = task.model;
|
|
3310
3279
|
let reasoningEffort = null;
|
|
3311
3280
|
let agentStartedAt = null;
|
|
@@ -3328,7 +3297,6 @@ async function startWorker(options = {}) {
|
|
|
3328
3297
|
status,
|
|
3329
3298
|
resolvedRuntimeModel,
|
|
3330
3299
|
reasoningEffort,
|
|
3331
|
-
providerAccountLabel,
|
|
3332
3300
|
availableSkillPaths,
|
|
3333
3301
|
observedSkillPaths: [...observedSkillPaths],
|
|
3334
3302
|
startedAt: agentStartedAt ?? completedAt,
|
|
@@ -3341,7 +3309,6 @@ async function startWorker(options = {}) {
|
|
|
3341
3309
|
if (!assignment) {
|
|
3342
3310
|
throw new Error('agent_task_claim_missing_task_assignment');
|
|
3343
3311
|
}
|
|
3344
|
-
providerAccountLabel = readProviderAccountLabel(assignment.target);
|
|
3345
3312
|
const codexModel = assignment.agent === 'CODEX' ? resolveCodexModel(assignment.model) : null;
|
|
3346
3313
|
const claudeModel = assignment.agent === 'CLAUDE_CODE' ? resolveClaudeModel(assignment.model) : null;
|
|
3347
3314
|
resolvedRuntimeModel = codexModel?.model ?? claudeModel?.model ?? assignment.model;
|
|
@@ -3557,6 +3524,7 @@ async function startWorker(options = {}) {
|
|
|
3557
3524
|
binDir,
|
|
3558
3525
|
eventDir,
|
|
3559
3526
|
prompt,
|
|
3527
|
+
enableChrome: task.kind === 'GAME_REVIEW' || task.kind === 'GAME_EVAL',
|
|
3560
3528
|
envName: env,
|
|
3561
3529
|
taskId: task.id,
|
|
3562
3530
|
attempt: taskContext.attempt,
|
|
@@ -3786,7 +3754,7 @@ async function startWorker(options = {}) {
|
|
|
3786
3754
|
let claimBackoffMs = CLAIM_BACKOFF_BASE_MS;
|
|
3787
3755
|
while (!shuttingDown && !quiescingForUpdate) {
|
|
3788
3756
|
if (fatalTaskError) {
|
|
3789
|
-
|
|
3757
|
+
throwWorkerRuntimeError(fatalTaskError);
|
|
3790
3758
|
}
|
|
3791
3759
|
if (sessionExpired) {
|
|
3792
3760
|
throw new Error(exports.WORKER_SESSION_EXPIRED_MESSAGE);
|
|
@@ -3845,7 +3813,7 @@ async function startWorker(options = {}) {
|
|
|
3845
3813
|
if (options.once) {
|
|
3846
3814
|
await taskRun;
|
|
3847
3815
|
if (fatalTaskError) {
|
|
3848
|
-
|
|
3816
|
+
throwWorkerRuntimeError(fatalTaskError);
|
|
3849
3817
|
}
|
|
3850
3818
|
return;
|
|
3851
3819
|
}
|
|
@@ -3854,7 +3822,7 @@ async function startWorker(options = {}) {
|
|
|
3854
3822
|
await Promise.allSettled(Array.from(activeTaskRuns.values()));
|
|
3855
3823
|
}
|
|
3856
3824
|
if (fatalTaskError) {
|
|
3857
|
-
|
|
3825
|
+
throwWorkerRuntimeError(fatalTaskError);
|
|
3858
3826
|
}
|
|
3859
3827
|
if (sessionExpired) {
|
|
3860
3828
|
throw new Error(exports.WORKER_SESSION_EXPIRED_MESSAGE);
|
|
@@ -3994,40 +3962,22 @@ async function uploadTask(options = {}) {
|
|
|
3994
3962
|
return;
|
|
3995
3963
|
}
|
|
3996
3964
|
const projectDir = discoverWorkerProjectRoot(node_process_1.default.cwd());
|
|
3997
|
-
|
|
3998
|
-
|
|
3999
|
-
|
|
4000
|
-
|
|
4001
|
-
|
|
4002
|
-
|
|
4003
|
-
|
|
4004
|
-
|
|
4005
|
-
|
|
4006
|
-
|
|
4007
|
-
|
|
4008
|
-
|
|
4009
|
-
|
|
4010
|
-
|
|
4011
|
-
|
|
4012
|
-
|
|
4013
|
-
});
|
|
4014
|
-
}
|
|
4015
|
-
catch (error) {
|
|
4016
|
-
if (isFinalOwnerRouteLaunchCheckFailure(error)) {
|
|
4017
|
-
const terminalError = formatTerminalFinalOwnerRouteFailure(error);
|
|
4018
|
-
await ctx.client.workerFailAgentTask(taskContext.taskId, {
|
|
4019
|
-
taskToken: taskContext.taskToken,
|
|
4020
|
-
error: terminalError,
|
|
4021
|
-
result: {
|
|
4022
|
-
failedBy: 'worker_upload_final_owner_route',
|
|
4023
|
-
finalOwnerRouteFailure: true,
|
|
4024
|
-
originalError: error instanceof Error ? error.message : String(error),
|
|
4025
|
-
},
|
|
4026
|
-
});
|
|
4027
|
-
throw new Error(terminalError);
|
|
4028
|
-
}
|
|
4029
|
-
throw error;
|
|
4030
|
-
}
|
|
3965
|
+
const published = await (0, upload_1.publishWorkerAppProject)({
|
|
3966
|
+
client: ctx.client,
|
|
3967
|
+
taskId: taskContext.taskId,
|
|
3968
|
+
kind: taskContext.kind,
|
|
3969
|
+
executionTarget: taskContext.target,
|
|
3970
|
+
expectedAppName: taskContext.outputAppName ?? undefined,
|
|
3971
|
+
remixSourceRef: taskContext.remixSourceRef ?? null,
|
|
3972
|
+
playdropAssetRequirement: resolvePlaydropAssetRequirementFromTaskRequest(taskContext.creatorRequest),
|
|
3973
|
+
creatorRequest: taskContext.creatorRequest,
|
|
3974
|
+
projectDir,
|
|
3975
|
+
creatorUsername: taskContext.creatorUsername,
|
|
3976
|
+
apiBase: ctx.envConfig.apiBase,
|
|
3977
|
+
webBase: ctx.envConfig.webBase ?? null,
|
|
3978
|
+
token: ctx.token,
|
|
3979
|
+
user: ctx.user,
|
|
3980
|
+
});
|
|
4031
3981
|
const result = {
|
|
4032
3982
|
taskId: taskContext.taskId,
|
|
4033
3983
|
appId: published.appId,
|
package/dist/config.js
CHANGED
|
@@ -18,8 +18,8 @@ exports.setCurrentAccount = setCurrentAccount;
|
|
|
18
18
|
exports.removeAccountSession = removeAccountSession;
|
|
19
19
|
const crypto_1 = require("crypto");
|
|
20
20
|
const fs_1 = require("fs");
|
|
21
|
-
const path_1 = require("path");
|
|
22
21
|
const os_1 = __importDefault(require("os"));
|
|
22
|
+
const path_1 = require("path");
|
|
23
23
|
const CONFIG_VERSION = 2;
|
|
24
24
|
function getConfigPath() {
|
|
25
25
|
const custom = process.env.PLAYDROP_CONFIG_PATH;
|
|
@@ -225,7 +225,6 @@ function setCurrentAccount(input) {
|
|
|
225
225
|
saveConfig(next);
|
|
226
226
|
return loadConfig();
|
|
227
227
|
}
|
|
228
|
-
// eslint-disable-next-line complexity
|
|
229
228
|
function removeAccountSession(input = {}) {
|
|
230
229
|
const cfg = loadConfig();
|
|
231
230
|
const current = getCurrentAccountSession(cfg);
|
package/dist/index.js
CHANGED
|
@@ -30,10 +30,9 @@ const create_1 = require("./commands/create");
|
|
|
30
30
|
const createRemixContent_1 = require("./commands/createRemixContent");
|
|
31
31
|
const dev_1 = require("./commands/dev");
|
|
32
32
|
const devBrowser_1 = require("./commands/devBrowser");
|
|
33
|
-
const
|
|
33
|
+
const check_1 = require("./commands/check");
|
|
34
34
|
const devServer_1 = require("./commands/devServer");
|
|
35
35
|
const captureListing_1 = require("./commands/captureListing");
|
|
36
|
-
const captureRemote_1 = require("./commands/captureRemote");
|
|
37
36
|
const marketing_1 = require("./commands/marketing");
|
|
38
37
|
const review_1 = require("./commands/review");
|
|
39
38
|
const validate_1 = require("./commands/validate");
|
|
@@ -290,6 +289,23 @@ task
|
|
|
290
289
|
await (0, worker_1.failTask)(opts);
|
|
291
290
|
});
|
|
292
291
|
const review = program.command('review').description('Review helper commands for PlayDrop worker tasks');
|
|
292
|
+
review
|
|
293
|
+
.command('list-windows')
|
|
294
|
+
.description('List native capture windows for review evidence')
|
|
295
|
+
.requiredOption('--pid <pid>', 'Browser process id')
|
|
296
|
+
.action(async (opts) => {
|
|
297
|
+
await (0, review_1.listReviewCaptureWindows)(opts);
|
|
298
|
+
});
|
|
299
|
+
review
|
|
300
|
+
.command('screenshot')
|
|
301
|
+
.description('Capture a native screenshot for review evidence')
|
|
302
|
+
.requiredOption('--pid <pid>', 'Browser process id')
|
|
303
|
+
.option('--window-id <id>', 'Native capture window id')
|
|
304
|
+
.requiredOption('--out <path>', 'Output PNG path')
|
|
305
|
+
.option('--metadata <path>', 'Output metadata JSON path')
|
|
306
|
+
.action(async (opts) => {
|
|
307
|
+
await (0, review_1.captureReviewScreenshot)(opts);
|
|
308
|
+
});
|
|
293
309
|
review
|
|
294
310
|
.command('validate-result')
|
|
295
311
|
.description('Validate a canonical game review result')
|
|
@@ -986,37 +1002,24 @@ project
|
|
|
986
1002
|
player: opts.player,
|
|
987
1003
|
});
|
|
988
1004
|
});
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
.
|
|
1005
|
+
project
|
|
1006
|
+
.command('check [target]')
|
|
1007
|
+
.description('Run the deterministic hosted game load-check in installed Chrome')
|
|
992
1008
|
.option('--app <name>', 'App name when the target is a workspace')
|
|
993
|
-
.option('--timeout <seconds>', '
|
|
994
|
-
.option('--log-level <level>', 'debug, info, warn, or error')
|
|
1009
|
+
.option('--timeout <seconds>', 'Load-check timeout in seconds')
|
|
995
1010
|
.option('--screenshot <path>', 'Screenshot output path')
|
|
996
|
-
.option('--
|
|
997
|
-
.
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
const timeoutSeconds = opts.timeout !== undefined ? Number.parseFloat(String(opts.timeout)) : undefined;
|
|
1004
|
-
await (0, capture_1.capture)(target, {
|
|
1005
|
-
timeoutSeconds,
|
|
1006
|
-
appName: opts.app,
|
|
1007
|
-
logLevel: opts.logLevel,
|
|
1008
|
-
screenshotPath: opts.screenshot,
|
|
1009
|
-
surfaceTarget: opts.surface,
|
|
1010
|
-
devAuth: opts.devAuth,
|
|
1011
|
-
player: opts.player,
|
|
1012
|
-
resetDevPlayer: opts.resetDevPlayer,
|
|
1013
|
-
username: opts.username,
|
|
1014
|
-
password: opts.password,
|
|
1011
|
+
.option('--actions <path>', 'JSON action script to dispatch after the game frame is ready')
|
|
1012
|
+
.action(async (target, opts = {}) => {
|
|
1013
|
+
await (0, check_1.check)(target, {
|
|
1014
|
+
app: opts.app,
|
|
1015
|
+
timeout: opts.timeout,
|
|
1016
|
+
screenshot: opts.screenshot,
|
|
1017
|
+
actions: opts.actions,
|
|
1015
1018
|
});
|
|
1016
1019
|
});
|
|
1020
|
+
const projectCapture = project.command('capture').description('Record game media with the native macOS recorder');
|
|
1017
1021
|
projectCapture
|
|
1018
|
-
.
|
|
1019
|
-
.description('Record private listing video for a hosted app')
|
|
1022
|
+
.argument('[target]')
|
|
1020
1023
|
.option('--app <name>', 'App name when the target is a workspace')
|
|
1021
1024
|
.option('--duration <seconds>', 'Recording duration in seconds')
|
|
1022
1025
|
.option('--width <pixels>', 'Final gameplay width in pixels')
|
|
@@ -1026,6 +1029,7 @@ projectCapture
|
|
|
1026
1029
|
.option('--audio', 'Capture gameplay audio')
|
|
1027
1030
|
.option('--output-dir <path>', 'Output directory for the capture artifacts')
|
|
1028
1031
|
.option('--keep-raw', 'Keep the raw intermediate recording')
|
|
1032
|
+
.option('--content-hash <sha256>', 'Uploaded build content hash to bind this capture to')
|
|
1029
1033
|
.action(async (target, opts) => {
|
|
1030
1034
|
await (0, captureListing_1.captureListing)(target, {
|
|
1031
1035
|
app: opts.app,
|
|
@@ -1037,27 +1041,7 @@ projectCapture
|
|
|
1037
1041
|
audio: opts.audio,
|
|
1038
1042
|
outputDir: opts.outputDir,
|
|
1039
1043
|
keepRaw: opts.keepRaw,
|
|
1040
|
-
|
|
1041
|
-
});
|
|
1042
|
-
projectCapture
|
|
1043
|
-
.command('remote <url>')
|
|
1044
|
-
.description('Run a Playwright capture against a published URL')
|
|
1045
|
-
.option('--timeout <seconds>', 'Readiness timeout in seconds')
|
|
1046
|
-
.option('--settle <seconds>', 'Post-ready settle delay before screenshot in seconds')
|
|
1047
|
-
.option('--screenshot <path>', 'Screenshot output path')
|
|
1048
|
-
.option('--log <path>', 'Log output path')
|
|
1049
|
-
.option('--expected-url <url>', 'Expected final URL after redirects')
|
|
1050
|
-
.option('--actions <path>', 'JSON action file with click, press, and wait steps before screenshot')
|
|
1051
|
-
.option('--viewport <size>', 'Viewport size as WIDTHxHEIGHT')
|
|
1052
|
-
.option('--surface <surface>', 'Browser surface preset: desktop, mobile-landscape, or mobile-portrait')
|
|
1053
|
-
.option('--fps-sample-ms <milliseconds>', 'Sample frame rate for this many milliseconds after capture')
|
|
1054
|
-
.option('--username <username>', 'Login username')
|
|
1055
|
-
.option('--password <password>', 'Login password')
|
|
1056
|
-
.option('--login-url <url>', 'Explicit login URL')
|
|
1057
|
-
.action(async (url, _opts, command) => {
|
|
1058
|
-
await (0, captureRemote_1.captureRemote)(url, {
|
|
1059
|
-
...(command.parent?.opts() ?? {}),
|
|
1060
|
-
...command.opts(),
|
|
1044
|
+
contentHash: opts.contentHash,
|
|
1061
1045
|
});
|
|
1062
1046
|
});
|
|
1063
1047
|
const projectMarketing = project.command('marketing').description('Prepare local marketing captures and assets');
|
package/dist/playwright.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Browser, BrowserContext, BrowserContextOptions, Page } from 'playwright-core';
|
|
2
2
|
export declare const HEADLESS_CHROMIUM_ARGS: readonly ["--no-sandbox", "--disable-web-security", "--use-gl=angle", "--use-angle=swiftshader", "--enable-unsafe-swiftshader", "--ignore-gpu-blocklist"];
|
|
3
3
|
export declare const INTERACTIVE_CHROMIUM_ARGS: readonly ["--no-sandbox", "--disable-web-security", "--ignore-gpu-blocklist"];
|
|
4
|
+
export declare const INSTALLED_CHROME_ARGS: readonly ["--no-sandbox", "--disable-web-security", "--ignore-gpu-blocklist"];
|
|
4
5
|
export declare const CHROMIUM_ARGS: readonly ["--no-sandbox", "--disable-web-security", "--use-gl=angle", "--use-angle=swiftshader", "--enable-unsafe-swiftshader", "--ignore-gpu-blocklist"];
|
|
5
6
|
type PlaywrightModule = {
|
|
6
7
|
chromium: {
|
|
@@ -8,11 +9,13 @@ type PlaywrightModule = {
|
|
|
8
9
|
headless?: boolean;
|
|
9
10
|
args?: readonly string[];
|
|
10
11
|
chromiumSandbox?: boolean;
|
|
12
|
+
channel?: string;
|
|
11
13
|
}): Promise<Browser>;
|
|
12
14
|
launchPersistentContext?(userDataDir: string, options: BrowserContextOptions & {
|
|
13
15
|
headless?: boolean;
|
|
14
16
|
args?: readonly string[];
|
|
15
17
|
chromiumSandbox?: boolean;
|
|
18
|
+
channel?: string;
|
|
16
19
|
}): Promise<BrowserContext>;
|
|
17
20
|
};
|
|
18
21
|
};
|
|
@@ -21,11 +24,13 @@ type PlaydropBrowserContextOptions = BrowserContextOptions & {
|
|
|
21
24
|
};
|
|
22
25
|
export declare function setPlaywrightLoader(loader: (() => Promise<PlaywrightModule>) | null): void;
|
|
23
26
|
export declare function createPlaywrightLaunchError(tool: string, error: unknown): Error;
|
|
27
|
+
export declare function createInstalledChromeLaunchError(tool: string, error: unknown): Error;
|
|
24
28
|
type PageCallback<T> = (context: {
|
|
25
29
|
browser: Browser;
|
|
26
30
|
context: BrowserContext;
|
|
27
31
|
page: Page;
|
|
28
32
|
}) => Promise<T>;
|
|
29
33
|
export declare function withChromiumPage<T>(callback: PageCallback<T>, options?: PlaydropBrowserContextOptions): Promise<T>;
|
|
34
|
+
export declare function withInstalledChromePage<T>(callback: PageCallback<T>, options?: PlaydropBrowserContextOptions): Promise<T>;
|
|
30
35
|
export declare function launchPersistentChromiumContext(userDataDir: string, options?: PlaydropBrowserContextOptions): Promise<BrowserContext>;
|
|
31
36
|
export {};
|
package/dist/playwright.js
CHANGED
|
@@ -33,13 +33,16 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.CHROMIUM_ARGS = exports.INTERACTIVE_CHROMIUM_ARGS = exports.HEADLESS_CHROMIUM_ARGS = void 0;
|
|
36
|
+
exports.CHROMIUM_ARGS = exports.INSTALLED_CHROME_ARGS = exports.INTERACTIVE_CHROMIUM_ARGS = exports.HEADLESS_CHROMIUM_ARGS = void 0;
|
|
37
37
|
exports.setPlaywrightLoader = setPlaywrightLoader;
|
|
38
38
|
exports.createPlaywrightLaunchError = createPlaywrightLaunchError;
|
|
39
|
+
exports.createInstalledChromeLaunchError = createInstalledChromeLaunchError;
|
|
39
40
|
exports.withChromiumPage = withChromiumPage;
|
|
41
|
+
exports.withInstalledChromePage = withInstalledChromePage;
|
|
40
42
|
exports.launchPersistentChromiumContext = launchPersistentChromiumContext;
|
|
41
43
|
const node_url_1 = require("node:url");
|
|
42
44
|
const TOOL_NAME = 'playdrop';
|
|
45
|
+
const INSTALLED_CHROME_CHANNEL = 'chrome';
|
|
43
46
|
const COMMON_CHROMIUM_ARGS = [
|
|
44
47
|
'--no-sandbox',
|
|
45
48
|
'--disable-web-security',
|
|
@@ -57,6 +60,8 @@ exports.INTERACTIVE_CHROMIUM_ARGS = [
|
|
|
57
60
|
...COMMON_CHROMIUM_ARGS,
|
|
58
61
|
'--ignore-gpu-blocklist',
|
|
59
62
|
];
|
|
63
|
+
// Deterministic project checks must exercise the installed Chrome GPU path.
|
|
64
|
+
exports.INSTALLED_CHROME_ARGS = exports.INTERACTIVE_CHROMIUM_ARGS;
|
|
60
65
|
// Backward-compatible alias for older imports.
|
|
61
66
|
exports.CHROMIUM_ARGS = exports.HEADLESS_CHROMIUM_ARGS;
|
|
62
67
|
let customLoader = null;
|
|
@@ -101,6 +106,19 @@ function createPlaywrightLaunchError(tool, error) {
|
|
|
101
106
|
}
|
|
102
107
|
return error instanceof Error ? error : new Error(message);
|
|
103
108
|
}
|
|
109
|
+
function createInstalledChromeLaunchError(tool, error) {
|
|
110
|
+
const message = error && typeof error === 'object' && 'message' in error ? String(error.message) : String(error);
|
|
111
|
+
return new Error([
|
|
112
|
+
`[${tool}] Failed to launch installed Google Chrome.`,
|
|
113
|
+
'',
|
|
114
|
+
'Required setup:',
|
|
115
|
+
' 1. Install Google Chrome for this macOS user.',
|
|
116
|
+
' 2. Run from a logged-in GUI session with WindowServer access.',
|
|
117
|
+
' 3. If invoked over SSH, keep keychain unlock and the command in the same SSH session.',
|
|
118
|
+
'',
|
|
119
|
+
`Original error: ${message}`,
|
|
120
|
+
].join('\n'));
|
|
121
|
+
}
|
|
104
122
|
async function grantAutomationLocalNetworkAccess(context, origin) {
|
|
105
123
|
if (!origin?.trim()) {
|
|
106
124
|
return;
|
|
@@ -153,6 +171,47 @@ async function withChromiumPage(callback, options = {}) {
|
|
|
153
171
|
}
|
|
154
172
|
}
|
|
155
173
|
}
|
|
174
|
+
async function withInstalledChromePage(callback, options = {}) {
|
|
175
|
+
const { chromium } = await loadPlaywright();
|
|
176
|
+
let browser;
|
|
177
|
+
try {
|
|
178
|
+
browser = await chromium.launch({
|
|
179
|
+
channel: INSTALLED_CHROME_CHANNEL,
|
|
180
|
+
headless: false,
|
|
181
|
+
args: [...exports.INSTALLED_CHROME_ARGS],
|
|
182
|
+
chromiumSandbox: false,
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
catch (error) {
|
|
186
|
+
throw createInstalledChromeLaunchError(TOOL_NAME, error);
|
|
187
|
+
}
|
|
188
|
+
let context = null;
|
|
189
|
+
try {
|
|
190
|
+
const { automationOrigin, ...contextOptions } = options;
|
|
191
|
+
context = await browser.newContext(contextOptions);
|
|
192
|
+
await grantAutomationLocalNetworkAccess(context, automationOrigin);
|
|
193
|
+
const page = await context.newPage();
|
|
194
|
+
return await callback({ browser, context, page });
|
|
195
|
+
}
|
|
196
|
+
finally {
|
|
197
|
+
if (context) {
|
|
198
|
+
try {
|
|
199
|
+
await context.close();
|
|
200
|
+
}
|
|
201
|
+
catch (closeError) {
|
|
202
|
+
const message = closeError instanceof Error ? closeError.message : String(closeError);
|
|
203
|
+
console.warn(`[${TOOL_NAME}] Failed to close Playwright context: ${message}`);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
try {
|
|
207
|
+
await browser.close();
|
|
208
|
+
}
|
|
209
|
+
catch (closeError) {
|
|
210
|
+
const message = closeError instanceof Error ? closeError.message : String(closeError);
|
|
211
|
+
console.warn(`[${TOOL_NAME}] Failed to close Playwright browser: ${message}`);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
156
215
|
async function launchPersistentChromiumContext(userDataDir, options = {}) {
|
|
157
216
|
const { chromium } = await loadPlaywright();
|
|
158
217
|
if (typeof chromium.launchPersistentContext !== 'function') {
|