@playdrop/playdrop-cli 0.12.41 → 0.13.0

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.
Files changed (116) hide show
  1. package/config/client-meta.json +2 -2
  2. package/dist/apps/index.d.ts +3 -0
  3. package/dist/apps/index.js +3 -1
  4. package/dist/apps/loadCheck.d.ts +21 -1
  5. package/dist/apps/loadCheck.js +253 -1
  6. package/dist/apps/playtestContract.d.ts +2 -0
  7. package/dist/apps/playtestContract.js +77 -0
  8. package/dist/apps/staticHtml.d.ts +28 -0
  9. package/dist/apps/staticHtml.js +343 -0
  10. package/dist/apps/upload.d.ts +1 -0
  11. package/dist/apps/upload.js +17 -0
  12. package/dist/apps/validate.js +2 -1
  13. package/dist/commands/devServer.js +19 -0
  14. package/dist/commands/feedback.d.ts +2 -0
  15. package/dist/commands/feedback.js +44 -2
  16. package/dist/commands/upload.d.ts +24 -0
  17. package/dist/commands/upload.js +131 -60
  18. package/dist/commands/worker/instrument-evidence.js +1 -1
  19. package/dist/commands/worker/runtime.d.ts +14 -0
  20. package/dist/commands/worker/runtime.js +97 -8
  21. package/dist/commands/worker.d.ts +27 -2
  22. package/dist/commands/worker.js +688 -146
  23. package/dist/index.js +7 -0
  24. package/dist/listingPreflight.js +15 -4
  25. package/node_modules/@playdrop/api-client/dist/client.d.ts +6 -2
  26. package/node_modules/@playdrop/api-client/dist/client.d.ts.map +1 -1
  27. package/node_modules/@playdrop/api-client/dist/domains/agent-tasks.d.ts +3 -2
  28. package/node_modules/@playdrop/api-client/dist/domains/agent-tasks.d.ts.map +1 -1
  29. package/node_modules/@playdrop/api-client/dist/domains/agent-tasks.js +13 -2
  30. package/node_modules/@playdrop/api-client/dist/domains/apps.d.ts +3 -1
  31. package/node_modules/@playdrop/api-client/dist/domains/apps.d.ts.map +1 -1
  32. package/node_modules/@playdrop/api-client/dist/domains/apps.js +11 -0
  33. package/node_modules/@playdrop/api-client/dist/domains/me.d.ts +2 -1
  34. package/node_modules/@playdrop/api-client/dist/domains/me.d.ts.map +1 -1
  35. package/node_modules/@playdrop/api-client/dist/domains/me.js +11 -0
  36. package/node_modules/@playdrop/api-client/dist/index.d.ts +6 -3
  37. package/node_modules/@playdrop/api-client/dist/index.d.ts.map +1 -1
  38. package/node_modules/@playdrop/api-client/dist/index.js +14 -2
  39. package/node_modules/@playdrop/config/client-meta.json +2 -2
  40. package/node_modules/@playdrop/config/dist/src/constants.d.ts +1 -0
  41. package/node_modules/@playdrop/config/dist/src/constants.d.ts.map +1 -1
  42. package/node_modules/@playdrop/config/dist/src/constants.js +1 -0
  43. package/node_modules/@playdrop/config/dist/tsconfig.tsbuildinfo +1 -1
  44. package/node_modules/@playdrop/types/dist/api.d.ts +195 -4
  45. package/node_modules/@playdrop/types/dist/api.d.ts.map +1 -1
  46. package/node_modules/@playdrop/types/dist/api.js +25 -2
  47. package/node_modules/@playdrop/types/dist/app-playtest-tape.d.ts +4 -0
  48. package/node_modules/@playdrop/types/dist/app-playtest-tape.d.ts.map +1 -1
  49. package/node_modules/@playdrop/types/dist/app-playtest-tape.js +56 -0
  50. package/node_modules/@playdrop/types/dist/version.d.ts +49 -1
  51. package/node_modules/@playdrop/types/dist/version.d.ts.map +1 -1
  52. package/node_modules/entities/decode-codepoint.d.ts +19 -0
  53. package/node_modules/entities/decode-codepoint.d.ts.map +1 -0
  54. package/node_modules/entities/decode-codepoint.js +77 -0
  55. package/node_modules/entities/decode-codepoint.js.map +1 -0
  56. package/node_modules/entities/decode.d.ts +209 -0
  57. package/node_modules/entities/decode.d.ts.map +1 -0
  58. package/node_modules/entities/decode.js +511 -0
  59. package/node_modules/entities/decode.js.map +1 -0
  60. package/node_modules/entities/encode.d.ts +22 -0
  61. package/node_modules/entities/encode.d.ts.map +1 -0
  62. package/node_modules/entities/encode.js +73 -0
  63. package/node_modules/entities/encode.js.map +1 -0
  64. package/node_modules/entities/escape.d.ts +43 -0
  65. package/node_modules/entities/escape.d.ts.map +1 -0
  66. package/node_modules/entities/escape.js +121 -0
  67. package/node_modules/entities/escape.js.map +1 -0
  68. package/node_modules/entities/generated/decode-data-html.d.ts +2 -0
  69. package/node_modules/entities/generated/decode-data-html.d.ts.map +1 -0
  70. package/node_modules/entities/generated/decode-data-html.js +10 -0
  71. package/node_modules/entities/generated/decode-data-html.js.map +1 -0
  72. package/node_modules/entities/generated/decode-data-xml.d.ts +2 -0
  73. package/node_modules/entities/generated/decode-data-xml.d.ts.map +1 -0
  74. package/node_modules/entities/generated/decode-data-xml.js +10 -0
  75. package/node_modules/entities/generated/decode-data-xml.js.map +1 -0
  76. package/node_modules/entities/generated/encode-html.d.ts +8 -0
  77. package/node_modules/entities/generated/encode-html.d.ts.map +1 -0
  78. package/node_modules/entities/generated/encode-html.js +13 -0
  79. package/node_modules/entities/generated/encode-html.js.map +1 -0
  80. package/node_modules/entities/index.d.ts +96 -0
  81. package/node_modules/entities/index.d.ts.map +1 -0
  82. package/node_modules/entities/index.js +131 -0
  83. package/node_modules/entities/index.js.map +1 -0
  84. package/node_modules/entities/package.json +3 -0
  85. package/node_modules/parse5/common/doctype.d.ts +4 -0
  86. package/node_modules/parse5/common/doctype.js +118 -0
  87. package/node_modules/parse5/common/error-codes.d.ts +67 -0
  88. package/node_modules/parse5/common/error-codes.js +66 -0
  89. package/node_modules/parse5/common/foreign-content.d.ts +9 -0
  90. package/node_modules/parse5/common/foreign-content.js +237 -0
  91. package/node_modules/parse5/common/html.d.ts +289 -0
  92. package/node_modules/parse5/common/html.js +528 -0
  93. package/node_modules/parse5/common/token.d.ts +84 -0
  94. package/node_modules/parse5/common/token.js +24 -0
  95. package/node_modules/parse5/common/unicode.d.ts +42 -0
  96. package/node_modules/parse5/common/unicode.js +70 -0
  97. package/node_modules/parse5/index.d.ts +71 -0
  98. package/node_modules/parse5/index.js +54 -0
  99. package/node_modules/parse5/package.json +1 -0
  100. package/node_modules/parse5/parser/formatting-element-list.d.ts +36 -0
  101. package/node_modules/parse5/parser/formatting-element-list.js +114 -0
  102. package/node_modules/parse5/parser/index.d.ts +221 -0
  103. package/node_modules/parse5/parser/index.js +3240 -0
  104. package/node_modules/parse5/parser/open-element-stack.d.ts +53 -0
  105. package/node_modules/parse5/parser/open-element-stack.js +328 -0
  106. package/node_modules/parse5/serializer/index.d.ts +60 -0
  107. package/node_modules/parse5/serializer/index.js +172 -0
  108. package/node_modules/parse5/tokenizer/index.d.ts +247 -0
  109. package/node_modules/parse5/tokenizer/index.js +2714 -0
  110. package/node_modules/parse5/tokenizer/preprocessor.d.ts +36 -0
  111. package/node_modules/parse5/tokenizer/preprocessor.js +200 -0
  112. package/node_modules/parse5/tree-adapters/default.d.ts +84 -0
  113. package/node_modules/parse5/tree-adapters/default.js +176 -0
  114. package/node_modules/parse5/tree-adapters/interface.d.ts +255 -0
  115. package/node_modules/parse5/tree-adapters/interface.js +2 -0
  116. package/package.json +7 -1
