@playdrop/playdrop-cli 0.12.2 → 0.12.4
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 +1 -1
- package/dist/appUrls.d.ts +9 -0
- package/dist/appUrls.js +29 -0
- package/dist/apps/index.d.ts +2 -0
- package/dist/apps/index.js +2 -0
- package/dist/apps/loadCheck.d.ts +4 -0
- package/dist/apps/loadCheck.js +48 -13
- package/dist/apps/upload.d.ts +2 -0
- package/dist/apps/upload.js +1 -0
- package/dist/clientInfo.js +0 -11
- package/dist/commands/captureListing.d.ts +3 -1
- package/dist/commands/captureListing.js +24 -8
- package/dist/commands/check.js +40 -26
- package/dist/commands/create.js +47 -2
- package/dist/commands/devShared.d.ts +5 -0
- package/dist/commands/devShared.js +9 -0
- package/dist/commands/login.d.ts +13 -1
- package/dist/commands/login.js +72 -5
- package/dist/commands/taskCaptureSession.d.ts +4 -0
- package/dist/commands/taskCaptureSession.js +21 -0
- package/dist/commands/upload.d.ts +1 -0
- package/dist/commands/upload.js +16 -1
- package/dist/commands/worker.d.ts +5 -1
- package/dist/commands/worker.js +187 -119
- package/dist/index.js +2 -0
- package/node_modules/@playdrop/config/client-meta.json +1 -1
- package/node_modules/@playdrop/types/dist/api.d.ts +9 -10
- package/node_modules/@playdrop/types/dist/api.d.ts.map +1 -1
- package/node_modules/@playdrop/types/dist/api.js +3 -60
- package/package.json +1 -1
package/dist/commands/worker.js
CHANGED
|
@@ -39,6 +39,8 @@ exports.assertWorkerProjectVersionBumped = assertWorkerProjectVersionBumped;
|
|
|
39
39
|
exports.buildAgentFailureCode = buildAgentFailureCode;
|
|
40
40
|
exports.describeAgentFailureForEvent = describeAgentFailureForEvent;
|
|
41
41
|
exports.createLocalPlaydropShim = createLocalPlaydropShim;
|
|
42
|
+
exports.parseCodexModelCatalog = parseCodexModelCatalog;
|
|
43
|
+
exports.parseClaudeModelCatalog = parseClaudeModelCatalog;
|
|
42
44
|
exports.buildWorkerSetupActions = buildWorkerSetupActions;
|
|
43
45
|
exports.readActivePersonalWorkerRuntimeState = readActivePersonalWorkerRuntimeState;
|
|
44
46
|
exports.parseLaunchAgentProgramArguments = parseLaunchAgentProgramArguments;
|
|
@@ -99,6 +101,7 @@ Object.defineProperty(exports, "readEnvBoolean", { enumerable: true, get: functi
|
|
|
99
101
|
Object.defineProperty(exports, "runLoggedProcess", { enumerable: true, get: function () { return runtime_2.runLoggedProcess; } });
|
|
100
102
|
const DEFAULT_POLL_INTERVAL_MS = 1000;
|
|
101
103
|
const HEARTBEAT_INTERVAL_MS = 10000;
|
|
104
|
+
const WORKER_CAPABILITY_REFRESH_INTERVAL_MS = 10 * 60000;
|
|
102
105
|
const INSTRUMENT_HEARTBEAT_INTERVAL_MS = 1000;
|
|
103
106
|
const TASK_HEARTBEAT_TRANSIENT_FAILURE_LIMIT = 6;
|
|
104
107
|
const DEFAULT_WORKER_MAX_PARALLEL_TASKS = 5;
|
|
@@ -973,12 +976,24 @@ function resolvePlaydropPluginRoot(input = {}) {
|
|
|
973
976
|
...candidateVersionDirectories(node_path_1.default.join(homeDir, '.codex', 'plugins', 'cache', 'playdrop', 'playdrop')),
|
|
974
977
|
...candidateVersionDirectories(node_path_1.default.join(homeDir, '.codex', 'plugins', 'cache', 'olivier-local-plugins', 'playdrop')),
|
|
975
978
|
];
|
|
979
|
+
let firstCandidateError = null;
|
|
976
980
|
for (const candidate of candidates) {
|
|
977
981
|
if (!looksLikePlaydropPluginRoot(candidate)) {
|
|
978
982
|
continue;
|
|
979
983
|
}
|
|
980
|
-
|
|
981
|
-
|
|
984
|
+
try {
|
|
985
|
+
readPlaydropPluginStagingManifest(candidate);
|
|
986
|
+
return candidate;
|
|
987
|
+
}
|
|
988
|
+
catch (error) {
|
|
989
|
+
firstCandidateError ?? (firstCandidateError = error);
|
|
990
|
+
continue;
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
if (firstCandidateError) {
|
|
994
|
+
throw firstCandidateError instanceof Error
|
|
995
|
+
? firstCandidateError
|
|
996
|
+
: new Error(String(firstCandidateError));
|
|
982
997
|
}
|
|
983
998
|
throw new Error(`playdrop_plugin_staging_manifest_missing: install or update the PlayDrop plugin so ${PLAYDROP_PLUGIN_STAGING_MANIFEST_PATH} is available.`);
|
|
984
999
|
}
|
|
@@ -1320,29 +1335,8 @@ function probePlaywrightChromium() {
|
|
|
1320
1335
|
}
|
|
1321
1336
|
return { version, chromiumInstalled: true, executablePath };
|
|
1322
1337
|
}
|
|
1323
|
-
function
|
|
1324
|
-
|
|
1325
|
-
if (typeof raw !== 'string' || raw.trim().length === 0) {
|
|
1326
|
-
return [...types_1.AGENT_TASK_MODEL_VALUES_BY_AGENT[agent]];
|
|
1327
|
-
}
|
|
1328
|
-
const values = raw
|
|
1329
|
-
.split(',')
|
|
1330
|
-
.map((entry) => entry.trim())
|
|
1331
|
-
.filter(Boolean)
|
|
1332
|
-
.map((entry) => (0, types_1.normalizeAgentTaskModel)(agent, entry));
|
|
1333
|
-
const unsupported = raw
|
|
1334
|
-
.split(',')
|
|
1335
|
-
.map((entry) => entry.trim())
|
|
1336
|
-
.filter(Boolean)
|
|
1337
|
-
.filter((entry) => !(0, types_1.normalizeAgentTaskModel)(agent, entry));
|
|
1338
|
-
if (unsupported.length > 0) {
|
|
1339
|
-
throw new Error(`worker_preflight_unsupported_model_list:${envName}:${unsupported.join(',')}`);
|
|
1340
|
-
}
|
|
1341
|
-
const unique = Array.from(new Set(values));
|
|
1342
|
-
if (unique.length === 0 || unique.some((model) => !model || model.length > 120)) {
|
|
1343
|
-
throw new Error(`worker_preflight_invalid_model_list:${envName}`);
|
|
1344
|
-
}
|
|
1345
|
-
return unique;
|
|
1338
|
+
function normalizeDiscoveredModels(agent, models) {
|
|
1339
|
+
return Array.from(new Set(models.map((model) => (0, types_1.normalizeAgentTaskModel)(agent, model)).filter(Boolean)));
|
|
1346
1340
|
}
|
|
1347
1341
|
function parseEnvLine(line) {
|
|
1348
1342
|
const trimmed = line.trim();
|
|
@@ -1388,45 +1382,51 @@ function loadWorkerEnvFile(envName, cwd = node_process_1.default.cwd()) {
|
|
|
1388
1382
|
return envPath;
|
|
1389
1383
|
}
|
|
1390
1384
|
function buildWorkerCapabilities(input) {
|
|
1391
|
-
const codexVersion =
|
|
1392
|
-
const codexAuthenticated =
|
|
1393
|
-
const
|
|
1394
|
-
const
|
|
1395
|
-
const
|
|
1396
|
-
const
|
|
1397
|
-
const
|
|
1398
|
-
const
|
|
1385
|
+
const codexVersion = input.codexVersion?.trim() || null;
|
|
1386
|
+
const codexAuthenticated = input.codexAuthenticated === true;
|
|
1387
|
+
const codexModels = normalizeDiscoveredModels('CODEX', input.codexModels ?? []);
|
|
1388
|
+
const claudeVersion = input.claudeVersion?.trim() || null;
|
|
1389
|
+
const claudeAuthenticated = input.claudeAuthenticated === true;
|
|
1390
|
+
const claudeModels = normalizeDiscoveredModels('CLAUDE_CODE', input.claudeModels ?? []);
|
|
1391
|
+
const cursorVersion = input.cursorVersion?.trim() || null;
|
|
1392
|
+
const cursorAuthenticated = input.cursorAuthenticated === true;
|
|
1393
|
+
const npmVersion = input.npmVersion?.trim() || null;
|
|
1394
|
+
const rawPlaywright = input.playwright ?? null;
|
|
1399
1395
|
const playwright = rawPlaywright
|
|
1400
1396
|
? { version: rawPlaywright.version, chromiumInstalled: rawPlaywright.chromiumInstalled }
|
|
1401
1397
|
: null;
|
|
1402
|
-
const maxParallelTasks =
|
|
1403
|
-
|
|
1404
|
-
: input.maxParallelTasks ?? DEFAULT_WORKER_MAX_PARALLEL_TASKS;
|
|
1405
|
-
const runningTaskCount = typeof input === 'string' ? 0 : input.runningTaskCount ?? 0;
|
|
1398
|
+
const maxParallelTasks = input.maxParallelTasks ?? DEFAULT_WORKER_MAX_PARALLEL_TASKS;
|
|
1399
|
+
const runningTaskCount = input.runningTaskCount ?? 0;
|
|
1406
1400
|
const degradedReasons = [];
|
|
1407
1401
|
const agents = [];
|
|
1408
1402
|
if (codexVersion) {
|
|
1409
1403
|
if (!codexAuthenticated) {
|
|
1410
1404
|
degradedReasons.push('codex_not_authenticated');
|
|
1411
1405
|
}
|
|
1406
|
+
if (codexModels.length === 0) {
|
|
1407
|
+
degradedReasons.push('codex_models_unavailable');
|
|
1408
|
+
}
|
|
1412
1409
|
agents.push({
|
|
1413
1410
|
agent: 'CODEX',
|
|
1414
1411
|
cliVersion: codexVersion,
|
|
1415
1412
|
authenticated: codexAuthenticated,
|
|
1416
|
-
models:
|
|
1417
|
-
ready: codexAuthenticated,
|
|
1413
|
+
models: codexModels,
|
|
1414
|
+
ready: codexAuthenticated && codexModels.length > 0,
|
|
1418
1415
|
});
|
|
1419
1416
|
}
|
|
1420
1417
|
if (claudeVersion) {
|
|
1421
1418
|
if (!claudeAuthenticated) {
|
|
1422
1419
|
degradedReasons.push('claude_not_authenticated');
|
|
1423
1420
|
}
|
|
1421
|
+
if (claudeModels.length === 0) {
|
|
1422
|
+
degradedReasons.push('claude_models_unavailable');
|
|
1423
|
+
}
|
|
1424
1424
|
agents.push({
|
|
1425
1425
|
agent: 'CLAUDE_CODE',
|
|
1426
1426
|
cliVersion: claudeVersion,
|
|
1427
1427
|
authenticated: claudeAuthenticated,
|
|
1428
|
-
models:
|
|
1429
|
-
ready: claudeAuthenticated,
|
|
1428
|
+
models: claudeModels,
|
|
1429
|
+
ready: claudeAuthenticated && claudeModels.length > 0,
|
|
1430
1430
|
});
|
|
1431
1431
|
}
|
|
1432
1432
|
if (cursorVersion) {
|
|
@@ -1761,7 +1761,7 @@ function resolveCodexModel(model) {
|
|
|
1761
1761
|
if (!normalized) {
|
|
1762
1762
|
throw new Error('agent_task_assignment_model_missing');
|
|
1763
1763
|
}
|
|
1764
|
-
const effortMatch = normalized.match(/^(
|
|
1764
|
+
const effortMatch = normalized.match(/^(.*?)-(extra-high|low|medium|high|xhigh|max)$/);
|
|
1765
1765
|
if (effortMatch?.[1] && effortMatch[2]) {
|
|
1766
1766
|
const effort = effortMatch[2] === 'extra-high' ? 'xhigh' : effortMatch[2];
|
|
1767
1767
|
return { model: effortMatch[1], reasoningEffort: effort };
|
|
@@ -2105,6 +2105,61 @@ function probeCodexInstallation() {
|
|
|
2105
2105
|
}
|
|
2106
2106
|
return { codexVersion: match[1] };
|
|
2107
2107
|
}
|
|
2108
|
+
function parseCodexModelCatalog(output) {
|
|
2109
|
+
const jsonStart = output.indexOf('{');
|
|
2110
|
+
const jsonEnd = output.lastIndexOf('}');
|
|
2111
|
+
if (jsonStart < 0 || jsonEnd <= jsonStart) {
|
|
2112
|
+
throw new Error('worker_preflight_codex_model_catalog_invalid');
|
|
2113
|
+
}
|
|
2114
|
+
let parsed;
|
|
2115
|
+
try {
|
|
2116
|
+
parsed = JSON.parse(output.slice(jsonStart, jsonEnd + 1));
|
|
2117
|
+
}
|
|
2118
|
+
catch {
|
|
2119
|
+
throw new Error('worker_preflight_codex_model_catalog_invalid');
|
|
2120
|
+
}
|
|
2121
|
+
const models = typeof parsed === 'object' && parsed !== null && Array.isArray(parsed.models)
|
|
2122
|
+
? parsed.models
|
|
2123
|
+
: null;
|
|
2124
|
+
if (!models) {
|
|
2125
|
+
throw new Error('worker_preflight_codex_model_catalog_invalid');
|
|
2126
|
+
}
|
|
2127
|
+
const discovered = [];
|
|
2128
|
+
for (const value of models) {
|
|
2129
|
+
if (typeof value !== 'object' || value === null) {
|
|
2130
|
+
continue;
|
|
2131
|
+
}
|
|
2132
|
+
const model = value;
|
|
2133
|
+
const slug = typeof model.slug === 'string' ? model.slug.trim() : '';
|
|
2134
|
+
if (!slug || model.visibility !== 'list') {
|
|
2135
|
+
continue;
|
|
2136
|
+
}
|
|
2137
|
+
const levels = Array.isArray(model.supported_reasoning_levels)
|
|
2138
|
+
? model.supported_reasoning_levels
|
|
2139
|
+
.map((entry) => typeof entry === 'object' && entry !== null ? entry.effort : null)
|
|
2140
|
+
.filter((effort) => typeof effort === 'string' && Boolean(effort.trim()))
|
|
2141
|
+
: [];
|
|
2142
|
+
if (levels.length === 0) {
|
|
2143
|
+
discovered.push(slug);
|
|
2144
|
+
continue;
|
|
2145
|
+
}
|
|
2146
|
+
for (const effort of levels) {
|
|
2147
|
+
discovered.push(`${slug}-${effort.trim()}`);
|
|
2148
|
+
}
|
|
2149
|
+
}
|
|
2150
|
+
const normalized = normalizeDiscoveredModels('CODEX', discovered);
|
|
2151
|
+
if (normalized.length === 0) {
|
|
2152
|
+
throw new Error('worker_preflight_codex_model_catalog_empty');
|
|
2153
|
+
}
|
|
2154
|
+
return normalized;
|
|
2155
|
+
}
|
|
2156
|
+
function probeCodexModels() {
|
|
2157
|
+
const result = (0, shellProbe_1.runShell)('codex debug models');
|
|
2158
|
+
if (result.exitCode !== 0) {
|
|
2159
|
+
throw new Error(`worker_preflight_codex_model_catalog_failed: "codex debug models" exited with code ${result.exitCode}. Output: ${result.output.slice(0, 200)}`);
|
|
2160
|
+
}
|
|
2161
|
+
return parseCodexModelCatalog(result.output);
|
|
2162
|
+
}
|
|
2108
2163
|
function probeClaudeInstallation() {
|
|
2109
2164
|
const probe = (0, shellProbe_1.runShell)((0, shellProbe_1.buildCommandPathProbe)('claude'));
|
|
2110
2165
|
if (probe.exitCode !== 0 || !probe.output.trim()) {
|
|
@@ -2123,6 +2178,71 @@ function probeClaudeInstallation() {
|
|
|
2123
2178
|
}
|
|
2124
2179
|
return { claudeVersion: match[1] };
|
|
2125
2180
|
}
|
|
2181
|
+
function parseClaudeModelCatalog(output) {
|
|
2182
|
+
let parsed;
|
|
2183
|
+
try {
|
|
2184
|
+
parsed = JSON.parse(output);
|
|
2185
|
+
}
|
|
2186
|
+
catch {
|
|
2187
|
+
throw new Error('worker_preflight_claude_model_catalog_invalid');
|
|
2188
|
+
}
|
|
2189
|
+
const result = typeof parsed === 'object' && parsed !== null && typeof parsed.result === 'string'
|
|
2190
|
+
? parsed.result
|
|
2191
|
+
: '';
|
|
2192
|
+
const available = /Available:\s*([^\n]+)/.exec(result)?.[1]?.trim() ?? '';
|
|
2193
|
+
if (!available) {
|
|
2194
|
+
throw new Error('worker_preflight_claude_model_catalog_invalid');
|
|
2195
|
+
}
|
|
2196
|
+
const discovered = available
|
|
2197
|
+
.replace(/\.$/, '')
|
|
2198
|
+
.split(/,|\bor\b/)
|
|
2199
|
+
.map((entry) => entry.trim())
|
|
2200
|
+
.filter((entry) => entry && entry !== 'a full model ID');
|
|
2201
|
+
const normalized = normalizeDiscoveredModels('CLAUDE_CODE', discovered);
|
|
2202
|
+
if (normalized.length === 0) {
|
|
2203
|
+
throw new Error('worker_preflight_claude_model_catalog_empty');
|
|
2204
|
+
}
|
|
2205
|
+
return normalized;
|
|
2206
|
+
}
|
|
2207
|
+
function probeClaudeModels() {
|
|
2208
|
+
const result = (0, shellProbe_1.runShell)('claude --print --output-format json --max-turns 1 "/model"');
|
|
2209
|
+
if (result.exitCode !== 0) {
|
|
2210
|
+
throw new Error(`worker_preflight_claude_model_catalog_failed: "claude /model" exited with code ${result.exitCode}. Output: ${result.output.slice(0, 200)}`);
|
|
2211
|
+
}
|
|
2212
|
+
return parseClaudeModelCatalog(result.output);
|
|
2213
|
+
}
|
|
2214
|
+
function probeReadyWorkerCapabilities(input) {
|
|
2215
|
+
const codexVersion = probeCodexInstallation()?.codexVersion ?? null;
|
|
2216
|
+
const claudeVersion = probeClaudeInstallation()?.claudeVersion ?? null;
|
|
2217
|
+
const cursorVersion = probeCursorInstallation()?.cursorVersion ?? null;
|
|
2218
|
+
const capabilities = buildWorkerCapabilities({
|
|
2219
|
+
codexVersion,
|
|
2220
|
+
codexAuthenticated: codexVersion ? readCodexAuthenticated() : false,
|
|
2221
|
+
codexModels: codexVersion ? probeCodexModels() : [],
|
|
2222
|
+
claudeVersion,
|
|
2223
|
+
claudeAuthenticated: claudeVersion ? readClaudeAuthenticated() : false,
|
|
2224
|
+
claudeModels: claudeVersion ? probeClaudeModels() : [],
|
|
2225
|
+
cursorVersion,
|
|
2226
|
+
cursorAuthenticated: cursorVersion ? readCursorAuthenticated() : false,
|
|
2227
|
+
npmVersion: input.npmVersion,
|
|
2228
|
+
playwright: input.playwright,
|
|
2229
|
+
maxParallelTasks: input.maxParallelTasks,
|
|
2230
|
+
runningTaskCount: 0,
|
|
2231
|
+
});
|
|
2232
|
+
if (input.pluginVersion) {
|
|
2233
|
+
capabilities.pluginVersion = input.pluginVersion;
|
|
2234
|
+
for (const agent of capabilities.agents) {
|
|
2235
|
+
agent.pluginVersion = input.pluginVersion;
|
|
2236
|
+
}
|
|
2237
|
+
}
|
|
2238
|
+
if (!capabilities.ready) {
|
|
2239
|
+
const reasons = Array.isArray(capabilities.degradedReasons) && capabilities.degradedReasons.length > 0
|
|
2240
|
+
? capabilities.degradedReasons.join(', ')
|
|
2241
|
+
: 'no ready agent';
|
|
2242
|
+
throw new Error(`worker_preflight_failed: ${reasons}`);
|
|
2243
|
+
}
|
|
2244
|
+
return capabilities;
|
|
2245
|
+
}
|
|
2126
2246
|
function probeCursorInstallation() {
|
|
2127
2247
|
if (!(0, runtime_1.readEnvBoolean)('PLAYDROP_WORKER_ENABLE_CURSOR', false)) {
|
|
2128
2248
|
return null;
|
|
@@ -2190,7 +2310,9 @@ function readWorkerTargetUpdateFailure() {
|
|
|
2190
2310
|
function collectWorkerLocalStatus() {
|
|
2191
2311
|
const degradedReasons = [];
|
|
2192
2312
|
let codexVersion = null;
|
|
2313
|
+
let codexModels = [];
|
|
2193
2314
|
let claudeVersion = null;
|
|
2315
|
+
let claudeModels = [];
|
|
2194
2316
|
let cursorVersion = null;
|
|
2195
2317
|
let npmVersion = null;
|
|
2196
2318
|
let playwright = null;
|
|
@@ -2200,12 +2322,14 @@ function collectWorkerLocalStatus() {
|
|
|
2200
2322
|
let targetUpdateFailure = null;
|
|
2201
2323
|
try {
|
|
2202
2324
|
codexVersion = probeCodexInstallation()?.codexVersion ?? null;
|
|
2325
|
+
codexModels = codexVersion ? probeCodexModels() : [];
|
|
2203
2326
|
}
|
|
2204
2327
|
catch (error) {
|
|
2205
2328
|
degradedReasons.push(errorCode(error));
|
|
2206
2329
|
}
|
|
2207
2330
|
try {
|
|
2208
2331
|
claudeVersion = probeClaudeInstallation()?.claudeVersion ?? null;
|
|
2332
|
+
claudeModels = claudeVersion ? probeClaudeModels() : [];
|
|
2209
2333
|
}
|
|
2210
2334
|
catch (error) {
|
|
2211
2335
|
degradedReasons.push(errorCode(error));
|
|
@@ -2250,8 +2374,10 @@ function collectWorkerLocalStatus() {
|
|
|
2250
2374
|
capabilities = buildWorkerCapabilities({
|
|
2251
2375
|
codexVersion,
|
|
2252
2376
|
codexAuthenticated: codexVersion ? readCodexAuthenticated() : false,
|
|
2377
|
+
codexModels,
|
|
2253
2378
|
claudeVersion,
|
|
2254
2379
|
claudeAuthenticated: claudeVersion ? readClaudeAuthenticated() : false,
|
|
2380
|
+
claudeModels,
|
|
2255
2381
|
cursorVersion,
|
|
2256
2382
|
cursorAuthenticated: cursorVersion ? readCursorAuthenticated() : false,
|
|
2257
2383
|
npmVersion,
|
|
@@ -2404,7 +2530,6 @@ function writeManagedWorkerUpdatePolicyFile(input) {
|
|
|
2404
2530
|
minimumCliVersion: input.updatePolicy.minimumCliVersion,
|
|
2405
2531
|
targetPluginVersion: input.updatePolicy.targetPluginVersion,
|
|
2406
2532
|
minimumPluginVersion: input.updatePolicy.minimumPluginVersion,
|
|
2407
|
-
managedAgentCliVersions: input.updatePolicy.managedAgentCliVersions ?? {},
|
|
2408
2533
|
requiredWrapperContractVersion: input.updatePolicy.requiredWrapperContractVersion,
|
|
2409
2534
|
}, null, 2));
|
|
2410
2535
|
}
|
|
@@ -2557,6 +2682,7 @@ async function writeManagedWorkerWrapper(input) {
|
|
|
2557
2682
|
const script = `#!/bin/sh
|
|
2558
2683
|
set -eu
|
|
2559
2684
|
|
|
2685
|
+
export PATH="${node_path_1.default.join(node_os_1.default.homedir(), '.playdrop', 'worker', 'bin')}:${node_path_1.default.join(node_os_1.default.homedir(), '.local', 'bin')}:/usr/local/bin:/opt/homebrew/bin:/usr/bin:/bin:/usr/sbin:/sbin"
|
|
2560
2686
|
export PLAYDROP_WORKER_WRAPPER_CONTRACT_VERSION="${WORKER_WRAPPER_CONTRACT_VERSION}"
|
|
2561
2687
|
POLICY_FILE="${policyFile}"
|
|
2562
2688
|
FAILURE_FILE="${failureFile}"
|
|
@@ -2760,55 +2886,7 @@ if [ "$TARGET_UPDATE_FAILED" -eq 0 ]; then
|
|
|
2760
2886
|
rm -f "$FAILURE_FILE"
|
|
2761
2887
|
fi
|
|
2762
2888
|
|
|
2763
|
-
|
|
2764
|
-
const childProcess = require("child_process");
|
|
2765
|
-
const fs = require("fs");
|
|
2766
|
-
|
|
2767
|
-
const policyFile = process.argv[2];
|
|
2768
|
-
if (!policyFile || !fs.existsSync(policyFile)) {
|
|
2769
|
-
process.exit(0);
|
|
2770
|
-
}
|
|
2771
|
-
const policy = JSON.parse(fs.readFileSync(policyFile, "utf8"));
|
|
2772
|
-
const versions = policy && policy.managedAgentCliVersions && typeof policy.managedAgentCliVersions === "object"
|
|
2773
|
-
? policy.managedAgentCliVersions
|
|
2774
|
-
: {};
|
|
2775
|
-
const packages = {
|
|
2776
|
-
CODEX: "@openai/codex",
|
|
2777
|
-
CLAUDE_CODE: "@anthropic-ai/claude-code",
|
|
2778
|
-
};
|
|
2779
|
-
const aliases = {
|
|
2780
|
-
CODEX: "CODEX",
|
|
2781
|
-
OPENAI_CODEX: "CODEX",
|
|
2782
|
-
CLAUDE: "CLAUDE_CODE",
|
|
2783
|
-
CLAUDE_CODE: "CLAUDE_CODE",
|
|
2784
|
-
CURSOR: "CURSOR_COMPOSER",
|
|
2785
|
-
CURSOR_COMPOSER: "CURSOR_COMPOSER",
|
|
2786
|
-
};
|
|
2787
|
-
for (const [rawKey, rawVersion] of Object.entries(versions)) {
|
|
2788
|
-
const version = typeof rawVersion === "string" ? rawVersion.trim() : "";
|
|
2789
|
-
if (!/^\\d+\\.\\d+\\.\\d+(?:[-+][0-9A-Za-z.-]+)?$/.test(version)) {
|
|
2790
|
-
throw new Error(\`worker_update_agent_cli_version_invalid:\${rawKey}\`);
|
|
2791
|
-
}
|
|
2792
|
-
const normalizedKey = aliases[String(rawKey).trim().toUpperCase().replace(/[-\\s]+/g, "_")];
|
|
2793
|
-
if (normalizedKey === "CURSOR_COMPOSER") {
|
|
2794
|
-
throw new Error("worker_update_cursor_cli_auto_update_unsupported");
|
|
2795
|
-
}
|
|
2796
|
-
const packageName = normalizedKey ? packages[normalizedKey] : null;
|
|
2797
|
-
if (!packageName) {
|
|
2798
|
-
throw new Error(\`worker_update_agent_cli_unknown:\${rawKey}\`);
|
|
2799
|
-
}
|
|
2800
|
-
const result = childProcess.spawnSync(
|
|
2801
|
-
"npm",
|
|
2802
|
-
["install", "-g", "--no-audit", "--no-fund", \`\${packageName}@\${version}\`],
|
|
2803
|
-
{ stdio: "inherit" },
|
|
2804
|
-
);
|
|
2805
|
-
if (result.status !== 0) {
|
|
2806
|
-
throw new Error(\`worker_update_agent_cli_install_failed:\${normalizedKey}\`);
|
|
2807
|
-
}
|
|
2808
|
-
}
|
|
2809
|
-
NODE
|
|
2810
|
-
|
|
2811
|
-
exec playdrop worker start --env ${shellQuote(input.env)} --name ${shellQuote(input.workerName)}
|
|
2889
|
+
exec /usr/bin/caffeinate -dimsu playdrop worker start --env ${shellQuote(input.env)} --name ${shellQuote(input.workerName)}
|
|
2812
2890
|
`;
|
|
2813
2891
|
await (0, promises_1.writeFile)(wrapperPath, script, 'utf8');
|
|
2814
2892
|
await (0, promises_1.chmod)(wrapperPath, 0o755);
|
|
@@ -2864,8 +2942,9 @@ function launchManagedWorker(label, plistPath) {
|
|
|
2864
2942
|
throw new Error('worker_setup_launchagent_uid_unavailable');
|
|
2865
2943
|
}
|
|
2866
2944
|
const domain = `gui/${uid}`;
|
|
2945
|
+
(0, shellProbe_1.runShell)(`launchctl bootout ${shellQuote(`${domain}/${label}`)}`);
|
|
2867
2946
|
const bootstrap = (0, shellProbe_1.runShell)(`launchctl bootstrap ${shellQuote(domain)} ${shellQuote(plistPath)}`);
|
|
2868
|
-
if (bootstrap.exitCode !== 0
|
|
2947
|
+
if (bootstrap.exitCode !== 0) {
|
|
2869
2948
|
throw new Error(`worker_setup_launchagent_start_failed: launchctl bootstrap exited with code ${bootstrap.exitCode}. ${bootstrap.output.slice(0, 300)}`);
|
|
2870
2949
|
}
|
|
2871
2950
|
const kickstart = (0, shellProbe_1.runShell)(`launchctl kickstart -k ${shellQuote(`${domain}/${label}`)}`);
|
|
@@ -3247,12 +3326,6 @@ async function startWorker(options = {}) {
|
|
|
3247
3326
|
throw new Error('worker_session_invalid: the stored session did not resolve to a user. Run "playdrop auth login" and retry.');
|
|
3248
3327
|
}
|
|
3249
3328
|
const target = resolveWorkerExecutionTargetFromRole(me.user.role);
|
|
3250
|
-
const codexVersion = probeCodexInstallation()?.codexVersion ?? null;
|
|
3251
|
-
const claudeVersion = probeClaudeInstallation()?.claudeVersion ?? null;
|
|
3252
|
-
const cursorVersion = probeCursorInstallation()?.cursorVersion ?? null;
|
|
3253
|
-
const codexAuthenticated = codexVersion ? readCodexAuthenticated() : false;
|
|
3254
|
-
const claudeAuthenticated = claudeVersion ? readClaudeAuthenticated() : false;
|
|
3255
|
-
const cursorAuthenticated = cursorVersion ? readCursorAuthenticated() : false;
|
|
3256
3329
|
const npmVersion = probeNpmVersion();
|
|
3257
3330
|
const playwright = probePlaywrightChromium();
|
|
3258
3331
|
const playdropPluginRoot = resolvePlaydropPluginRoot();
|
|
@@ -3260,30 +3333,13 @@ async function startWorker(options = {}) {
|
|
|
3260
3333
|
const workerKey = (0, config_1.getOrCreateWorkerKey)();
|
|
3261
3334
|
const workerName = options.name?.trim() || `${username} - ${node_os_1.default.hostname()}`;
|
|
3262
3335
|
const maxParallelTasks = (0, runtime_1.readPositiveEnvInt)('PLAYDROP_WORKER_MAX_PARALLEL_TASKS', DEFAULT_WORKER_MAX_PARALLEL_TASKS);
|
|
3263
|
-
|
|
3264
|
-
codexVersion,
|
|
3265
|
-
codexAuthenticated,
|
|
3266
|
-
claudeVersion,
|
|
3267
|
-
claudeAuthenticated,
|
|
3268
|
-
cursorVersion,
|
|
3269
|
-
cursorAuthenticated,
|
|
3336
|
+
let capabilities = probeReadyWorkerCapabilities({
|
|
3270
3337
|
npmVersion,
|
|
3271
3338
|
playwright,
|
|
3272
3339
|
maxParallelTasks,
|
|
3273
|
-
|
|
3340
|
+
pluginVersion: playdropPluginVersion,
|
|
3274
3341
|
});
|
|
3275
|
-
|
|
3276
|
-
capabilities.pluginVersion = playdropPluginVersion;
|
|
3277
|
-
for (const agent of capabilities.agents) {
|
|
3278
|
-
agent.pluginVersion = playdropPluginVersion;
|
|
3279
|
-
}
|
|
3280
|
-
}
|
|
3281
|
-
if (!capabilities.ready) {
|
|
3282
|
-
const reasons = Array.isArray(capabilities.degradedReasons) && capabilities.degradedReasons.length > 0
|
|
3283
|
-
? capabilities.degradedReasons.join(', ')
|
|
3284
|
-
: 'no ready agent';
|
|
3285
|
-
throw new Error(`worker_preflight_failed: ${reasons}`);
|
|
3286
|
-
}
|
|
3342
|
+
let lastCapabilityRefreshAt = Date.now();
|
|
3287
3343
|
writeWorkerRuntimeState({
|
|
3288
3344
|
env,
|
|
3289
3345
|
workerKey,
|
|
@@ -3924,6 +3980,17 @@ async function startWorker(options = {}) {
|
|
|
3924
3980
|
if (sessionExpired) {
|
|
3925
3981
|
throw new Error(exports.WORKER_SESSION_EXPIRED_MESSAGE);
|
|
3926
3982
|
}
|
|
3983
|
+
if (activeTaskRuns.size === 0
|
|
3984
|
+
&& Date.now() - lastCapabilityRefreshAt >= WORKER_CAPABILITY_REFRESH_INTERVAL_MS) {
|
|
3985
|
+
capabilities = probeReadyWorkerCapabilities({
|
|
3986
|
+
npmVersion,
|
|
3987
|
+
playwright,
|
|
3988
|
+
maxParallelTasks,
|
|
3989
|
+
pluginVersion: playdropPluginVersion,
|
|
3990
|
+
});
|
|
3991
|
+
lastCapabilityRefreshAt = Date.now();
|
|
3992
|
+
console.log('Worker refreshed installed agent CLI versions and model catalogs.');
|
|
3993
|
+
}
|
|
3927
3994
|
if (activeTaskRuns.size >= maxParallelTasks) {
|
|
3928
3995
|
await sleep(DEFAULT_POLL_INTERVAL_MS);
|
|
3929
3996
|
continue;
|
|
@@ -4130,6 +4197,7 @@ async function uploadTask(options = {}) {
|
|
|
4130
4197
|
const published = await (0, upload_1.publishWorkerAppProject)({
|
|
4131
4198
|
client: ctx.client,
|
|
4132
4199
|
taskId: taskContext.taskId,
|
|
4200
|
+
taskToken: taskContext.taskToken,
|
|
4133
4201
|
kind: taskContext.kind,
|
|
4134
4202
|
executionTarget: taskContext.target,
|
|
4135
4203
|
expectedAppName: taskContext.outputAppName ?? undefined,
|
package/dist/index.js
CHANGED
|
@@ -120,6 +120,7 @@ function registerLoginCommand(parent) {
|
|
|
120
120
|
.option('--password <password>', 'Password for direct login')
|
|
121
121
|
.option('--key <apiKey>', 'API key for direct login')
|
|
122
122
|
.option('--handoff-token <token>', 'Native app handoff token for direct login')
|
|
123
|
+
.option('--handoff-token-stdin', 'Read a native app handoff token from stdin')
|
|
123
124
|
.option('--json', 'Output JSON')
|
|
124
125
|
.action(async (opts) => {
|
|
125
126
|
await (0, login_1.login)(opts.env, {
|
|
@@ -127,6 +128,7 @@ function registerLoginCommand(parent) {
|
|
|
127
128
|
password: opts.password,
|
|
128
129
|
key: opts.key,
|
|
129
130
|
handoffToken: opts.handoffToken,
|
|
131
|
+
handoffTokenStdin: opts.handoffTokenStdin,
|
|
130
132
|
json: opts.json,
|
|
131
133
|
});
|
|
132
134
|
});
|
|
@@ -141,14 +141,7 @@ export declare const AGENT_TASK_PROMPT_MIN_LENGTH = 4;
|
|
|
141
141
|
export declare const AGENT_TASK_PROMPT_MAX_LENGTH = 100000;
|
|
142
142
|
export declare const AGENT_RUNTIME_VALUES: readonly ["CODEX", "CLAUDE_CODE", "CURSOR_COMPOSER"];
|
|
143
143
|
export type AgentRuntime = typeof AGENT_RUNTIME_VALUES[number];
|
|
144
|
-
export declare
|
|
145
|
-
export type AgentTaskCodexModel = typeof AGENT_TASK_CODEX_MODEL_VALUES[number];
|
|
146
|
-
export declare const AGENT_TASK_CLAUDE_CODE_MODEL_VALUES: readonly ["claude-haiku-4-5", "claude-sonnet-4-6", "claude-opus-4-8"];
|
|
147
|
-
export type AgentTaskClaudeCodeModel = typeof AGENT_TASK_CLAUDE_CODE_MODEL_VALUES[number];
|
|
148
|
-
export declare const AGENT_TASK_CURSOR_COMPOSER_MODEL_VALUES: readonly ["cursor-composer-latest"];
|
|
149
|
-
export type AgentTaskCursorComposerModel = typeof AGENT_TASK_CURSOR_COMPOSER_MODEL_VALUES[number];
|
|
150
|
-
export declare const AGENT_TASK_MODEL_VALUES_BY_AGENT: Record<AgentRuntime, readonly string[]>;
|
|
151
|
-
export declare function normalizeAgentTaskModel(agent: AgentRuntime, model: string): string | null;
|
|
144
|
+
export declare function normalizeAgentTaskModel(_agent: AgentRuntime, model: string): string | null;
|
|
152
145
|
export declare const AGENT_TASK_EFFORT_VALUES: readonly ["simple", "standard", "complex"];
|
|
153
146
|
export type AgentTaskEffort = typeof AGENT_TASK_EFFORT_VALUES[number];
|
|
154
147
|
export declare const AGENT_TASK_EFFORT_KIND_VALUES: readonly ["BUILD_COMPLEXITY", "CHANGE_MAGNITUDE", "REVIEW_DEPTH"];
|
|
@@ -178,7 +171,6 @@ export interface AgentAttemptResult {
|
|
|
178
171
|
export interface AgentTaskAgentPreference extends AgentAttemptOption {
|
|
179
172
|
reason?: string | null;
|
|
180
173
|
}
|
|
181
|
-
export declare const AGENT_ATTEMPT_PLAN_DEFAULTS: Record<AgentTaskKind, AgentAttemptOption[]>;
|
|
182
174
|
export declare const AGENT_TASK_EVENT_KIND_VALUES: readonly ["progress", "agent_message", "system", "catalogue_preview"];
|
|
183
175
|
export type AgentTaskEventKind = typeof AGENT_TASK_EVENT_KIND_VALUES[number];
|
|
184
176
|
export declare const AGENT_TASK_TRANSCRIPT_STREAM_VALUES: readonly ["stdout", "stderr", "combined"];
|
|
@@ -660,7 +652,6 @@ export interface AgentWorkerUpdatePolicyResponse {
|
|
|
660
652
|
targetPluginVersion: string | null;
|
|
661
653
|
minimumPluginVersion: string | null;
|
|
662
654
|
requiredWrapperContractVersion: number;
|
|
663
|
-
managedAgentCliVersions?: Record<string, string>;
|
|
664
655
|
}
|
|
665
656
|
export interface WorkerUpdateIntentRequest {
|
|
666
657
|
workerKey: string;
|
|
@@ -1691,6 +1682,14 @@ export interface ReviewerAppAccessTokenResponse extends AppAccessTokenResponse {
|
|
|
1691
1682
|
reviewer: true;
|
|
1692
1683
|
};
|
|
1693
1684
|
}
|
|
1685
|
+
export interface CaptureAppAccessTokenResponse extends AppAccessTokenResponse {
|
|
1686
|
+
player: {
|
|
1687
|
+
id: number;
|
|
1688
|
+
username: string;
|
|
1689
|
+
displayName: string;
|
|
1690
|
+
capture: true;
|
|
1691
|
+
};
|
|
1692
|
+
}
|
|
1694
1693
|
export interface DevPlayerSummary {
|
|
1695
1694
|
userId: number;
|
|
1696
1695
|
slot: number;
|