@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.
@@ -1,7 +1,7 @@
1
1
  {
2
- "version": "0.13.3",
2
+ "version": "0.13.5",
3
3
  "build": 1,
4
- "runtimeSdkVersion": "0.13.3",
4
+ "runtimeSdkVersion": "0.13.5",
5
5
  "runtimeSdkBuild": 1,
6
6
  "clients": {
7
7
  "all": {
@@ -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>;
@@ -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);
@@ -1,7 +1,7 @@
1
1
  {
2
- "version": "0.13.3",
2
+ "version": "0.13.5",
3
3
  "build": 1,
4
- "runtimeSdkVersion": "0.13.3",
4
+ "runtimeSdkVersion": "0.13.5",
5
5
  "runtimeSdkBuild": 1,
6
6
  "clients": {
7
7
  "all": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@playdrop/playdrop-cli",
3
- "version": "0.13.3",
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": {