@@ -8,17 +8,20 @@ exports.assertAgentNewGamePlaytestContract = assertAgentNewGamePlaytestContract;
8
8
  exports.assertTaskPlaytestEvidenceManifest = assertTaskPlaytestEvidenceManifest;
9
9
  exports.assertWorkerAppLocalUploadPreflight = assertWorkerAppLocalUploadPreflight;
10
10
  exports.publishWorkerAppProject = publishWorkerAppProject;
11
+ exports.publishStaticHtmlProject = publishStaticHtmlProject;
11
12
  const node_crypto_1 = require("node:crypto");
12
13
  const node_fs_1 = require("node:fs");
13
14
  const node_path_1 = require("node:path");
14
15
  const semver_1 = require("semver");
15
16
  const types_1 = require("@playdrop/types");
16
17
  const apps_1 = require("../apps");
18
+ const staticHtml_1 = require("../apps/staticHtml");
17
19
  const registration_1 = require("../apps/registration");
18
20
  const commandContext_1 = require("../commandContext");
19
21
  const http_1 = require("../http");
20
22
  const catalogue_1 = require("../catalogue");
21
23
  const messages_1 = require("../messages");
24
+ const output_1 = require("../output");
22
25
  const taskSelection_1 = require("../taskSelection");
23
26
  const taskUtils_1 = require("../taskUtils");
24
27
  const uploadLog_1 = require("../uploadLog");
@@ -1142,6 +1145,10 @@ function printResolvedUploadAccount(input) {
1142
1145
  console.log(`Resolved account: ${username} (${input.env})`);
1143
1146
  }
