@playdrop/playdrop-cli 0.12.42 → 0.13.1

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 (110) hide show
  1. package/config/client-meta.json +2 -2
  2. package/dist/apps/index.d.ts +2 -0
  3. package/dist/apps/index.js +2 -1
  4. package/dist/apps/loadCheck.d.ts +4 -1
  5. package/dist/apps/loadCheck.js +40 -10
  6. package/dist/apps/staticHtml.d.ts +28 -0
  7. package/dist/apps/staticHtml.js +343 -0
  8. package/dist/apps/validate.js +2 -1
  9. package/dist/commands/captureListing.d.ts +1 -1
  10. package/dist/commands/captureListing.js +4 -3
  11. package/dist/commands/devServer.js +19 -0
  12. package/dist/commands/feedback.d.ts +2 -0
  13. package/dist/commands/feedback.js +44 -2
  14. package/dist/commands/upload.d.ts +24 -0
  15. package/dist/commands/upload.js +122 -4
  16. package/dist/commands/worker/instrument-evidence.js +1 -1
  17. package/dist/commands/worker/runtime.d.ts +15 -0
  18. package/dist/commands/worker/runtime.js +121 -11
  19. package/dist/commands/worker.d.ts +28 -2
  20. package/dist/commands/worker.js +843 -170
  21. package/dist/index.js +7 -0
  22. package/dist/listingPreflight.js +15 -4
  23. package/dist/recorderRelease.d.ts +18 -0
  24. package/dist/recorderRelease.js +90 -0
  25. package/node_modules/@playdrop/api-client/dist/client.d.ts +5 -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 +2 -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/me.d.ts +2 -1
  33. package/node_modules/@playdrop/api-client/dist/domains/me.d.ts.map +1 -1
  34. package/node_modules/@playdrop/api-client/dist/domains/me.js +11 -0
  35. package/node_modules/@playdrop/api-client/dist/index.d.ts +6 -3
  36. package/node_modules/@playdrop/api-client/dist/index.d.ts.map +1 -1
  37. package/node_modules/@playdrop/api-client/dist/index.js +14 -2
  38. package/node_modules/@playdrop/config/client-meta.json +2 -2
  39. package/node_modules/@playdrop/config/dist/src/constants.d.ts +1 -0
  40. package/node_modules/@playdrop/config/dist/src/constants.d.ts.map +1 -1
  41. package/node_modules/@playdrop/config/dist/src/constants.js +1 -0
  42. package/node_modules/@playdrop/config/dist/tsconfig.tsbuildinfo +1 -1
  43. package/node_modules/@playdrop/types/dist/api.d.ts +195 -4
  44. package/node_modules/@playdrop/types/dist/api.d.ts.map +1 -1
  45. package/node_modules/@playdrop/types/dist/api.js +25 -2
  46. package/node_modules/entities/decode-codepoint.d.ts +19 -0
  47. package/node_modules/entities/decode-codepoint.d.ts.map +1 -0
  48. package/node_modules/entities/decode-codepoint.js +77 -0
  49. package/node_modules/entities/decode-codepoint.js.map +1 -0
  50. package/node_modules/entities/decode.d.ts +209 -0
  51. package/node_modules/entities/decode.d.ts.map +1 -0
  52. package/node_modules/entities/decode.js +511 -0
  53. package/node_modules/entities/decode.js.map +1 -0
  54. package/node_modules/entities/encode.d.ts +22 -0
  55. package/node_modules/entities/encode.d.ts.map +1 -0
  56. package/node_modules/entities/encode.js +73 -0
  57. package/node_modules/entities/encode.js.map +1 -0
  58. package/node_modules/entities/escape.d.ts +43 -0
  59. package/node_modules/entities/escape.d.ts.map +1 -0
  60. package/node_modules/entities/escape.js +121 -0
  61. package/node_modules/entities/escape.js.map +1 -0
  62. package/node_modules/entities/generated/decode-data-html.d.ts +2 -0
  63. package/node_modules/entities/generated/decode-data-html.d.ts.map +1 -0
  64. package/node_modules/entities/generated/decode-data-html.js +10 -0
  65. package/node_modules/entities/generated/decode-data-html.js.map +1 -0
  66. package/node_modules/entities/generated/decode-data-xml.d.ts +2 -0
  67. package/node_modules/entities/generated/decode-data-xml.d.ts.map +1 -0
  68. package/node_modules/entities/generated/decode-data-xml.js +10 -0
  69. package/node_modules/entities/generated/decode-data-xml.js.map +1 -0
  70. package/node_modules/entities/generated/encode-html.d.ts +8 -0
  71. package/node_modules/entities/generated/encode-html.d.ts.map +1 -0
  72. package/node_modules/entities/generated/encode-html.js +13 -0
  73. package/node_modules/entities/generated/encode-html.js.map +1 -0
  74. package/node_modules/entities/index.d.ts +96 -0
  75. package/node_modules/entities/index.d.ts.map +1 -0
  76. package/node_modules/entities/index.js +131 -0
  77. package/node_modules/entities/index.js.map +1 -0
  78. package/node_modules/entities/package.json +3 -0
  79. package/node_modules/parse5/common/doctype.d.ts +4 -0
  80. package/node_modules/parse5/common/doctype.js +118 -0
  81. package/node_modules/parse5/common/error-codes.d.ts +67 -0
  82. package/node_modules/parse5/common/error-codes.js +66 -0
  83. package/node_modules/parse5/common/foreign-content.d.ts +9 -0
  84. package/node_modules/parse5/common/foreign-content.js +237 -0
  85. package/node_modules/parse5/common/html.d.ts +289 -0
  86. package/node_modules/parse5/common/html.js +528 -0
  87. package/node_modules/parse5/common/token.d.ts +84 -0
  88. package/node_modules/parse5/common/token.js +24 -0
  89. package/node_modules/parse5/common/unicode.d.ts +42 -0
  90. package/node_modules/parse5/common/unicode.js +70 -0
  91. package/node_modules/parse5/index.d.ts +71 -0
  92. package/node_modules/parse5/index.js +54 -0
  93. package/node_modules/parse5/package.json +1 -0
  94. package/node_modules/parse5/parser/formatting-element-list.d.ts +36 -0
  95. package/node_modules/parse5/parser/formatting-element-list.js +114 -0
  96. package/node_modules/parse5/parser/index.d.ts +221 -0
  97. package/node_modules/parse5/parser/index.js +3240 -0
  98. package/node_modules/parse5/parser/open-element-stack.d.ts +53 -0
  99. package/node_modules/parse5/parser/open-element-stack.js +328 -0
  100. package/node_modules/parse5/serializer/index.d.ts +60 -0
  101. package/node_modules/parse5/serializer/index.js +172 -0
  102. package/node_modules/parse5/tokenizer/index.d.ts +247 -0
  103. package/node_modules/parse5/tokenizer/index.js +2714 -0
  104. package/node_modules/parse5/tokenizer/preprocessor.d.ts +36 -0
  105. package/node_modules/parse5/tokenizer/preprocessor.js +200 -0
  106. package/node_modules/parse5/tree-adapters/default.d.ts +84 -0
  107. package/node_modules/parse5/tree-adapters/default.js +176 -0
  108. package/node_modules/parse5/tree-adapters/interface.d.ts +255 -0
  109. package/node_modules/parse5/tree-adapters/interface.js +2 -0
  110. package/package.json +8 -1
