@playdrop/playdrop-cli 0.13.3 → 0.13.5
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
CHANGED
|
@@ -304,15 +304,6 @@ export declare function parseCodexModelCatalog(output: string): string[];
|
|
|
304
304
|
export declare function parseClaudeModelCatalog(output: string): string[];
|
|
305
305
|
export declare function claudeModelProbeReportsSelection(output: string, expectedDisplayName: string): boolean;
|
|
306
306
|
export declare function probeWorkerProviderIndependently<T>(probe: () => T, unavailable: T): T;
|
|
307
|
-
type MacChromeAutomationProbeRunner = (command: string, args: string[]) => {
|
|
308
|
-
status: number | null;
|
|
309
|
-
stdout: string;
|
|
310
|
-
stderr: string;
|
|
311
|
-
};
|
|
312
|
-
export declare function probeMacChromeAutomationPermission(options?: {
|
|
313
|
-
platform?: NodeJS.Platform;
|
|
314
|
-
runner?: MacChromeAutomationProbeRunner;
|
|
315
|
-
}): 'granted' | 'not_running' | 'denied' | 'not_applicable';
|
|
316
307
|
export declare function describeWorkerPreflightReason(reason: string): string;
|
|
317
308
|
export declare function buildWorkerSetupActions(input: {
|
|
318
309
|
degradedReasons: string[];
|
|
@@ -390,29 +381,6 @@ export declare function launchManagedWorker(label: string, plistPath: string, op
|
|
|
390
381
|
}): void;
|
|
391
382
|
export declare function showWorkerStatus(options?: WorkerStatusOptions): Promise<WorkerStatusPayload>;
|
|
392
383
|
export declare function setupWorker(options?: WorkerSetupOptions): Promise<void>;
|
|
393
|
-
export declare function instrumentTaskChromeTitleMatchers(assignment: WorkerTaskAssignmentV2): string[];
|
|
394
|
-
type InstrumentBrowserHygieneRunner = (command: string, args: string[]) => Promise<{
|
|
395
|
-
stdout: string;
|
|
396
|
-
stderr: string;
|
|
397
|
-
}>;
|
|
398
|
-
export declare function enforceInstrumentBrowserHygiene(assignment: WorkerTaskAssignmentV2, options?: {
|
|
399
|
-
platform?: NodeJS.Platform;
|
|
400
|
-
runner?: InstrumentBrowserHygieneRunner;
|
|
401
|
-
}): Promise<{
|
|
402
|
-
remainingTaskTabs: number;
|
|
403
|
-
blankWindows: number;
|
|
404
|
-
}>;
|
|
405
|
-
export declare function finalizeInstrumentBrowserHygiene(assignment: WorkerTaskAssignmentV2, options?: {
|
|
406
|
-
platform?: NodeJS.Platform;
|
|
407
|
-
runner?: InstrumentBrowserHygieneRunner;
|
|
408
|
-
}): Promise<{
|
|
409
|
-
ok: true;
|
|
410
|
-
remainingTaskTabs: number;
|
|
411
|
-
blankWindows: number;
|
|
412
|
-
} | {
|
|
413
|
-
ok: false;
|
|
414
|
-
error: string;
|
|
415
|
-
}>;
|
|
416
384
|
export declare function assignmentRequiresRegisteredBundle(assignment: WorkerTaskAssignmentV2): boolean;
|
|
417
385
|
export declare function startWorker(options?: WorkerStartOptions): Promise<void>;
|
|
418
386
|
export declare function reportTask(options: TaskReportOptions): Promise<void>;
|
package/dist/commands/worker.js
CHANGED
|
@@ -56,7 +56,6 @@ exports.parseCodexModelCatalog = parseCodexModelCatalog;
|
|
|
56
56
|
exports.parseClaudeModelCatalog = parseClaudeModelCatalog;
|
|
57
57
|
exports.claudeModelProbeReportsSelection = claudeModelProbeReportsSelection;
|
|
58
58
|
exports.probeWorkerProviderIndependently = probeWorkerProviderIndependently;
|
|
59
|
-
exports.probeMacChromeAutomationPermission = probeMacChromeAutomationPermission;
|
|
60
59
|
exports.describeWorkerPreflightReason = describeWorkerPreflightReason;
|
|
61
60
|
exports.buildWorkerSetupActions = buildWorkerSetupActions;
|
|
62
61
|
exports.resolveWorkerStateDir = resolveWorkerStateDir;
|
|
@@ -77,9 +76,6 @@ exports.assertLaunchAgentPlistCompatible = assertLaunchAgentPlistCompatible;
|
|
|
77
76
|
exports.launchManagedWorker = launchManagedWorker;
|
|
78
77
|
exports.showWorkerStatus = showWorkerStatus;
|
|
79
78
|
exports.setupWorker = setupWorker;
|
|
80
|
-
exports.instrumentTaskChromeTitleMatchers = instrumentTaskChromeTitleMatchers;
|
|
81
|
-
exports.enforceInstrumentBrowserHygiene = enforceInstrumentBrowserHygiene;
|
|
82
|
-
exports.finalizeInstrumentBrowserHygiene = finalizeInstrumentBrowserHygiene;
|
|
83
79
|
exports.assignmentRequiresRegisteredBundle = assignmentRequiresRegisteredBundle;
|
|
84
80
|
exports.startWorker = startWorker;
|
|
85
81
|
exports.reportTask = reportTask;
|
|
@@ -2852,37 +2848,6 @@ function resolveInstalledChromeExecutable() {
|
|
|
2852
2848
|
}
|
|
2853
2849
|
return workerCommandExists('google-chrome') ? 'google-chrome' : null;
|
|
2854
2850
|
}
|
|
2855
|
-
const MAC_CHROME_AUTOMATION_PREFLIGHT_APPLESCRIPT = `
|
|
2856
|
-
if application "Google Chrome" is not running then
|
|
2857
|
-
return "not_running"
|
|
2858
|
-
end if
|
|
2859
|
-
tell application "Google Chrome"
|
|
2860
|
-
count of windows
|
|
2861
|
-
end tell
|
|
2862
|
-
return "granted"
|
|
2863
|
-
`;
|
|
2864
|
-
function probeMacChromeAutomationPermission(options = {}) {
|
|
2865
|
-
if ((options.platform ?? node_process_1.default.platform) !== 'darwin') {
|
|
2866
|
-
return 'not_applicable';
|
|
2867
|
-
}
|
|
2868
|
-
const runner = options.runner ?? ((command, args) => {
|
|
2869
|
-
const result = (0, node_child_process_1.spawnSync)(command, args, { encoding: 'utf8', timeout: 10000 });
|
|
2870
|
-
return {
|
|
2871
|
-
status: result.status,
|
|
2872
|
-
stdout: result.stdout ?? '',
|
|
2873
|
-
stderr: result.stderr ?? '',
|
|
2874
|
-
};
|
|
2875
|
-
});
|
|
2876
|
-
const result = runner('osascript', ['-e', MAC_CHROME_AUTOMATION_PREFLIGHT_APPLESCRIPT]);
|
|
2877
|
-
const output = result.stdout.trim();
|
|
2878
|
-
if (result.status === 0 && output === 'granted') {
|
|
2879
|
-
return 'granted';
|
|
2880
|
-
}
|
|
2881
|
-
if (result.status === 0 && output === 'not_running') {
|
|
2882
|
-
return 'not_running';
|
|
2883
|
-
}
|
|
2884
|
-
return 'denied';
|
|
2885
|
-
}
|
|
2886
2851
|
function collectWorkerInfrastructureFailures() {
|
|
2887
2852
|
const failures = [];
|
|
2888
2853
|
if (!resolveInstalledChromeExecutable()) {
|
|
@@ -2911,9 +2876,6 @@ function collectWorkerInfrastructureFailures() {
|
|
|
2911
2876
|
if (guiSession.exitCode !== 0) {
|
|
2912
2877
|
failures.push('worker_preflight_gui_session_missing');
|
|
2913
2878
|
}
|
|
2914
|
-
if (probeMacChromeAutomationPermission() === 'denied') {
|
|
2915
|
-
failures.push('worker_preflight_chrome_automation_permission_missing');
|
|
2916
|
-
}
|
|
2917
2879
|
const recorderPath = (0, recorderRelease_1.resolveMacWorkerRecorderPath)();
|
|
2918
2880
|
if (!(0, node_fs_1.existsSync)(recorderPath)) {
|
|
2919
2881
|
failures.push('worker_preflight_recorder_missing');
|
|
@@ -2951,7 +2913,6 @@ function describeWorkerPreflightReason(reason) {
|
|
|
2951
2913
|
worker_preflight_ffmpeg_missing: 'ffmpeg is missing from PATH.',
|
|
2952
2914
|
worker_preflight_ffprobe_missing: 'ffprobe is missing from PATH.',
|
|
2953
2915
|
worker_preflight_gui_session_missing: 'No active macOS GUI session is available.',
|
|
2954
|
-
worker_preflight_chrome_automation_permission_missing: 'Google Chrome Automation permission is missing. In System Settings > Privacy & Security > Automation, allow the PlayDrop worker process to control Google Chrome, then restart the worker.',
|
|
2955
2916
|
worker_preflight_recorder_architecture_unsupported: 'The native recorder is currently available only for Apple silicon Macs.',
|
|
2956
2917
|
worker_preflight_recorder_missing: 'The PlayDrop macOS recorder is missing.',
|
|
2957
2918
|
worker_preflight_recorder_not_executable: 'The PlayDrop macOS recorder is not executable.',
|
|
@@ -3120,7 +3081,6 @@ function buildWorkerSetupActions(input) {
|
|
|
3120
3081
|
addManualAction('worker_preflight_ffmpeg_missing', 'Install ffmpeg');
|
|
3121
3082
|
addManualAction('worker_preflight_ffprobe_missing', 'Install ffprobe');
|
|
3122
3083
|
addManualAction('worker_preflight_gui_session_missing', 'Sign in to the Mac desktop');
|
|
3123
|
-
addManualAction('worker_preflight_chrome_automation_permission_missing', 'Grant Google Chrome Automation permission');
|
|
3124
3084
|
addManualAction('worker_preflight_recorder_architecture_unsupported', 'Use an Apple silicon Mac');
|
|
3125
3085
|
addManualAction('worker_preflight_recorder_missing', 'Restart the worker to download the recorder');
|
|
3126
3086
|
addManualAction('worker_preflight_recorder_not_executable', 'Restart the worker to repair the recorder');
|
|
@@ -4045,173 +4005,6 @@ async function fetchTaskDetail(client, target, taskId) {
|
|
|
4045
4005
|
}
|
|
4046
4006
|
return await client.getAgentTask(taskId);
|
|
4047
4007
|
}
|
|
4048
|
-
function instrumentTaskChromeTitleMatchers(assignment) {
|
|
4049
|
-
const playdrop = assignment.task.metadata.playdrop;
|
|
4050
|
-
const metadata = playdrop && typeof playdrop === 'object' && !Array.isArray(playdrop)
|
|
4051
|
-
? playdrop
|
|
4052
|
-
: {};
|
|
4053
|
-
const kind = metadata.kind;
|
|
4054
|
-
const evalTarget = metadata.evalTarget && typeof metadata.evalTarget === 'object' && !Array.isArray(metadata.evalTarget)
|
|
4055
|
-
? metadata.evalTarget
|
|
4056
|
-
: null;
|
|
4057
|
-
const targets = kind === 'GAME_REVIEW'
|
|
4058
|
-
? [metadata.reviewTarget]
|
|
4059
|
-
: kind === 'GAME_EVAL' && Array.isArray(evalTarget?.targets)
|
|
4060
|
-
? evalTarget.targets
|
|
4061
|
-
: [];
|
|
4062
|
-
const matchers = new Set();
|
|
4063
|
-
for (const rawTarget of targets) {
|
|
4064
|
-
const target = rawTarget && typeof rawTarget === 'object' && !Array.isArray(rawTarget)
|
|
4065
|
-
? rawTarget
|
|
4066
|
-
: null;
|
|
4067
|
-
if (!target)
|
|
4068
|
-
continue;
|
|
4069
|
-
for (const value of [target.appDisplayName, target.appName]) {
|
|
4070
|
-
const normalized = typeof value === 'string' ? value.trim() : '';
|
|
4071
|
-
if (normalized.length >= 3) {
|
|
4072
|
-
matchers.add(normalized);
|
|
4073
|
-
}
|
|
4074
|
-
}
|
|
4075
|
-
}
|
|
4076
|
-
return [...matchers].sort((left, right) => right.length - left.length);
|
|
4077
|
-
}
|
|
4078
|
-
const INSTRUMENT_BROWSER_HYGIENE_APPLESCRIPT = String.raw `
|
|
4079
|
-
on run matchers
|
|
4080
|
-
tell application "Google Chrome"
|
|
4081
|
-
repeat with windowIndex from (count of windows) to 1 by -1
|
|
4082
|
-
try
|
|
4083
|
-
set currentWindow to window windowIndex
|
|
4084
|
-
repeat with tabIndex from (count of tabs of currentWindow) to 1 by -1
|
|
4085
|
-
set currentTab to tab tabIndex of currentWindow
|
|
4086
|
-
set currentTitle to title of currentTab
|
|
4087
|
-
set shouldClose to false
|
|
4088
|
-
repeat with matcher in matchers
|
|
4089
|
-
if currentTitle contains (matcher as text) then
|
|
4090
|
-
set shouldClose to true
|
|
4091
|
-
exit repeat
|
|
4092
|
-
end if
|
|
4093
|
-
end repeat
|
|
4094
|
-
if shouldClose then close currentTab
|
|
4095
|
-
end repeat
|
|
4096
|
-
end try
|
|
4097
|
-
end repeat
|
|
4098
|
-
|
|
4099
|
-
set blankWindowCount to 0
|
|
4100
|
-
repeat with currentWindow in windows
|
|
4101
|
-
try
|
|
4102
|
-
if (count of tabs of currentWindow) is 1 then
|
|
4103
|
-
set currentUrl to URL of active tab of currentWindow
|
|
4104
|
-
if currentUrl is "about:blank" or currentUrl starts with "chrome://newtab" then
|
|
4105
|
-
set blankWindowCount to blankWindowCount + 1
|
|
4106
|
-
end if
|
|
4107
|
-
end if
|
|
4108
|
-
end try
|
|
4109
|
-
end repeat
|
|
4110
|
-
if blankWindowCount is 0 then
|
|
4111
|
-
set blankWindow to make new window
|
|
4112
|
-
set URL of active tab of blankWindow to "about:blank"
|
|
4113
|
-
delay 1
|
|
4114
|
-
end if
|
|
4115
|
-
|
|
4116
|
-
set keptBlankWindow to false
|
|
4117
|
-
repeat with windowIndex from (count of windows) to 1 by -1
|
|
4118
|
-
try
|
|
4119
|
-
set currentWindow to window windowIndex
|
|
4120
|
-
if (count of tabs of currentWindow) is 1 then
|
|
4121
|
-
set currentUrl to URL of active tab of currentWindow
|
|
4122
|
-
if currentUrl is "about:blank" or currentUrl starts with "chrome://newtab" then
|
|
4123
|
-
if keptBlankWindow then
|
|
4124
|
-
close currentWindow
|
|
4125
|
-
else
|
|
4126
|
-
set keptBlankWindow to true
|
|
4127
|
-
end if
|
|
4128
|
-
end if
|
|
4129
|
-
end if
|
|
4130
|
-
end try
|
|
4131
|
-
end repeat
|
|
4132
|
-
|
|
4133
|
-
set remainingCount to 0
|
|
4134
|
-
set blankWindowCount to 0
|
|
4135
|
-
repeat with currentWindow in windows
|
|
4136
|
-
try
|
|
4137
|
-
repeat with currentTab in tabs of currentWindow
|
|
4138
|
-
set currentTitle to title of currentTab
|
|
4139
|
-
repeat with matcher in matchers
|
|
4140
|
-
if currentTitle contains (matcher as text) then
|
|
4141
|
-
set remainingCount to remainingCount + 1
|
|
4142
|
-
exit repeat
|
|
4143
|
-
end if
|
|
4144
|
-
end repeat
|
|
4145
|
-
end repeat
|
|
4146
|
-
if (count of tabs of currentWindow) is 1 then
|
|
4147
|
-
set currentUrl to URL of active tab of currentWindow
|
|
4148
|
-
if currentUrl is "about:blank" or currentUrl starts with "chrome://newtab" then
|
|
4149
|
-
set blankWindowCount to blankWindowCount + 1
|
|
4150
|
-
end if
|
|
4151
|
-
end if
|
|
4152
|
-
end try
|
|
4153
|
-
end repeat
|
|
4154
|
-
end tell
|
|
4155
|
-
return "remaining=" & remainingCount & ";blank=" & blankWindowCount
|
|
4156
|
-
end run
|
|
4157
|
-
`;
|
|
4158
|
-
async function enforceInstrumentBrowserHygieneUnlocked(assignment, options = {}) {
|
|
4159
|
-
if (assignment.agent.browser === 'NONE') {
|
|
4160
|
-
return { remainingTaskTabs: 0, blankWindows: 0 };
|
|
4161
|
-
}
|
|
4162
|
-
if ((options.platform ?? node_process_1.default.platform) !== 'darwin') {
|
|
4163
|
-
throw new Error('worker_browser_hygiene_requires_macos');
|
|
4164
|
-
}
|
|
4165
|
-
const matchers = instrumentTaskChromeTitleMatchers(assignment);
|
|
4166
|
-
if (matchers.length === 0) {
|
|
4167
|
-
throw new Error('worker_browser_hygiene_missing_title_matchers');
|
|
4168
|
-
}
|
|
4169
|
-
const runner = options.runner ?? (async (command, args) => {
|
|
4170
|
-
const result = await execFileAsync(command, args, { timeout: 15000, maxBuffer: 1024 * 1024 });
|
|
4171
|
-
return { stdout: result.stdout, stderr: result.stderr };
|
|
4172
|
-
});
|
|
4173
|
-
let result = null;
|
|
4174
|
-
for (let attempt = 1; attempt <= 3; attempt += 1) {
|
|
4175
|
-
try {
|
|
4176
|
-
result = await runner('osascript', ['-e', INSTRUMENT_BROWSER_HYGIENE_APPLESCRIPT, ...matchers]);
|
|
4177
|
-
break;
|
|
4178
|
-
}
|
|
4179
|
-
catch (error) {
|
|
4180
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
4181
|
-
if (!message.includes('Connection is invalid. (-609)') || attempt === 3) {
|
|
4182
|
-
throw new Error(`worker_browser_hygiene_automation_failed:${message}`);
|
|
4183
|
-
}
|
|
4184
|
-
await sleep(250);
|
|
4185
|
-
}
|
|
4186
|
-
}
|
|
4187
|
-
if (!result)
|
|
4188
|
-
throw new Error('worker_browser_hygiene_automation_failed:no_result');
|
|
4189
|
-
const match = /remaining=(\d+);blank=(\d+)/.exec(result.stdout.trim());
|
|
4190
|
-
if (!match) {
|
|
4191
|
-
throw new Error(`worker_browser_hygiene_invalid_result:${result.stdout.trim() || result.stderr.trim() || 'empty'}`);
|
|
4192
|
-
}
|
|
4193
|
-
const remainingTaskTabs = Number(match[1]);
|
|
4194
|
-
const blankWindows = Number(match[2]);
|
|
4195
|
-
if (remainingTaskTabs !== 0 || blankWindows !== 1) {
|
|
4196
|
-
throw new Error(`worker_browser_hygiene_failed:remaining=${remainingTaskTabs}:blank=${blankWindows}`);
|
|
4197
|
-
}
|
|
4198
|
-
return { remainingTaskTabs, blankWindows };
|
|
4199
|
-
}
|
|
4200
|
-
let instrumentBrowserHygieneTail = Promise.resolve();
|
|
4201
|
-
async function enforceInstrumentBrowserHygiene(assignment, options = {}) {
|
|
4202
|
-
const result = instrumentBrowserHygieneTail.then(() => enforceInstrumentBrowserHygieneUnlocked(assignment, options));
|
|
4203
|
-
instrumentBrowserHygieneTail = result.then(() => undefined, () => undefined);
|
|
4204
|
-
return result;
|
|
4205
|
-
}
|
|
4206
|
-
async function finalizeInstrumentBrowserHygiene(assignment, options = {}) {
|
|
4207
|
-
try {
|
|
4208
|
-
const result = await enforceInstrumentBrowserHygiene(assignment, options);
|
|
4209
|
-
return { ok: true, ...result };
|
|
4210
|
-
}
|
|
4211
|
-
catch (error) {
|
|
4212
|
-
return { ok: false, error: errorMessage(error) };
|
|
4213
|
-
}
|
|
4214
|
-
}
|
|
4215
4008
|
function assignmentRequiresRegisteredBundle(assignment) {
|
|
4216
4009
|
const playdropMetadata = assignment.task.metadata.playdrop;
|
|
4217
4010
|
return Boolean(playdropMetadata
|
|
@@ -5155,17 +4948,6 @@ async function startWorker(options = {}) {
|
|
|
5155
4948
|
if (eventDrainTimer) {
|
|
5156
4949
|
clearInterval(eventDrainTimer);
|
|
5157
4950
|
}
|
|
5158
|
-
if (agentStartedAt
|
|
5159
|
-
&& assignment.agent.browser !== 'NONE') {
|
|
5160
|
-
const hygiene = await finalizeInstrumentBrowserHygiene(assignment);
|
|
5161
|
-
if (hygiene.ok) {
|
|
5162
|
-
console.log(`Agent task ${task.id} browser hygiene passed: ${hygiene.remainingTaskTabs} task tabs, ${hygiene.blankWindows} blank window(s).`);
|
|
5163
|
-
}
|
|
5164
|
-
else {
|
|
5165
|
-
console.error(`Agent task ${task.id} browser hygiene failed; worker continuing: ${hygiene.error}`);
|
|
5166
|
-
retainWorkspace = true;
|
|
5167
|
-
}
|
|
5168
|
-
}
|
|
5169
4951
|
activeTerminators.delete(task.id);
|
|
5170
4952
|
if (workspaceDir) {
|
|
5171
4953
|
await removeAgentRunCredentials(workspaceDir);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@playdrop/playdrop-cli",
|
|
3
|
-
"version": "0.13.
|
|
3
|
+
"version": "0.13.5",
|
|
4
4
|
"description": "Official Playdrop CLI for publishing browser games, creator apps, and AI-generated game assets on playdrop.ai",
|
|
5
5
|
"homepage": "https://www.playdrop.ai",
|
|
6
6
|
"repository": {
|