1144
1147
  async function upload(pathOrName, options) {
1148
+ const directEntryPath = (0, node_path_1.resolve)(pathOrName);
1149
+ const directStaticHtml = (0, node_fs_1.existsSync)(directEntryPath)
1150
+ && (0, node_fs_1.statSync)(directEntryPath).isFile()
1151
+ && (0, node_path_1.basename)(directEntryPath).toLowerCase() === 'index.html';
1145
1152
  const selection = (0, taskSelection_1.selectTasks)(pathOrName);
1146
1153
  const workspaceRoot = resolveUploadWorkspaceRoot(pathOrName, selection.resolution);
1147
1154
  const ctx = await (0, commandContext_1.resolveAuthenticatedEnvironmentContext)('project publish', 'Publishing content', {
@@ -1152,10 +1159,12 @@ async function upload(pathOrName, options) {
1152
1159
  return;
1153
1160
  }
1154
1161
  const { client, env, envConfig } = ctx;
1155
- printResolvedUploadAccount({
1156
- env,
1157
- username: ctx.account?.username,
1158
- });
1162
+ if (!options?.json) {
1163
+ printResolvedUploadAccount({
1164
+ env,
1165
+ username: ctx.account?.username,
1166
+ });
1167
+ }
1159
1168
  let userInfo = { username: null, role: null, user: null };
1160
1169
  try {
1161
1170
  userInfo = await fetchCurrentUserInfo(client, envConfig.apiBase);
@@ -1167,6 +1176,30 @@ async function upload(pathOrName, options) {
1167
1176
  throw error;
1168
1177
  }
1169
1178
  const owner = resolveUploadOwner(userInfo.username, ctx.workspaceAuth?.config.ownerUsername);
1179
+ if (directStaticHtml) {
1180
+ if (!userInfo.username || !userInfo.user) {
1181
+ throw new Error('static_game_publish_authenticated_user_missing');
1182
+ }
1183
+ const result = await publishStaticHtmlProject({
1184
+ client,
1185
+ projectDir: (0, node_path_1.dirname)(directEntryPath),
1186
+ creatorUsername: userInfo.username,
1187
+ primarySurface: 'DESKTOP',
1188
+ apiBase: envConfig.apiBase,
1189
+ webBase: envConfig.webBase,
1190
+ token: ctx.token,
1191
+ user: userInfo.user,
1192
+ });
1193
+ if (options?.json) {
1194
+ (0, output_1.printJson)(result);
1195
+ }
1196
+ else {
1197
+ (0, output_1.printSuccess)(`Published private static game ${result.creatorUsername}/${result.appName}@${result.version}`);
1198
+ console.log(result.playUrl);
1199
+ result.warnings.forEach((warning) => console.warn(warning));
1200
+ }
1201
+ return;
1202
+ }
1170
1203
  const tagGroupLoad = (0, catalogue_1.resolveCatalogueTagGroups)(workspaceRoot);
1171
1204
  if (tagGroupLoad.errors.length > 0) {
1172
1205
  (0, taskSelection_1.reportTaskErrors)(tagGroupLoad.errors.map((message) => ({
@@ -1234,9 +1267,16 @@ function assertAgentNewGamePlaytestContract(task) {
1234
1267
  throw new Error('agent_task_playtest_tapes_required: NEW_GAME catalogue.json must declare one playtest tape per supported surface.');
1235
1268
  }
1236
1269
  for (const surface of task.surfaceTargets) {
1237
- if (!task.playtestTapes[surface]) {
1270
+ const tape = task.playtestTapes[surface];
1271
+ if (!tape) {
1238
1272
  throw new Error(`agent_task_playtest_tape_missing:${surface}`);
1239
1273
  }
1274
+ if (tape.startOnlyEventCount <= 0) {
1275
+ throw new Error(`agent_task_playtest_start_only_required:${surface}: the tape must include an explicit startup action.`);
1276
+ }
1277
+ if (tape.events[0]?.atMs !== 0) {
1278
+ throw new Error(`agent_task_playtest_ready_relative_timing_required:${surface}: the first startup event must run at 0 ms after sdk.host.ready().`);
1279
+ }
1240
1280
  }
1241
1281
  }
1242
1282
  const WORKER_SUPERVISOR_SOURCE_EXCLUDES = [
@@ -1823,58 +1863,6 @@ function buildRequiredTaskPlaytestProof(task, manifest, currentSelfPlaytestCaptu
1823
1863
  }
1824
1864
  return parsed.value;
1825
1865
  }
1826
- function assertRequiredCausalChecks(manifest) {
1827
- const rawChecks = manifest.causalChecks;
1828
- if (!rawChecks || typeof rawChecks !== 'object' || Array.isArray(rawChecks)) {
1829
- throw new Error(formatPlaytestEvidenceManifestError('causalChecks must contain matchedRuns, counterfactual, replay, challenge, and readability3D for NEW_GAME tasks.'));
1830
- }
1831
- const checks = rawChecks;
1832
- assertExactObjectKeys(checks, ['matchedRuns', 'counterfactual', 'replay', 'challenge', 'readability3D'], 'causalChecks');
1833
- const requirePassingCheck = (name, stringKeys, booleanKeys) => {
1834
- const rawCheck = checks[name];
1835
- if (!rawCheck || typeof rawCheck !== 'object' || Array.isArray(rawCheck)) {
1836
- throw new Error(formatPlaytestEvidenceManifestError(`causalChecks.${name} must be an object.`));
1837
- }
1838
- const check = rawCheck;
1839
- assertExactObjectKeys(check, [...stringKeys, ...booleanKeys], `causalChecks.${name}`);
1840
- for (const key of stringKeys) {
1841
- if (typeof check[key] !== 'string' || !check[key].trim()) {
1842
- throw new Error(formatPlaytestEvidenceManifestError(`causalChecks.${name}.${key} must be a non-empty string.`));
1843
- }
1844
- }
1845
- for (const key of booleanKeys) {
1846
- if (typeof check[key] !== 'boolean') {
1847
- throw new Error(formatPlaytestEvidenceManifestError(`causalChecks.${name}.${key} must be boolean.`));
1848
- }
1849
- }
1850
- if (check.passed !== true) {
1851
- throw new Error(formatPlaytestEvidenceManifestError(`causalChecks.${name}.passed must be true before upload.`));
1852
- }
1853
- return check;
1854
- };
1855
- if (!Array.isArray(checks.matchedRuns) || checks.matchedRuns.length === 0) {
1856
- throw new Error(formatPlaytestEvidenceManifestError('causalChecks.matchedRuns must include the primary-surface comparison.'));
1857
- }
1858
- for (const [index, rawRun] of checks.matchedRuns.entries()) {
1859
- if (!rawRun || typeof rawRun !== 'object' || Array.isArray(rawRun)) {
1860
- throw new Error(formatPlaytestEvidenceManifestError(`causalChecks.matchedRuns[${index}] must be an object.`));
1861
- }
1862
- const run = rawRun;
1863
- assertExactObjectKeys(run, ['surface', 'zeroInputOutcome', 'startOnlyOutcome', 'fullTapeOutcome', 'criterion', 'passed'], `causalChecks.matchedRuns[${index}]`);
1864
- for (const key of ['surface', 'zeroInputOutcome', 'startOnlyOutcome', 'fullTapeOutcome', 'criterion']) {
1865
- if (typeof run[key] !== 'string' || !run[key].trim()) {
1866
- throw new Error(formatPlaytestEvidenceManifestError(`causalChecks.matchedRuns[${index}].${key} must be a non-empty string.`));
1867
- }
1868
- }
1869
- if (run.passed !== true) {
1870
- throw new Error(formatPlaytestEvidenceManifestError(`causalChecks.matchedRuns[${index}].passed must be true before upload.`));
1871
- }
1872
- }
1873
- requirePassingCheck('counterfactual', ['normalInput', 'perturbedInput', 'normalOutcome', 'perturbedOutcome'], ['passed']);
1874
- requirePassingCheck('replay', ['action', 'outcome'], ['applicable', 'passed']);
1875
- requirePassingCheck('challenge', ['claim', 'action', 'outcome'], ['passed']);
1876
- requirePassingCheck('readability3D', ['controlledEntity', 'objectiveOrHazard', 'primaryActionEffect'], ['applicable', 'passed']);
1877
- }
1878
1866
  function assertTaskPlaytestEvidenceManifest(task, options = {}) {
1879
1867
  const manifest = readPlaytestEvidenceManifest(task);
1880
1868
  if (manifest.version !== 1) {
@@ -1918,9 +1906,6 @@ function assertTaskPlaytestEvidenceManifest(task, options = {}) {
1918
1906
  if (!hasCurrentSelfPlaytest) {
1919
1907
  throw new Error(formatPlaytestEvidenceManifestError(`playtest-evidence.json must include a non-final self-playtest checkedAt after the last source change${sourceLastModifiedAt ? ` (${sourceLastModifiedAt})` : ''}.`));
1920
1908
  }
1921
- if (options.requireOutcomeProof) {
1922
- assertRequiredCausalChecks(manifest);
1923
- }
1924
1909
  return options.requireOutcomeProof
1925
1910
  ? buildRequiredTaskPlaytestProof(task, manifest, currentSelfPlaytestCaptures)
1926
1911
  : null;
@@ -2080,6 +2065,7 @@ async function publishWorkerAppProject(input) {
2080
2065
  agentTaskId: input.taskId,
2081
2066
  playtestProof: playtestProof ?? undefined,
2082
2067
  mediaCaptureRequired: input.executionTarget === 'FIRST_PARTY',
2068
+ machineCausalGateRequired: input.kind === 'NEW_GAME',
2083
2069
  captureSession,
2084
2070
  });
2085
2071
  if (!uploadResult.versionCreated || !uploadResult.version) {
@@ -2101,3 +2087,88 @@ async function publishWorkerAppProject(input) {
2101
2087
  warnings: [...selection.warnings, ...warnings],
2102
2088
  };
2103
2089
  }
2090
+ async function publishStaticHtmlProject(input) {
2091
+ const creatorUsername = input.creatorUsername.trim();
2092
+ if (!creatorUsername) {
2093
+ throw new Error('static_game_publish_creator_username_missing');
2094
+ }
2095
+ if (input.user.username !== creatorUsername && input.user.role !== 'ADMIN') {
2096
+ throw new Error(`static_game_publish_on_behalf_requires_admin:${input.user.username}:${creatorUsername}`);
2097
+ }
2098
+ const prepared = await (0, staticHtml_1.prepareStaticHtmlProject)({
2099
+ projectDir: input.projectDir,
2100
+ taskId: input.taskId,
2101
+ appName: input.claimedAppName?.trim() || undefined,
2102
+ primarySurface: input.primarySurface,
2103
+ });
2104
+ try {
2105
+ if (input.taskId !== undefined && !input.claimedAppName?.trim()) {
2106
+ const taskToken = input.taskToken?.trim() ?? '';
2107
+ if (!taskToken) {
2108
+ throw new Error('static_game_publish_task_token_missing');
2109
+ }
2110
+ const claimed = await input.client.workerClaimAgentTaskSlug(input.taskId, {
2111
+ appName: prepared.runtimeTask.name,
2112
+ displayName: prepared.metadata.title,
2113
+ });
2114
+ if (claimed.appName !== prepared.runtimeTask.name) {
2115
+ throw new Error(`static_game_publish_slug_claim_mismatch:${claimed.appName}:${prepared.runtimeTask.name}`);
2116
+ }
2117
+ }
2118
+ const { app } = await (0, registration_1.ensureRegisteredHostedAppShell)({
2119
+ client: input.client,
2120
+ creatorUsername,
2121
+ task: prepared.runtimeTask,
2122
+ agentTaskId: input.taskId,
2123
+ });
2124
+ if (typeof app.id !== 'number' || !Number.isInteger(app.id) || app.id <= 0) {
2125
+ throw new Error('static_game_publish_app_registration_failed');
2126
+ }
2127
+ const appId = app.id;
2128
+ const captureSession = input.taskId !== undefined && input.taskToken?.trim()
2129
+ ? { appId, taskId: input.taskId, taskToken: input.taskToken.trim() }
2130
+ : null;
2131
+ const { upload, warnings } = await (0, apps_1.runAppPipeline)(input.client, prepared.runtimeTask, {
2132
+ creatorUsername,
2133
+ apiBase: input.apiBase,
2134
+ webBase: normalizePortalBase(input.webBase ?? undefined),
2135
+ token: input.token,
2136
+ user: input.user,
2137
+ runLocalLoadCheck: true,
2138
+ devRouterPort: input.devRouterPort,
2139
+ runStagedUploadLoadCheck: true,
2140
+ ensureRegisteredAppShell: true,
2141
+ agentTaskId: input.taskId,
2142
+ mediaCaptureRequired: false,
2143
+ machineCausalGateRequired: false,
2144
+ captureSession,
2145
+ artifacts: prepared.artifacts,
2146
+ });
2147
+ if (!upload.version || !Number.isInteger(upload.versionId) || !upload.versionNodeId?.trim()) {
2148
+ throw new Error('static_game_publish_version_result_missing');
2149
+ }
2150
+ return {
2151
+ appId,
2152
+ appVersionId: upload.versionId,
2153
+ versionNodeId: upload.versionNodeId,
2154
+ version: upload.version,
2155
+ appName: prepared.runtimeTask.name,
2156
+ creatorUsername,
2157
+ sourceHash: prepared.sourceHash,
2158
+ runtimeHash: prepared.runtimeHash,
2159
+ sourceContainsInjectedSdk: false,
2160
+ runtimeContainsInjectedSdk: true,
2161
+ hostedLoadCheckPassed: true,
2162
+ warnings: [...prepared.metadata.warnings, ...warnings],
2163
+ playUrl: (0, appUrls_1.buildPlatformPrivateDraftPlayUrl)(input.webBase, {
2164
+ creatorUsername,
2165
+ appName: prepared.runtimeTask.name,
2166
+ appType: 'GAME',
2167
+ version: upload.version,
2168
+ }),
2169
+ };
2170
+ }
2171
+ finally {
2172
+ await prepared.cleanup();
2173
+ }
2174
+ }
@@ -260,7 +260,7 @@ function readAndValidateInstrumentEvidenceManifest(input) {
260
260
  const rawCapture = parsed.captures?.[name];
261
261
  if (!rawCapture) {
262
262
  if (types_1.REQUIRED_INSTRUMENT_EVIDENCE_NAMES.includes(name)) {
263
- throw new Error(`invalid_instrument_evidence_capture:${name}`);
263
+ throw new Error(`invalid_instrument_evidence_capture:${groupId}:${name}`);
264
264
  }
265
265
  continue;
266
266
  }
@@ -1,4 +1,6 @@
1
1
  export declare const DEFAULT_CODEX_TIMEOUT_MS: number;
2
+ export declare const DEFAULT_CREATOR_AGENT_TIMEOUT_MS: number;
3
+ export declare const DEFAULT_CREATOR_UPLOAD_RECOVERY_TIMEOUT_MS: number;
2
4
  export declare const DEFAULT_WORKER_TOKEN_CAP = 20000000;
3
5
  export declare const DEFAULT_CODEX_LOG_TAIL_CHARS = 12000;
4
6
  export declare const DEFAULT_TRANSCRIPT_FLUSH_INTERVAL_MS = 10000;
@@ -11,6 +13,7 @@ export type LoggedProcessResult = {
11
13
  timedOut: boolean;
12
14
  tokenUsage: AgentTokenUsage;
13
15
  tokensUsed: number | null;
16
+ providerSessionId?: string | null;
14
17
  };
15
18
  export type AgentTokenUsage = {
16
19
  inputTokens: number | null;
@@ -31,6 +34,7 @@ export declare function readEnvBoolean(name: string, fallback: boolean): boolean
31
34
  export declare function extractAgentTokenUsage(output: string): AgentTokenUsage;
32
35
  export declare function extractCodexRolloutTokenUsage(output: string): AgentTokenUsage;
33
36
  export declare function extractCodexThreadId(output: string): string | null;
37
+ export declare function extractClaudeSessionId(output: string): string | null;
34
38
  export type CodexRolloutTokenUsageReadOptions = {
35
39
  sessionsRoot?: string;
36
40
  deleteAfterRead?: boolean;
@@ -63,6 +67,7 @@ export declare function buildCodexExecArgs(input: {
63
67
  networkAccess: boolean;
64
68
  sandboxMode?: CodexSandboxMode;
65
69
  imagePaths?: string[];
70
+ resumeSessionId?: string | null;
66
71
  }): string[];
67
72
  export type CodexSandboxMode = 'danger-full-access' | 'workspace-write' | 'read-only';
68
73
  export declare function readCodexSandboxMode(env?: NodeJS.ProcessEnv): CodexSandboxMode;
@@ -75,6 +80,8 @@ export declare function buildClaudeExecArgs(input: {
75
80
  workspaceDir?: string | null;
76
81
  denyReadRoots?: string[] | null;
77
82
  pluginDir?: string | null;
83
+ playdropCliEnabled?: boolean;
84
+ resumeSessionId?: string | null;
78
85
  }): string[];
79
86
  export declare const PLAYWRIGHT_MCP_VERSION = "0.0.78";
80
87
  export type WorkerInstrumentSurface = 'DESKTOP' | 'MOBILE_LANDSCAPE' | 'MOBILE_PORTRAIT';
@@ -86,6 +93,7 @@ export declare function buildPlaywrightMcpServerConfig(surface?: WorkerInstrumen
86
93
  export declare function buildClaudePermissionSettings(input?: {
87
94
  workspaceDir?: string | null;
88
95
  denyReadRoots?: string[];
96
+ playdropCliEnabled?: boolean;
89
97
  }): {
90
98
  permissions: {
91
99
  allow: string[];
@@ -108,3 +116,9 @@ export declare function buildWorkerChildEnv(input: {
108
116
  playwrightBrowsersPath?: string;
109
117
  baseEnv?: NodeJS.ProcessEnv;
110
118
  }): NodeJS.ProcessEnv;
119
+ export declare function buildCleanRoomChildEnv(input: {
120
+ binDir: string;
121
+ homeDir?: string;
122
+ codexHomeDir?: string;
123
+ baseEnv?: NodeJS.ProcessEnv;
124
+ }): NodeJS.ProcessEnv;
@@ -3,13 +3,14 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.PLAYWRIGHT_MCP_VERSION = exports.DEFAULT_TRANSCRIPT_FLUSH_INTERVAL_MS = exports.DEFAULT_CODEX_LOG_TAIL_CHARS = exports.DEFAULT_WORKER_TOKEN_CAP = exports.DEFAULT_CODEX_TIMEOUT_MS = void 0;
6
+ exports.PLAYWRIGHT_MCP_VERSION = exports.DEFAULT_TRANSCRIPT_FLUSH_INTERVAL_MS = exports.DEFAULT_CODEX_LOG_TAIL_CHARS = exports.DEFAULT_WORKER_TOKEN_CAP = exports.DEFAULT_CREATOR_UPLOAD_RECOVERY_TIMEOUT_MS = exports.DEFAULT_CREATOR_AGENT_TIMEOUT_MS = exports.DEFAULT_CODEX_TIMEOUT_MS = void 0;
7
7
  exports.resolveDescendantProcessIds = resolveDescendantProcessIds;
8
8
  exports.readPositiveEnvInt = readPositiveEnvInt;
9
9
  exports.readEnvBoolean = readEnvBoolean;
10
10
  exports.extractAgentTokenUsage = extractAgentTokenUsage;
11
11
  exports.extractCodexRolloutTokenUsage = extractCodexRolloutTokenUsage;
12
12
  exports.extractCodexThreadId = extractCodexThreadId;
13
+ exports.extractClaudeSessionId = extractClaudeSessionId;
13
14
  exports.readCodexRolloutTokenUsageForThread = readCodexRolloutTokenUsageForThread;
14
15
  exports.extractCodexTokensUsed = extractCodexTokensUsed;
15
16
  exports.assertWorkerTokenUsageWithinCap = assertWorkerTokenUsageWithinCap;
@@ -22,13 +23,17 @@ exports.buildPlaywrightMcpServerConfig = buildPlaywrightMcpServerConfig;
22
23
  exports.buildClaudePermissionSettings = buildClaudePermissionSettings;
23
24
  exports.buildClaudeDeniedPermissionRules = buildClaudeDeniedPermissionRules;
24
25
  exports.buildWorkerChildEnv = buildWorkerChildEnv;
26
+ exports.buildCleanRoomChildEnv = buildCleanRoomChildEnv;
25
27
  const node_child_process_1 = require("node:child_process");
28
+ const node_fs_1 = require("node:fs");
26
29
  const promises_1 = require("node:fs/promises");
27
30
  const node_os_1 = __importDefault(require("node:os"));
28
31
  const node_path_1 = __importDefault(require("node:path"));
29
32
  const surfaceProfiles_1 = require("../../apps/surfaceProfiles");
30
33
  const CHILD_KILL_GRACE_MS = 10000;
31
34
  exports.DEFAULT_CODEX_TIMEOUT_MS = 2 * 60 * 60 * 1000;
35
+ exports.DEFAULT_CREATOR_AGENT_TIMEOUT_MS = 60 * 60 * 1000;
36
+ exports.DEFAULT_CREATOR_UPLOAD_RECOVERY_TIMEOUT_MS = 30 * 60 * 1000;
32
37
  exports.DEFAULT_WORKER_TOKEN_CAP = 20000000;
33
38
  exports.DEFAULT_CODEX_LOG_TAIL_CHARS = 12000;
34
39
  exports.DEFAULT_TRANSCRIPT_FLUSH_INTERVAL_MS = 10000;
@@ -296,6 +301,25 @@ function extractCodexThreadId(output) {
296
301
  }
297
302
  return null;
298
303
  }
304
+ function extractClaudeSessionId(output) {
305
+ for (const line of output.split(/\r?\n/)) {
306
+ const trimmed = line.trim();
307
+ if (!trimmed.startsWith('{') || !trimmed.endsWith('}')) {
308
+ continue;
309
+ }
310
+ try {
311
+ const root = coerceRecord(JSON.parse(trimmed));
312
+ const rawSessionId = root?.session_id ?? root?.sessionId;
313
+ if (typeof rawSessionId === 'string' && rawSessionId.trim()) {
314
+ return rawSessionId.trim();
315
+ }
316
+ }
317
+ catch {
318
+ continue;
319
+ }
320
+ }
321
+ return null;
322
+ }
299
323
  async function findCodexRolloutFileForThread(threadId, sessionsRoot) {
300
324
  const stack = [{ dir: sessionsRoot, depth: 0 }];
301
325
  const matches = [];
@@ -531,10 +555,24 @@ async function runLoggedProcess(input) {
531
555
  }
532
556
  function buildCodexExecArgs(input) {
533
557
  const sandboxMode = input.sandboxMode ?? 'danger-full-access';
558
+ const resumeSessionId = input.resumeSessionId?.trim() ?? '';
559
+ if (resumeSessionId) {
560
+ return [
561
+ 'exec',
562
+ 'resume',
563
+ '--json',
564
+ '--skip-git-repo-check',
565
+ '--model',
566
+ input.model,
567
+ '-c',
568
+ `model_reasoning_effort="${input.reasoningEffort}"`,
569
+ resumeSessionId,
570
+ '-',
571
+ ];
572
+ }
534
573
  const args = [
535
574
  'exec',
536
575
  '--json',
537
- '--ephemeral',
538
576
  '--sandbox',
539
577
  sandboxMode,
540
578
  '--cd',
@@ -581,6 +619,7 @@ function buildClaudeExecArgs(input) {
581
619
  const permissionSettings = buildClaudePermissionSettings({
582
620
  workspaceDir: input.workspaceDir,
583
621
  denyReadRoots: input.denyReadRoots ?? [],
622
+ playdropCliEnabled: input.playdropCliEnabled,
584
623
  });
585
624
  const permissionMode = input.chrome || input.playwrightMcp ? 'bypassPermissions' : 'acceptEdits';
586
625
  // MCP tools are deferred behind ToolSearch in the Claude CLI; without it in the toolset a
@@ -590,7 +629,7 @@ function buildClaudeExecArgs(input) {
590
629
  : input.playwrightMcp
591
630
  ? [...CLAUDE_BASE_TOOL_NAMES, 'ToolSearch'].join(',')
592
631
  : CLAUDE_BASE_TOOL_NAMES.join(',');
593
- const allowedPermissionRules = buildClaudeAllowedPermissionRules(input.workspaceDir);
632
+ const allowedPermissionRules = buildClaudeAllowedPermissionRules(input.workspaceDir, input.playdropCliEnabled);
594
633
  const allowedTools = input.chrome
595
634
  ? [...allowedPermissionRules, ...CLAUDE_CHROME_TOOL_NAMES]
596
635
  : input.playwrightMcp
@@ -609,7 +648,6 @@ function buildClaudeExecArgs(input) {
609
648
  'stream-json',
610
649
  '--verbose',
611
650
  '--include-partial-messages',
612
- '--no-session-persistence',
613
651
  '--permission-mode',
614
652
  permissionMode,
615
653
  '--tools',
@@ -635,6 +673,10 @@ function buildClaudeExecArgs(input) {
635
673
  if (effort) {
636
674
  args.push('--effort', effort);
637
675
  }
676
+ const resumeSessionId = input.resumeSessionId?.trim() ?? '';
677
+ if (resumeSessionId) {
678
+ args.push('--resume', resumeSessionId);
679
+ }
638
680
  return args;
639
681
  }
640
682
  const CLAUDE_BASE_TOOL_NAMES = [
@@ -702,6 +744,7 @@ const CLAUDE_BUILD_PERMISSION_RULES = [
702
744
  'Grep',
703
745
  'Bash(playdrop *)',
704
746
  'Bash(./bin/playdrop *)',
747
+ 'Bash(../bin/playdrop *)',
705
748
  'Bash(bin/playdrop *)',
706
749
  'Bash(node *)',
707
750
  'Bash(npm *)',
@@ -709,6 +752,7 @@ const CLAUDE_BUILD_PERMISSION_RULES = [
709
752
  'Bash(cp *)',
710
753
  'Bash(mv *)',
711
754
  'Bash(file *)',
755
+ 'Bash(curl *)',
712
756
  'Bash(sips *)',
713
757
  'Bash(ls *)',
714
758
  'Bash(pwd)',
@@ -731,7 +775,7 @@ function normalizeClaudePermissionPath(value) {
731
775
  }
732
776
  return node_path_1.default.resolve(trimmed).replace(/\\/g, '/').replace(/\/+$/, '');
733
777
  }
734
- function buildClaudeAllowedPermissionRules(workspaceDir) {
778
+ function buildClaudeAllowedPermissionRules(workspaceDir, playdropCliEnabled = true) {
735
779
  const workspaceRoot = typeof workspaceDir === 'string' && workspaceDir.trim()
736
780
  ? normalizeClaudePermissionPath(workspaceDir)
737
781
  : null;
@@ -743,14 +787,14 @@ function buildClaudeAllowedPermissionRules(workspaceDir) {
743
787
  `Read(${absoluteWorkspacePattern})`,
744
788
  `Edit(${absoluteWorkspacePattern})`,
745
789
  `Write(${absoluteWorkspacePattern})`,
746
- `Bash(${workspaceRoot}/bin/playdrop *)`,
747
- ...CLAUDE_BUILD_PERMISSION_RULES,
790
+ ...(playdropCliEnabled ? [`Bash(${workspaceRoot}/bin/playdrop *)`] : []),
791
+ ...CLAUDE_BUILD_PERMISSION_RULES.filter((rule) => (playdropCliEnabled || !rule.toLowerCase().includes('playdrop'))),
748
792
  ];
749
793
  }
750
794
  function buildClaudePermissionSettings(input = {}) {
751
795
  return {
752
796
  permissions: {
753
- allow: buildClaudeAllowedPermissionRules(input.workspaceDir),
797
+ allow: buildClaudeAllowedPermissionRules(input.workspaceDir, input.playdropCliEnabled),
754
798
  deny: buildClaudeDeniedPermissionRules(input.denyReadRoots ?? []),
755
799
  },
756
800
  };
@@ -860,3 +904,48 @@ function buildWorkerChildEnv(input) {
860
904
  }
861
905
  return child;
862
906
  }
907
+ function buildCleanRoomChildEnv(input) {
908
+ const base = input.baseEnv ?? process.env;
909
+ const child = {};
910
+ for (const key of [
911
+ 'HOME',
912
+ 'USER',
913
+ 'SHELL',
914
+ 'TMPDIR',
915
+ 'LANG',
916
+ 'TERM',
917
+ 'ANTHROPIC_API_KEY',
918
+ 'OPENAI_API_KEY',
919
+ 'HTTP_PROXY',
920
+ 'HTTPS_PROXY',
921
+ 'ALL_PROXY',
922
+ 'NO_PROXY',
923
+ ]) {
924
+ const value = base[key];
925
+ if (typeof value === 'string')
926
+ child[key] = value;
927
+ }
928
+ for (const [key, value] of Object.entries(base)) {
929
+ if (key.startsWith('LC_') && typeof value === 'string')
930
+ child[key] = value;
931
+ }
932
+ if (input.homeDir !== undefined) {
933
+ const homeDir = input.homeDir.trim();
934
+ if (!homeDir || !node_path_1.default.isAbsolute(homeDir))
935
+ throw new Error('invalid_worker_child_home_dir');
936
+ child.HOME = homeDir;
937
+ }
938
+ if (input.codexHomeDir !== undefined) {
939
+ const codexHomeDir = input.codexHomeDir.trim();
940
+ if (!codexHomeDir || !node_path_1.default.isAbsolute(codexHomeDir))
941
+ throw new Error('invalid_worker_child_codex_home_dir');
942
+ child.CODEX_HOME = codexHomeDir;
943
+ }
944
+ const safeHostPath = (base.PATH ?? '').split(node_path_1.default.delimiter).filter((directory) => {
945
+ if (!directory || !node_path_1.default.isAbsolute(directory))
946
+ return false;
947
+ return !(0, node_fs_1.existsSync)(node_path_1.default.join(directory, process.platform === 'win32' ? 'playdrop.exe' : 'playdrop'));
948
+ });
949
+ child.PATH = [input.binDir, ...safeHostPath].join(node_path_1.default.delimiter);
950
+ return child;
951
+ }
@@ -4,8 +4,14 @@ import { loadConfig } from '../config';
4
4
  import { runShell } from '../shellProbe';
5
5
  import { type WorkerPlaydropAssetRequirement } from './upload';
6
6
  import { type WorkerInstrumentSurface, type LoggedProcessResult, type LoggedProcessTranscriptChunk } from './worker/runtime';
7
- export { assertWorkerTokenUsageWithinCap, buildClaudeExecArgs, buildClaudePermissionSettings, buildCodexExecArgs, buildPlaywrightMcpCommand, buildWorkerChildEnv, DEFAULT_CODEX_TIMEOUT_MS, DEFAULT_WORKER_TOKEN_CAP, extractAgentTokenUsage, extractCodexRolloutTokenUsage, extractCodexThreadId, extractCodexTokensUsed, readCodexRolloutTokenUsageForThread, readCodexSandboxMode, readEnvBoolean, runLoggedProcess } from './worker/runtime';
7
+ export { assertWorkerTokenUsageWithinCap, buildClaudeExecArgs, buildClaudePermissionSettings, buildCleanRoomChildEnv, buildCodexExecArgs, buildPlaywrightMcpCommand, buildWorkerChildEnv, DEFAULT_CODEX_TIMEOUT_MS, DEFAULT_CREATOR_AGENT_TIMEOUT_MS, DEFAULT_CREATOR_UPLOAD_RECOVERY_TIMEOUT_MS, DEFAULT_WORKER_TOKEN_CAP, extractAgentTokenUsage, extractCodexRolloutTokenUsage, extractClaudeSessionId, extractCodexThreadId, extractCodexTokensUsed, readCodexRolloutTokenUsageForThread, readCodexSandboxMode, readEnvBoolean, runLoggedProcess } from './worker/runtime';
8
8
  export type { AgentTokenUsage, LoggedProcessResult, LoggedProcessTranscriptChunk } from './worker/runtime';
9
+ export declare function usesCreatorRecovery(kind: AgentTaskKind): boolean;
10
+ export declare function buildCreatorRecoveryPrompt(input: {
11
+ prompt: string;
12
+ kind: AgentTaskKind;
13
+ }): string;
14
+ export declare function buildGameEvalRetryPrompt(prompt: string): string;
9
15
  export declare const WORKER_SESSION_EXPIRED_MESSAGE = "worker session expired: run \"playdrop auth login\" and start the worker again";
10
16
  export declare const WORKER_CONTEXT_COMMAND_NOT_ALLOWED_MESSAGE = "worker_context_command_not_allowed: inside a PlayDrop worker task only task progress, task claim-slug, task upload/done/fail, assigned app scaffolding, project validation/build/dev/check/capture, read-only help/catalogue/documentation lookup, and PlayDrop AI generation are permitted.";
11
17
  type WorkerStartOptions = {
@@ -76,6 +82,7 @@ type TaskCatalogueReportOptions = {
76
82
  type TaskCompleteOptions = {
77
83
  env?: string;
78
84
  nextSteps?: string;
85
+ platformFeedbackFile?: string;
79
86
  summary?: string;
80
87
  };
81
88
  type TaskClaimSlugOptions = {
@@ -89,6 +96,7 @@ type TaskUploadOptions = {
89
96
  type TaskFailOptions = {
90
97
  env?: string;
91
98
  message?: string;
99
+ platformFeedbackFile?: string;
92
100
  };
93
101
  type TaskEvidenceOptions = {
94
102
  evidenceDir?: string;
@@ -105,6 +113,7 @@ type TaskSubmitReviewOptions = {
105
113
  state?: string;
106
114
  messageFile?: string;
107
115
  creatorFeedbackFile?: string;
116
+ platformFeedbackFile?: string;
108
117
  evidenceDir?: string;
109
118
  nextSteps?: string;
110
119
  };
@@ -166,6 +175,12 @@ export declare function claimBackoffDelayMs(currentMs: number, random?: () => nu
166
175
  export declare function resolveWorkerHomeDir(): string;
167
176
  export declare const WORKER_TASK_WORKSPACE_RETENTION = 20;
168
177
  export declare function pruneWorkerTaskWorkspaces(incomingWorkspaceDir: string, retention?: number): Promise<string[]>;
178
+ export declare function prepareClaimedTaskWorkspace(input: {
179
+ workspaceDir: string;
180
+ attempt: number;
181
+ }): Promise<{
182
+ resumed: boolean;
183
+ }>;
169
184
  export declare function resolveWorkerInstrumentSurface(taskContext: Pick<WorkerTaskContextFile, 'kind' | 'metadata'>): WorkerInstrumentSurface | null;
170
185
  export declare function hasAgentTaskUploadedArtifact(task: Pick<AgentTaskResponse, 'appId' | 'appVersionId'>): boolean;
171
186
  export declare function appendWorkerTranscriptChunks(input: {
@@ -193,11 +208,17 @@ export declare function assertTaskUploadResultMatchesContext(input: {
193
208
  }): void;
194
209
  export declare function stageAssignmentWorkspaceV2(workspaceDir: string, workspace: WorkerTaskAssignmentV2['workspace']): Promise<void>;
195
210
  export declare function assertAssignmentPluginBundleExtractionBounds(buffer: Buffer): void;
211
+ export declare function stageDevPluginWorkingTree(input: {
212
+ workingTree: string;
213
+ workspaceDir: string;
214
+ taskKind?: AgentTaskKind;
215
+ }): Promise<string>;
196
216
  export declare function stageAssignmentPluginBundle(input: {
197
217
  workspaceDir: string;
218
+ extractionDir?: string;
198
219
  pluginBundle: WorkerTaskPluginV2;
199
220
  taskKind?: AgentTaskKind;
200
- }): Promise<string>;
221
+ }): Promise<string | null>;
201
222
  export declare function resolveDevPluginWorkingTree(input: {
202
223
  workingTree?: string;
203
224
  env: string;
@@ -251,6 +272,8 @@ export declare function prepareCodexRunHomes(input: {
251
272
  envName: string;
252
273
  sourceCodexHome?: string;
253
274
  playdropConfig?: ReturnType<typeof loadConfig>;
275
+ stagePlaydropSession?: boolean;
276
+ preserveExisting?: boolean;
254
277
  }): Promise<{
255
278
  homeDir: string;
256
279
  codexHomeDir: string;
@@ -265,6 +288,7 @@ export declare function prepareClaudeRunConfig(input: {
265
288
  }>;
266
289
  export declare function removeAgentRunCredentials(workspaceDir: string): Promise<void>;
267
290
  export declare function removeStaleAgentRunCredentials(workerHomeDir?: string): Promise<void>;
291
+ export declare function mergeCreatorRecoveryResults(runtime: AgentRuntime, initial: LoggedProcessResult, recovery: LoggedProcessResult): LoggedProcessResult;
268
292
  export declare function buildAgentFailureCode(agent: AgentRuntime, result: LoggedProcessResult, request?: {
269
293
  model: string;
270
294
  reasoningEffort?: string | null;
@@ -368,6 +392,7 @@ export declare function enforceInstrumentBrowserHygiene(assignment: WorkerTaskAs
368
392
  remainingTaskTabs: number;
369
393
  blankWindows: number;
370
394
  }>;
395
+ export declare function assignmentRequiresRegisteredBundle(assignment: WorkerTaskAssignmentV2): boolean;
371
396
  export declare function startWorker(options?: WorkerStartOptions): Promise<void>;
372
397
  export declare function reportTask(options: TaskReportOptions): Promise<void>;
373
398
  export declare function showTaskContext(): void;