@@ -16,7 +16,7 @@ const output_1 = require("../output");
16
16
  const clientInfo_1 = require("../clientInfo");
17
17
  const MAX_FEEDBACK_TITLE_LENGTH = 70;
18
18
  const MAX_FEEDBACK_COMMENT_LENGTH = 10000;
19
- const FEEDBACK_CATEGORY_SET = new Set(types_1.FEEDBACK_CATEGORY_VALUES);
19
+ const FEEDBACK_CATEGORY_SET = new Set(types_1.MANUAL_FEEDBACK_CATEGORY_VALUES);
20
20
  function parsePositiveInteger(raw, label, command, options = {}) {
21
21
  if (raw === undefined) {
22
22
  return null;
@@ -32,7 +32,7 @@ function parsePositiveInteger(raw, label, command, options = {}) {
32
32
  function parseFeedbackCategory(raw, command) {
33
33
  const normalized = typeof raw === 'string' && raw.trim().length > 0 ? raw.trim() : 'other';
34
34
  if (!FEEDBACK_CATEGORY_SET.has(normalized)) {
35
- (0, messages_1.printErrorWithHelp)(`Feedback category must be one of: ${types_1.FEEDBACK_CATEGORY_VALUES.join(', ')}.`, [], { command });
35
+ (0, messages_1.printErrorWithHelp)(`Feedback category must be one of: ${types_1.MANUAL_FEEDBACK_CATEGORY_VALUES.join(', ')}.`, [], { command });
36
36
  process.exitCode = 1;
37
37
  return null;
38
38
  }
@@ -137,8 +137,50 @@ async function browseFeedback(options = {}) {
137
137
  process.exitCode = 1;
138
138
  return;
139
139
  }
140
+ const sinceHours = options.sinceHours !== undefined
141
+ ? parsePositiveInteger(options.sinceHours, '--since-hours', 'feedback browse')
142
+ : null;
143
+ if (options.sinceHours !== undefined && sinceHours === null) {
144
+ return;
145
+ }
140
146
  await (0, commandContext_1.withEnvironment)('feedback browse', 'Browsing feedback', async ({ client }) => {
141
147
  try {
148
+ if (options.admin) {
149
+ const cutoff = sinceHours === null ? null : Date.now() - sinceHours * 60 * 60 * 1000;
150
+ const items = [];
151
+ let nextOffset = offset ?? 0;
152
+ let hasMore = true;
153
+ while (hasMore && (limit === null || items.length < limit)) {
154
+ const page = await client.fetchAdminFeedback({ limit: 100, offset: nextOffset });
155
+ for (const item of page.feedback ?? []) {
156
+ if (cutoff !== null && new Date(item.createdAt).getTime() < cutoff) {
157
+ hasMore = false;
158
+ break;
159
+ }
160
+ items.push(item);
161
+ if (limit !== null && items.length >= limit) {
162
+ break;
163
+ }
164
+ }
165
+ nextOffset += page.feedback?.length ?? 0;
166
+ hasMore = hasMore && Boolean(page.pagination?.hasMore) && (page.feedback?.length ?? 0) > 0;
167
+ }
168
+ if (options.json) {
169
+ (0, output_1.printJson)({ items, sinceHours, count: items.length });
170
+ return;
171
+ }
172
+ if (items.length === 0) {
173
+ console.log('No feedback entries found.');
174
+ return;
175
+ }
176
+ console.log('Feedback:\n');
177
+ for (const item of items) {
178
+ console.log(`#${item.id} | ${item.category} | ${item.client} | ${(0, output_1.formatTimestamp)(item.createdAt)}`);
179
+ console.log(` ${item.title}`);
180
+ console.log(` ${item.comment}`);
181
+ }
182
+ return;
183
+ }
142
184
  const response = await client.listFeedback({
143
185
  limit: limit ?? undefined,
144
186
  offset: offset ?? undefined,
@@ -5,6 +5,7 @@ export type UploadCommandOptions = {
5
5
  env?: string;
6
6
  skipReview?: boolean;
7
7
  clearTags?: boolean;
8
+ json?: boolean;
8
9
  };
9
10
  export declare function resolveUploadOwner(actorUsername: string | null | undefined, workspaceOwnerUsername: string | null | undefined): string;
10
11
  export declare function resolveDefaultUploadCreator(owner: string | null | undefined, actorUsername: string | null | undefined): string;
@@ -35,6 +36,28 @@ export type WorkerAppPublishResult = {
35
36
  creatorUsername: string;
36
37
  warnings: string[];
37
38
  };
39
+ export type StaticHtmlPublishInput = {
40
+ client: ApiClient;
41
+ projectDir: string;
42
+ creatorUsername: string;
43
+ primarySurface: 'DESKTOP' | 'MOBILE_LANDSCAPE' | 'MOBILE_PORTRAIT';
44
+ apiBase: string;
45
+ webBase?: string | null;
46
+ token: string;
47
+ user: UserResponse;
48
+ taskId?: number;
49
+ taskToken?: string;
50
+ claimedAppName?: string | null;
51
+ devRouterPort?: number;
52
+ };
53
+ export type StaticHtmlPublishResult = WorkerAppPublishResult & {
54
+ sourceHash: string;
55
+ runtimeHash: string;
56
+ playUrl: string;
57
+ sourceContainsInjectedSdk: false;
58
+ runtimeContainsInjectedSdk: true;
59
+ hostedLoadCheckPassed: true;
60
+ };
38
61
  export type WorkerPlaydropAssetRequirement = 'PACK' | 'ASSET_OR_PACK';
39
62
  export declare function resolveWorkerPlaydropAssetRequirement(value: unknown): WorkerPlaydropAssetRequirement | null;
40
63
  export declare function assertAgentNewGamePlaytestContract(task: AppTask): void;
@@ -50,3 +73,4 @@ export declare function assertWorkerAppLocalUploadPreflight(input: {
50
73
  creatorRequest?: string | null;
51
74
  }): Promise<AgentTaskPlaytestProof | null>;
52
75
  export declare function publishWorkerAppProject(input: WorkerAppPublishInput): Promise<WorkerAppPublishResult>;
76
+ export declare function publishStaticHtmlProject(input: StaticHtmlPublishInput): Promise<StaticHtmlPublishResult>;
@@ -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) => ({
@@ -2054,3 +2087,88 @@ async function publishWorkerAppProject(input) {
2054
2087
  warnings: [...selection.warnings, ...warnings],
2055
2088
  };
2056
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,9 +80,12 @@ 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';
88
+ export declare function resolvePlaywrightMcpCliPath(): string;
81
89
  export declare function buildPlaywrightMcpCommand(surface?: WorkerInstrumentSurface | null): {
82
90
  command: string;
83
91
  args: string[];
@@ -86,6 +94,7 @@ export declare function buildPlaywrightMcpServerConfig(surface?: WorkerInstrumen
86
94
  export declare function buildClaudePermissionSettings(input?: {
87
95
  workspaceDir?: string | null;
88
96
  denyReadRoots?: string[];
97
+ playdropCliEnabled?: boolean;
89
98
  }): {
90
99
  permissions: {
91
100
  allow: string[];
@@ -108,3 +117,9 @@ export declare function buildWorkerChildEnv(input: {
108
117
  playwrightBrowsersPath?: string;
109
118
  baseEnv?: NodeJS.ProcessEnv;
110
119
  }): NodeJS.ProcessEnv;
120
+ export declare function buildCleanRoomChildEnv(input: {
121
+ binDir: string;
122
+ homeDir?: string;
123
+ codexHomeDir?: string;
124
+ baseEnv?: NodeJS.ProcessEnv;
125
+ }): 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;
@@ -17,18 +18,24 @@ exports.runLoggedProcess = runLoggedProcess;
17
18
  exports.buildCodexExecArgs = buildCodexExecArgs;
18
19
  exports.readCodexSandboxMode = readCodexSandboxMode;
19
20
  exports.buildClaudeExecArgs = buildClaudeExecArgs;
21
+ exports.resolvePlaywrightMcpCliPath = resolvePlaywrightMcpCliPath;
20
22
  exports.buildPlaywrightMcpCommand = buildPlaywrightMcpCommand;
21
23
  exports.buildPlaywrightMcpServerConfig = buildPlaywrightMcpServerConfig;
22
24
  exports.buildClaudePermissionSettings = buildClaudePermissionSettings;
23
25
  exports.buildClaudeDeniedPermissionRules = buildClaudeDeniedPermissionRules;
24
26
  exports.buildWorkerChildEnv = buildWorkerChildEnv;
27
+ exports.buildCleanRoomChildEnv = buildCleanRoomChildEnv;
25
28
  const node_child_process_1 = require("node:child_process");
29
+ const node_fs_1 = require("node:fs");
26
30
  const promises_1 = require("node:fs/promises");
31
+ const node_module_1 = require("node:module");
27
32
  const node_os_1 = __importDefault(require("node:os"));
28
33
  const node_path_1 = __importDefault(require("node:path"));
29
34
  const surfaceProfiles_1 = require("../../apps/surfaceProfiles");
30
35
  const CHILD_KILL_GRACE_MS = 10000;
31
36
  exports.DEFAULT_CODEX_TIMEOUT_MS = 2 * 60 * 60 * 1000;
37
+ exports.DEFAULT_CREATOR_AGENT_TIMEOUT_MS = 60 * 60 * 1000;
38
+ exports.DEFAULT_CREATOR_UPLOAD_RECOVERY_TIMEOUT_MS = 30 * 60 * 1000;
32
39
  exports.DEFAULT_WORKER_TOKEN_CAP = 20000000;
33
40
  exports.DEFAULT_CODEX_LOG_TAIL_CHARS = 12000;
34
41
  exports.DEFAULT_TRANSCRIPT_FLUSH_INTERVAL_MS = 10000;
@@ -296,6 +303,25 @@ function extractCodexThreadId(output) {
296
303
  }
297
304
  return null;
298
305
  }
306
+ function extractClaudeSessionId(output) {
307
+ for (const line of output.split(/\r?\n/)) {
308
+ const trimmed = line.trim();
309
+ if (!trimmed.startsWith('{') || !trimmed.endsWith('}')) {
310
+ continue;
311
+ }
312
+ try {
313
+ const root = coerceRecord(JSON.parse(trimmed));
314
+ const rawSessionId = root?.session_id ?? root?.sessionId;
315
+ if (typeof rawSessionId === 'string' && rawSessionId.trim()) {
316
+ return rawSessionId.trim();
317
+ }
318
+ }
319
+ catch {
320
+ continue;
321
+ }
322
+ }
323
+ return null;
324
+ }
299
325
  async function findCodexRolloutFileForThread(threadId, sessionsRoot) {
300
326
  const stack = [{ dir: sessionsRoot, depth: 0 }];
301
327
  const matches = [];
@@ -531,10 +557,24 @@ async function runLoggedProcess(input) {
531
557
  }
532
558
  function buildCodexExecArgs(input) {
533
559
  const sandboxMode = input.sandboxMode ?? 'danger-full-access';
560
+ const resumeSessionId = input.resumeSessionId?.trim() ?? '';
561
+ if (resumeSessionId) {
562
+ return [
563
+ 'exec',
564
+ 'resume',
565
+ '--json',
566
+ '--skip-git-repo-check',
567
+ '--model',
568
+ input.model,
569
+ '-c',
570
+ `model_reasoning_effort="${input.reasoningEffort}"`,
571
+ resumeSessionId,
572
+ '-',
573
+ ];
574
+ }
534
575
  const args = [
535
576
  'exec',
536
577
  '--json',
537
- '--ephemeral',
538
578
  '--sandbox',
539
579
  sandboxMode,
540
580
  '--cd',
@@ -581,6 +621,7 @@ function buildClaudeExecArgs(input) {
581
621
  const permissionSettings = buildClaudePermissionSettings({
582
622
  workspaceDir: input.workspaceDir,
583
623
  denyReadRoots: input.denyReadRoots ?? [],
624
+ playdropCliEnabled: input.playdropCliEnabled,
584
625
  });
585
626
  const permissionMode = input.chrome || input.playwrightMcp ? 'bypassPermissions' : 'acceptEdits';
586
627
  // MCP tools are deferred behind ToolSearch in the Claude CLI; without it in the toolset a
@@ -590,7 +631,7 @@ function buildClaudeExecArgs(input) {
590
631
  : input.playwrightMcp
591
632
  ? [...CLAUDE_BASE_TOOL_NAMES, 'ToolSearch'].join(',')
592
633
  : CLAUDE_BASE_TOOL_NAMES.join(',');
593
- const allowedPermissionRules = buildClaudeAllowedPermissionRules(input.workspaceDir);
634
+ const allowedPermissionRules = buildClaudeAllowedPermissionRules(input.workspaceDir, input.playdropCliEnabled);
594
635
  const allowedTools = input.chrome
595
636
  ? [...allowedPermissionRules, ...CLAUDE_CHROME_TOOL_NAMES]
596
637
  : input.playwrightMcp
@@ -609,7 +650,6 @@ function buildClaudeExecArgs(input) {
609
650
  'stream-json',
610
651
  '--verbose',
611
652
  '--include-partial-messages',
612
- '--no-session-persistence',
613
653
  '--permission-mode',
614
654
  permissionMode,
615
655
  '--tools',
@@ -635,6 +675,10 @@ function buildClaudeExecArgs(input) {
635
675
  if (effort) {
636
676
  args.push('--effort', effort);
637
677
  }
678
+ const resumeSessionId = input.resumeSessionId?.trim() ?? '';
679
+ if (resumeSessionId) {
680
+ args.push('--resume', resumeSessionId);
681
+ }
638
682
  return args;
639
683
  }
640
684
  const CLAUDE_BASE_TOOL_NAMES = [
@@ -649,13 +693,32 @@ const CLAUDE_BASE_TOOL_NAMES = [
649
693
  // never through @latest drift (see the 2026-07-13 auto-update incident).
650
694
  exports.PLAYWRIGHT_MCP_VERSION = '0.0.78';
651
695
  const PLAYWRIGHT_MCP_ALLOWED_TOOL_RULE = 'mcp__playwright';
696
+ const requireFromWorkerRuntime = (0, node_module_1.createRequire)(__filename);
697
+ function resolvePlaywrightMcpCliPath() {
698
+ let packageJsonPath;
699
+ let packageJson;
700
+ try {
701
+ packageJsonPath = requireFromWorkerRuntime.resolve('@playwright/mcp/package.json');
702
+ packageJson = requireFromWorkerRuntime('@playwright/mcp/package.json');
703
+ }
704
+ catch {
705
+ throw new Error(`worker_preflight_playwright_mcp_missing:@playwright/mcp@${exports.PLAYWRIGHT_MCP_VERSION}`);
706
+ }
707
+ if (packageJson.version !== exports.PLAYWRIGHT_MCP_VERSION) {
708
+ throw new Error(`worker_preflight_playwright_mcp_version:expected=${exports.PLAYWRIGHT_MCP_VERSION}:actual=${packageJson.version ?? 'missing'}`);
709
+ }
710
+ const cliPath = node_path_1.default.join(node_path_1.default.dirname(packageJsonPath), 'cli.js');
711
+ if (!(0, node_fs_1.existsSync)(cliPath)) {
712
+ throw new Error(`worker_preflight_playwright_mcp_missing:${cliPath}`);
713
+ }
714
+ return cliPath;
715
+ }
652
716
  function buildPlaywrightMcpCommand(surface) {
653
717
  const surfaceArgs = surface ? (0, surfaceProfiles_1.buildPlaywrightMcpSurfaceArgs)(surface) : [];
654
718
  return {
655
- command: 'npx',
719
+ command: process.execPath,
656
720
  args: [
657
- '-y',
658
- `@playwright/mcp@${exports.PLAYWRIGHT_MCP_VERSION}`,
721
+ resolvePlaywrightMcpCliPath(),
659
722
  '--browser',
660
723
  'chrome',
661
724
  '--isolated',
@@ -702,6 +765,7 @@ const CLAUDE_BUILD_PERMISSION_RULES = [
702
765
  'Grep',
703
766
  'Bash(playdrop *)',
704
767
  'Bash(./bin/playdrop *)',
768
+ 'Bash(../bin/playdrop *)',
705
769
  'Bash(bin/playdrop *)',
706
770
  'Bash(node *)',
707
771
  'Bash(npm *)',
@@ -709,6 +773,7 @@ const CLAUDE_BUILD_PERMISSION_RULES = [
709
773
  'Bash(cp *)',
710
774
  'Bash(mv *)',
711
775
  'Bash(file *)',
776
+ 'Bash(curl *)',
712
777
  'Bash(sips *)',
713
778
  'Bash(ls *)',
714
779
  'Bash(pwd)',
@@ -731,7 +796,7 @@ function normalizeClaudePermissionPath(value) {
731
796
  }
732
797
  return node_path_1.default.resolve(trimmed).replace(/\\/g, '/').replace(/\/+$/, '');
733
798
  }
734
- function buildClaudeAllowedPermissionRules(workspaceDir) {
799
+ function buildClaudeAllowedPermissionRules(workspaceDir, playdropCliEnabled = true) {
735
800
  const workspaceRoot = typeof workspaceDir === 'string' && workspaceDir.trim()
736
801
  ? normalizeClaudePermissionPath(workspaceDir)
737
802
  : null;
@@ -743,14 +808,14 @@ function buildClaudeAllowedPermissionRules(workspaceDir) {
743
808
  `Read(${absoluteWorkspacePattern})`,
744
809
  `Edit(${absoluteWorkspacePattern})`,
745
810
  `Write(${absoluteWorkspacePattern})`,
746
- `Bash(${workspaceRoot}/bin/playdrop *)`,
747
- ...CLAUDE_BUILD_PERMISSION_RULES,
811
+ ...(playdropCliEnabled ? [`Bash(${workspaceRoot}/bin/playdrop *)`] : []),
812
+ ...CLAUDE_BUILD_PERMISSION_RULES.filter((rule) => (playdropCliEnabled || !rule.toLowerCase().includes('playdrop'))),
748
813
  ];
749
814
  }
750
815
  function buildClaudePermissionSettings(input = {}) {
751
816
  return {
752
817
  permissions: {
753
- allow: buildClaudeAllowedPermissionRules(input.workspaceDir),
818
+ allow: buildClaudeAllowedPermissionRules(input.workspaceDir, input.playdropCliEnabled),
754
819
  deny: buildClaudeDeniedPermissionRules(input.denyReadRoots ?? []),
755
820
  },
756
821
  };
@@ -860,3 +925,48 @@ function buildWorkerChildEnv(input) {
860
925
  }
861
926
  return child;
862
927
  }
928
+ function buildCleanRoomChildEnv(input) {
929
+ const base = input.baseEnv ?? process.env;
930
+ const child = {};
931
+ for (const key of [
932
+ 'HOME',
933
+ 'USER',
934
+ 'SHELL',
935
+ 'TMPDIR',
936
+ 'LANG',
937
+ 'TERM',
938
+ 'ANTHROPIC_API_KEY',
939
+ 'OPENAI_API_KEY',
940
+ 'HTTP_PROXY',
941
+ 'HTTPS_PROXY',
942
+ 'ALL_PROXY',
943
+ 'NO_PROXY',
944
+ ]) {
945
+ const value = base[key];
946
+ if (typeof value === 'string')
947
+ child[key] = value;
948
+ }
949
+ for (const [key, value] of Object.entries(base)) {
950
+ if (key.startsWith('LC_') && typeof value === 'string')
951
+ child[key] = value;
952
+ }
953
+ if (input.homeDir !== undefined) {
954
+ const homeDir = input.homeDir.trim();
955
+ if (!homeDir || !node_path_1.default.isAbsolute(homeDir))
956
+ throw new Error('invalid_worker_child_home_dir');
957
+ child.HOME = homeDir;
958
+ }
959
+ if (input.codexHomeDir !== undefined) {
960
+ const codexHomeDir = input.codexHomeDir.trim();
961
+ if (!codexHomeDir || !node_path_1.default.isAbsolute(codexHomeDir))
962
+ throw new Error('invalid_worker_child_codex_home_dir');
963
+ child.CODEX_HOME = codexHomeDir;
964
+ }
965
+ const safeHostPath = (base.PATH ?? '').split(node_path_1.default.delimiter).filter((directory) => {
966
+ if (!directory || !node_path_1.default.isAbsolute(directory))
967
+ return false;
968
+ return !(0, node_fs_1.existsSync)(node_path_1.default.join(directory, process.platform === 'win32' ? 'playdrop.exe' : 'playdrop'));
969
+ });
970
+ child.PATH = [input.binDir, ...safeHostPath].join(node_path_1.default.delimiter);
971
+ return child;
972
+ }