@playdrop/playdrop-cli 0.14.7 → 0.14.8

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.14.7",
2
+ "version": "0.14.8",
3
3
  "build": 1,
4
- "runtimeSdkVersion": "0.14.7",
4
+ "runtimeSdkVersion": "0.14.8",
5
5
  "runtimeSdkBuild": 1,
6
6
  "clients": {
7
7
  "all": {
@@ -346,7 +346,7 @@ type WorkerRuntimeState = {
346
346
  target: AgentExecutionTarget;
347
347
  startedAt: string;
348
348
  };
349
- export type WorkerSupervisorType = 'app' | 'terminal';
349
+ export type WorkerSupervisorType = 'app' | 'launchagent' | 'terminal';
350
350
  export type WorkerSupervisorLockOwner = {
351
351
  schemaVersion: 1;
352
352
  supervisorType: WorkerSupervisorType;
@@ -151,7 +151,7 @@ const CLAIM_BACKOFF_JITTER_MS = 500;
151
151
  const FAIL_REPORT_RETRY_DELAY_MS = 2000;
152
152
  const WORKER_TRANSCRIPT_CHUNK_BATCH_SIZE = 100;
153
153
  const SLACK_API_BASE_URL = 'https://slack.com/api';
154
- const WORKER_WRAPPER_CONTRACT_VERSION = 2;
154
+ const WORKER_WRAPPER_CONTRACT_VERSION = 3;
155
155
  const WORKER_SUPPORTED_KINDS = ['NEW_GAME', 'STATIC_GAME', 'REMIX_GAME', 'GAME_UPDATE', 'GAME_REVIEW', 'GAME_EVAL'];
156
156
  const GAME_CREATION_TASK_KINDS = new Set(['NEW_GAME', 'STATIC_GAME', 'REMIX_GAME', 'GAME_UPDATE']);
157
157
  const AGENT_MANAGED_UPLOAD_TASK_KINDS = new Set(['NEW_GAME', 'REMIX_GAME', 'GAME_UPDATE']);
@@ -3238,8 +3238,8 @@ function resolveWorkerStateDir() {
3238
3238
  }
3239
3239
  function normalizeWorkerSupervisorType(value) {
3240
3240
  const normalized = value?.trim().toLowerCase() || 'terminal';
3241
- if (normalized !== 'app' && normalized !== 'terminal') {
3242
- throw new Error(`worker_supervisor_type_invalid: expected app or terminal, received ${value ?? ''}.`);
3241
+ if (normalized !== 'app' && normalized !== 'launchagent' && normalized !== 'terminal') {
3242
+ throw new Error(`worker_supervisor_type_invalid: expected app, launchagent, or terminal, received ${value ?? ''}.`);
3243
3243
  }
3244
3244
  return normalized;
3245
3245
  }
@@ -3299,7 +3299,7 @@ function readWorkerSupervisorLockOwner(file) {
3299
3299
  throw new Error(`worker_supervisor_lock_invalid: ${file} does not contain valid owner metadata.`);
3300
3300
  }
3301
3301
  if (parsed.schemaVersion !== 1
3302
- || (parsed.supervisorType !== 'app' && parsed.supervisorType !== 'terminal')
3302
+ || (parsed.supervisorType !== 'app' && parsed.supervisorType !== 'launchagent' && parsed.supervisorType !== 'terminal')
3303
3303
  || !Number.isInteger(parsed.pid)
3304
3304
  || (parsed.pid ?? 0) <= 0
3305
3305
  || typeof parsed.processStartIdentity !== 'string'
@@ -3323,7 +3323,11 @@ function workerSupervisorOwnerIsLive(owner) {
3323
3323
  return currentIdentity === owner.processStartIdentity;
3324
3324
  }
3325
3325
  function workerSupervisorHolderDescription(owner) {
3326
- const supervisor = owner.supervisorType === 'app' ? 'Local Agent app' : 'terminal';
3326
+ const supervisor = owner.supervisorType === 'app'
3327
+ ? 'Local Agent app'
3328
+ : owner.supervisorType === 'launchagent'
3329
+ ? 'LaunchAgent'
3330
+ : 'terminal';
3327
3331
  return `${supervisor} worker "${owner.workerName}" (PID ${owner.pid})`;
3328
3332
  }
3329
3333
  function workerSupervisorOwnersMatch(left, right) {
@@ -3384,7 +3388,12 @@ function acquireWorkerSupervisorLock(input) {
3384
3388
  }
3385
3389
  const holder = readWorkerSupervisorLockOwner(file);
3386
3390
  if (workerSupervisorOwnerIsLive(holder)) {
3387
- throw new Error(`worker_supervisor_lock_held: ${workerSupervisorHolderDescription(holder)} already owns ${file}. Stop that worker before starting ${input.supervisorType === 'app' ? 'the Local Agent app worker' : 'a terminal worker'}.`);
3391
+ const requestedSupervisor = input.supervisorType === 'app'
3392
+ ? 'the Local Agent app worker'
3393
+ : input.supervisorType === 'launchagent'
3394
+ ? 'the LaunchAgent worker'
3395
+ : 'a terminal worker';
3396
+ throw new Error(`worker_supervisor_lock_held: ${workerSupervisorHolderDescription(holder)} already owns ${file}. Stop that worker before starting ${requestedSupervisor}.`);
3388
3397
  }
3389
3398
  removeStaleWorkerSupervisorLockIfUnchanged(file, holder);
3390
3399
  }
@@ -3885,7 +3894,7 @@ if [ "$TARGET_UPDATE_FAILED" -eq 0 ]; then
3885
3894
  rm -f "$FAILURE_FILE"
3886
3895
  fi
3887
3896
 
3888
- exec /usr/bin/caffeinate -dimsu playdrop worker start --env ${shellQuote(input.env)} --name ${shellQuote(input.workerName)}
3897
+ exec /usr/bin/caffeinate -dimsu playdrop worker start --env ${shellQuote(input.env)} --name ${shellQuote(input.workerName)} --supervisor launchagent
3889
3898
  `;
3890
3899
  await (0, promises_1.writeFile)(wrapperPath, script, 'utf8');
3891
3900
  await (0, promises_1.chmod)(wrapperPath, 0o755);
@@ -4191,6 +4200,19 @@ async function startWorker(options = {}) {
4191
4200
  throw new Error(`worker_update_policy_target_mismatch: expected ${target}, received ${initialWorkerPolicy.executionTarget}.`);
4192
4201
  }
4193
4202
  const workerName = options.name?.trim() || `${username} - ${node_os_1.default.hostname()}`;
4203
+ const workerKey = (0, config_1.getOrCreateWorkerKey)();
4204
+ const runningWrapperVersion = (0, runtime_1.readPositiveEnvInt)('PLAYDROP_WORKER_WRAPPER_CONTRACT_VERSION', WORKER_WRAPPER_CONTRACT_VERSION);
4205
+ if (target === 'FIRST_PARTY'
4206
+ && node_process_1.default.platform === 'darwin'
4207
+ && options.env?.trim()
4208
+ && node_process_1.default.env.PLAYDROP_WORKER_WRAPPER_CONTRACT_VERSION
4209
+ && runningWrapperVersion < WORKER_WRAPPER_CONTRACT_VERSION) {
4210
+ verifyNpmGlobalInstallPreconditions();
4211
+ const { wrapperPath } = await writeManagedWorkerWrapper({ env, workerName, workerKey });
4212
+ await writeManagedWorkerLaunchAgent({ env, workerName, wrapperPath });
4213
+ console.log(`Worker repaired LaunchAgent wrapper contract ${runningWrapperVersion} -> ${WORKER_WRAPPER_CONTRACT_VERSION}. Restarting under LaunchAgent ownership.`);
4214
+ return;
4215
+ }
4194
4216
  const supervisorType = normalizeWorkerSupervisorType(options.supervisor);
4195
4217
  const supervisorLock = acquireWorkerSupervisorLock({ supervisorType, workerName });
4196
4218
  try {
@@ -4221,7 +4243,6 @@ async function startWorker(options = {}) {
4221
4243
  chromiumInstalled: true,
4222
4244
  ...(local.playwright.executablePath ? { executablePath: local.playwright.executablePath } : {}),
4223
4245
  };
4224
- const workerKey = (0, config_1.getOrCreateWorkerKey)();
4225
4246
  const maxParallelTasks = (0, runtime_1.readPositiveEnvInt)('PLAYDROP_WORKER_MAX_PARALLEL_TASKS', DEFAULT_WORKER_MAX_PARALLEL_TASKS);
4226
4247
  let capabilities = local.capabilities;
4227
4248
  let lastCapabilityRefreshAt = Date.now();
package/dist/index.js CHANGED
@@ -179,7 +179,7 @@ worker
179
179
  .option('--env <env>', 'Resolve this command against one logged-in environment')
180
180
  .option('--once', 'Process at most one task then exit')
181
181
  .option('--name <name>', 'Worker display name override')
182
- .option('--supervisor <type>', 'Worker supervisor type: app or terminal', 'terminal')
182
+ .option('--supervisor <type>', 'Worker supervisor type: app, launchagent, or terminal', 'terminal')
183
183
  .option('--supervise-stdin', 'Exit with a bounded shutdown when stdin closes')
184
184
  .option('--dev-plugin-working-tree <path>', 'DEV ONLY: stage task plugin files from this working tree')
185
185
  .action(async (opts) => {
@@ -1,7 +1,7 @@
1
1
  {
2
- "version": "0.14.7",
2
+ "version": "0.14.8",
3
3
  "build": 1,
4
- "runtimeSdkVersion": "0.14.7",
4
+ "runtimeSdkVersion": "0.14.8",
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.14.7",
3
+ "version": "0.14.8",
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": {