@playdrop/playdrop-cli 0.10.5 → 0.10.7

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/README.md CHANGED
@@ -88,7 +88,7 @@ playdrop workspaces init
88
88
 
89
89
  `playdrop agents install-plugin claude` adds the PlayDrop marketplace, installs the PlayDrop plugin through the Claude Code CLI, and tells you to reload plugins.
90
90
 
91
- `playdrop agents install-plugin codex` configures the PlayDrop plugin marketplace and uses Codex's plugin install command when the local Codex CLI exposes one. If the installed Codex CLI only supports marketplace management, finish activation from Codex with `/plugins`.
91
+ `playdrop agents install-plugin codex` configures the PlayDrop plugin marketplace and uses Codex's `plugin add` command when the local Codex CLI exposes it. If the installed Codex CLI only supports marketplace management, finish activation from Codex with `/plugins`.
92
92
 
93
93
  Cursor does not currently expose documented plugin installation through its CLI. `playdrop agents install-plugin cursor` prints the manual steps instead: open Cursor and use `/add-plugin` or the Cursor Marketplace for PlayDrop.
94
94
 
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.10.5",
2
+ "version": "0.10.7",
3
3
  "build": 1,
4
4
  "runtimeSdkVersion": "0.10.0",
5
5
  "clients": {
@@ -296,6 +296,21 @@ function runCodexPluginAction(action, runCommand) {
296
296
  }
297
297
  const help = runCommand('codex', ['plugin', '--help']);
298
298
  const helpText = commandOutput(help);
299
+ if (commandHelpIncludes(helpText, 'add')) {
300
+ const add = runCommand('codex', ['plugin', 'add', PLAYDROP_PLUGIN_SPEC]);
301
+ if (add.status !== 0) {
302
+ console.error(`Codex PlayDrop plugin ${action === 'install-plugin' ? 'install' : 'update'} failed.`);
303
+ process.exitCode = 1;
304
+ return;
305
+ }
306
+ if (commandHelpIncludes(helpText, 'list') && !readInstalledPlayDropPlugin('codex', runCommand)) {
307
+ console.error(`Codex PlayDrop plugin ${action === 'install-plugin' ? 'install' : 'update'} could not be verified from codex plugin list --json.`);
308
+ process.exitCode = 1;
309
+ return;
310
+ }
311
+ console.log(`${action === 'install-plugin' ? 'Installed' : 'Updated'} the PlayDrop plugin for Codex.`);
312
+ return;
313
+ }
299
314
  if (action === 'install-plugin' && commandHelpIncludes(helpText, 'install')) {
300
315
  const install = runCommand('codex', ['plugin', 'install', PLAYDROP_PLUGIN_SPEC]);
301
316
  if (install.status !== 0) {
@@ -1 +1,10 @@
1
- export declare function upgrade(dryRun?: boolean): Promise<void>;
1
+ type UpgradeOptions = {
2
+ dryRun?: boolean;
3
+ targetVersion?: string;
4
+ worker?: boolean;
5
+ env?: string;
6
+ workerKey?: string;
7
+ updatePlugins?: boolean;
8
+ };
9
+ export declare function upgrade(options?: UpgradeOptions): Promise<void>;
10
+ export {};
@@ -2,16 +2,33 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.upgrade = upgrade;
4
4
  const node_child_process_1 = require("node:child_process");
5
- const UPGRADE_COMMAND = ['install', '-g', '@playdrop/playdrop-cli@latest'];
6
- async function upgrade(dryRun = false) {
7
- const commandString = `npm ${UPGRADE_COMMAND.join(' ')}`;
8
- if (dryRun) {
9
- console.log(commandString);
10
- return;
5
+ const commandContext_1 = require("../commandContext");
6
+ const config_1 = require("../config");
7
+ const worker_1 = require("./worker");
8
+ const WORKER_UPDATE_POLL_DEFAULT_MS = 3000;
9
+ const WORKER_UPDATE_TIMEOUT_DEFAULT_MS = 15 * 60000;
10
+ function readPositiveIntegerEnv(name, fallback) {
11
+ const raw = process.env[name]?.trim() || '';
12
+ const value = Number(raw);
13
+ return Number.isInteger(value) && value > 0 ? value : fallback;
14
+ }
15
+ function sleep(ms) {
16
+ return new Promise((resolve) => {
17
+ setTimeout(resolve, ms);
18
+ });
19
+ }
20
+ function validateTargetVersion(value) {
21
+ const version = value?.trim() || process.env.PLAYDROP_CLI_TARGET_VERSION?.trim() || '';
22
+ if (!/^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?$/.test(version)) {
23
+ throw new Error('playdrop_update_target_version_required: pass --target-version <version> or set PLAYDROP_CLI_TARGET_VERSION. Managed workers should use playdrop update --worker.');
11
24
  }
25
+ return version;
26
+ }
27
+ function runCommand(command, args) {
28
+ const commandString = `${command} ${args.join(' ')}`;
12
29
  console.log('Running:', commandString);
13
- await new Promise((resolve, reject) => {
14
- const child = (0, node_child_process_1.spawn)('npm', UPGRADE_COMMAND, {
30
+ return new Promise((resolve, reject) => {
31
+ const child = (0, node_child_process_1.spawn)(command, args, {
15
32
  stdio: 'inherit',
16
33
  shell: process.platform === 'win32'
17
34
  });
@@ -20,9 +37,82 @@ async function upgrade(dryRun = false) {
20
37
  resolve();
21
38
  }
22
39
  else {
23
- reject(new Error(`npm exited with code ${code}`));
40
+ reject(new Error(`${command} exited with code ${code}`));
24
41
  }
25
42
  });
26
43
  child.on('error', (error) => reject(error));
27
44
  });
28
45
  }
46
+ function formatWorkerUpdateState(worker) {
47
+ return [
48
+ `lifecycle=${worker.lifecycleState ?? 'unknown'}`,
49
+ `update=${worker.updateState ?? 'unknown'}`,
50
+ `ready=${worker.ready === true ? 'true' : worker.ready === false ? 'false' : 'unknown'}`,
51
+ `cli=${worker.cliVersion ?? 'unknown'}`,
52
+ `plugin=${worker.pluginVersion ?? 'unknown'}`,
53
+ ].join(' ');
54
+ }
55
+ async function observeManagedWorkerUpdate(input) {
56
+ const pollMs = readPositiveIntegerEnv('PLAYDROP_WORKER_UPDATE_POLL_MS', WORKER_UPDATE_POLL_DEFAULT_MS);
57
+ const timeoutMs = readPositiveIntegerEnv('PLAYDROP_WORKER_UPDATE_TIMEOUT_MS', WORKER_UPDATE_TIMEOUT_DEFAULT_MS);
58
+ const deadline = Date.now() + timeoutMs;
59
+ let lastState = '';
60
+ while (Date.now() <= deadline) {
61
+ const workers = await input.client.listMyAgentWorkers();
62
+ const worker = workers.workers.find((candidate) => candidate.workerKey === input.workerKey);
63
+ if (!worker) {
64
+ throw new Error(`playdrop_update_worker_missing: worker ${input.workerKey} is no longer registered. Run "playdrop worker status --json" on the worker host.`);
65
+ }
66
+ const state = formatWorkerUpdateState(worker);
67
+ if (state !== lastState) {
68
+ console.log(`Worker update progress: ${state}`);
69
+ lastState = state;
70
+ }
71
+ if (worker.updateState === 'UPDATE_BLOCKED' || worker.lifecycleState === 'DEGRADED' || worker.ready === false) {
72
+ throw new Error(`playdrop_update_worker_failed: ${state}. Next action: run "playdrop worker status --json" on the worker host and inspect the wrapper failure marker under ~/.playdrop/worker.`);
73
+ }
74
+ if (worker.activeUpdateIntentId !== input.intentId
75
+ && worker.lifecycleState === 'READY'
76
+ && worker.updateState === 'CURRENT'
77
+ && worker.ready === true) {
78
+ console.log('Managed worker update completed.');
79
+ return;
80
+ }
81
+ await sleep(pollMs);
82
+ }
83
+ throw new Error(`playdrop_update_worker_timeout: worker ${input.workerKey} did not complete update intent ${input.intentId} within ${timeoutMs}ms. Next action: check Slack worker alerts, launchctl status, and the wrapper failure marker on the worker host.`);
84
+ }
85
+ async function upgrade(options = {}) {
86
+ if (options.worker) {
87
+ const ctx = await (0, commandContext_1.resolveAuthenticatedEnvironmentContext)('update', 'Requesting a managed worker update', { env: options.env });
88
+ if (!ctx) {
89
+ return;
90
+ }
91
+ const workerKey = options.workerKey?.trim() || (0, config_1.getOrCreateWorkerKey)();
92
+ const intent = await ctx.client.workerCreateUpdateIntent({
93
+ workerKey,
94
+ environment: ctx.env,
95
+ reason: 'manual_update',
96
+ });
97
+ console.log(`Managed worker update intent ${intent.intent.id} created for worker ${workerKey}.`);
98
+ console.log(`Worker state: ${intent.worker.lifecycleState ?? 'unknown'} / ${intent.worker.updateState ?? 'unknown'}`);
99
+ await observeManagedWorkerUpdate({
100
+ client: ctx.client,
101
+ workerKey,
102
+ intentId: intent.intent.id,
103
+ });
104
+ return;
105
+ }
106
+ const activePersonalWorker = (0, worker_1.readActivePersonalWorkerRuntimeState)();
107
+ if (activePersonalWorker) {
108
+ throw new Error(`playdrop_update_active_personal_worker: stop the My Agent worker first, then rerun playdrop update. pid=${activePersonalWorker.pid} worker=${activePersonalWorker.workerName}`);
109
+ }
110
+ const targetVersion = validateTargetVersion(options.targetVersion);
111
+ const upgradeCommand = ['install', '-g', '--no-audit', '--no-fund', `@playdrop/playdrop-cli@${targetVersion}`];
112
+ const commandString = `npm ${upgradeCommand.join(' ')}`;
113
+ if (options.dryRun) {
114
+ console.log(commandString);
115
+ return;
116
+ }
117
+ await runCommand('npm', upgradeCommand);
118
+ }
@@ -10,6 +10,47 @@ type WorkerStartOptions = {
10
10
  env?: string;
11
11
  once?: boolean;
12
12
  name?: string;
13
+ superviseStdin?: boolean;
14
+ };
15
+ type WorkerStatusOptions = {
16
+ env?: string;
17
+ json?: boolean;
18
+ };
19
+ type WorkerSetupOptions = {
20
+ env?: string;
21
+ name?: string;
22
+ start?: boolean;
23
+ restart?: boolean;
24
+ };
25
+ type WorkerLocalStatus = {
26
+ ready: boolean;
27
+ degradedReasons: string[];
28
+ cliVersion: string;
29
+ nodeVersion: string;
30
+ npmVersion: string | null;
31
+ playwright: {
32
+ version?: string;
33
+ chromiumInstalled?: boolean;
34
+ } | null;
35
+ plugin: {
36
+ ready: boolean;
37
+ root: string | null;
38
+ version: string | null;
39
+ error: string | null;
40
+ };
41
+ agents: AgentWorkerCapabilities['agents'];
42
+ capabilities: AgentWorkerCapabilities | null;
43
+ };
44
+ type WorkerStatusPayload = {
45
+ schemaVersion: 1;
46
+ generatedAt: string;
47
+ local: WorkerLocalStatus;
48
+ server: {
49
+ reachable: boolean;
50
+ authenticated: boolean;
51
+ worker: import('@playdrop/types').AgentWorkerResponse | null;
52
+ error?: string;
53
+ };
13
54
  };
14
55
  type TaskReportOptions = {
15
56
  env?: string;
@@ -111,6 +152,8 @@ export declare function buildWorkerCapabilities(input: string | {
111
152
  codexAuthenticated?: boolean | null;
112
153
  claudeVersion?: string | null;
113
154
  claudeAuthenticated?: boolean | null;
155
+ cursorVersion?: string | null;
156
+ cursorAuthenticated?: boolean | null;
114
157
  npmVersion?: string | null;
115
158
  playwright?: {
116
159
  version?: string;
@@ -150,6 +193,27 @@ export declare function createLocalPlaydropShim(input: {
150
193
  attempt: number;
151
194
  devPort: number;
152
195
  }): Promise<string>;
196
+ type WorkerRuntimeState = {
197
+ schemaVersion: 1;
198
+ pid: number;
199
+ env: string;
200
+ workerKey: string;
201
+ workerName: string;
202
+ target: AgentExecutionTarget;
203
+ startedAt: string;
204
+ };
205
+ export declare function readActivePersonalWorkerRuntimeState(): WorkerRuntimeState | null;
206
+ export declare function parseLaunchAgentProgramArguments(plist: string): string[];
207
+ export declare function assertLaunchAgentPlistCompatible(input: {
208
+ plistPath: string;
209
+ plist: string;
210
+ env: string;
211
+ workerName: string;
212
+ wrapperPath: string;
213
+ canonicalPlistPath: string;
214
+ }): void;
215
+ export declare function showWorkerStatus(options?: WorkerStatusOptions): Promise<WorkerStatusPayload>;
216
+ export declare function setupWorker(options?: WorkerSetupOptions): Promise<void>;
153
217
  export declare function startWorker(options?: WorkerStartOptions): Promise<void>;
154
218
  export declare function reportTask(options: TaskReportOptions): Promise<void>;
155
219
  export declare function reportCatalogueTask(options: TaskCatalogueReportOptions): Promise<void>;