@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.
- package/config/client-meta.json +2 -2
- package/dist/apps/index.d.ts +2 -0
- package/dist/apps/index.js +2 -1
- package/dist/apps/loadCheck.d.ts +4 -1
- package/dist/apps/loadCheck.js +40 -10
- package/dist/apps/staticHtml.d.ts +28 -0
- package/dist/apps/staticHtml.js +343 -0
- package/dist/apps/validate.js +2 -1
- package/dist/commands/captureListing.d.ts +1 -1
- package/dist/commands/captureListing.js +4 -3
- package/dist/commands/devServer.js +19 -0
- package/dist/commands/feedback.d.ts +2 -0
- package/dist/commands/feedback.js +44 -2
- package/dist/commands/upload.d.ts +24 -0
- package/dist/commands/upload.js +122 -4
- package/dist/commands/worker/instrument-evidence.js +1 -1
- package/dist/commands/worker/runtime.d.ts +15 -0
- package/dist/commands/worker/runtime.js +121 -11
- package/dist/commands/worker.d.ts +28 -2
- package/dist/commands/worker.js +843 -170
- package/dist/index.js +7 -0
- package/dist/listingPreflight.js +15 -4
- package/dist/recorderRelease.d.ts +18 -0
- package/dist/recorderRelease.js +90 -0
- package/node_modules/@playdrop/api-client/dist/client.d.ts +5 -2
- package/node_modules/@playdrop/api-client/dist/client.d.ts.map +1 -1
- package/node_modules/@playdrop/api-client/dist/domains/agent-tasks.d.ts +3 -2
- package/node_modules/@playdrop/api-client/dist/domains/agent-tasks.d.ts.map +1 -1
- package/node_modules/@playdrop/api-client/dist/domains/agent-tasks.js +13 -2
- package/node_modules/@playdrop/api-client/dist/domains/apps.d.ts +2 -1
- package/node_modules/@playdrop/api-client/dist/domains/apps.d.ts.map +1 -1
- package/node_modules/@playdrop/api-client/dist/domains/me.d.ts +2 -1
- package/node_modules/@playdrop/api-client/dist/domains/me.d.ts.map +1 -1
- package/node_modules/@playdrop/api-client/dist/domains/me.js +11 -0
- package/node_modules/@playdrop/api-client/dist/index.d.ts +6 -3
- package/node_modules/@playdrop/api-client/dist/index.d.ts.map +1 -1
- package/node_modules/@playdrop/api-client/dist/index.js +14 -2
- package/node_modules/@playdrop/config/client-meta.json +2 -2
- package/node_modules/@playdrop/config/dist/src/constants.d.ts +1 -0
- package/node_modules/@playdrop/config/dist/src/constants.d.ts.map +1 -1
- package/node_modules/@playdrop/config/dist/src/constants.js +1 -0
- package/node_modules/@playdrop/config/dist/tsconfig.tsbuildinfo +1 -1
- package/node_modules/@playdrop/types/dist/api.d.ts +195 -4
- package/node_modules/@playdrop/types/dist/api.d.ts.map +1 -1
- package/node_modules/@playdrop/types/dist/api.js +25 -2
- package/node_modules/entities/decode-codepoint.d.ts +19 -0
- package/node_modules/entities/decode-codepoint.d.ts.map +1 -0
- package/node_modules/entities/decode-codepoint.js +77 -0
- package/node_modules/entities/decode-codepoint.js.map +1 -0
- package/node_modules/entities/decode.d.ts +209 -0
- package/node_modules/entities/decode.d.ts.map +1 -0
- package/node_modules/entities/decode.js +511 -0
- package/node_modules/entities/decode.js.map +1 -0
- package/node_modules/entities/encode.d.ts +22 -0
- package/node_modules/entities/encode.d.ts.map +1 -0
- package/node_modules/entities/encode.js +73 -0
- package/node_modules/entities/encode.js.map +1 -0
- package/node_modules/entities/escape.d.ts +43 -0
- package/node_modules/entities/escape.d.ts.map +1 -0
- package/node_modules/entities/escape.js +121 -0
- package/node_modules/entities/escape.js.map +1 -0
- package/node_modules/entities/generated/decode-data-html.d.ts +2 -0
- package/node_modules/entities/generated/decode-data-html.d.ts.map +1 -0
- package/node_modules/entities/generated/decode-data-html.js +10 -0
- package/node_modules/entities/generated/decode-data-html.js.map +1 -0
- package/node_modules/entities/generated/decode-data-xml.d.ts +2 -0
- package/node_modules/entities/generated/decode-data-xml.d.ts.map +1 -0
- package/node_modules/entities/generated/decode-data-xml.js +10 -0
- package/node_modules/entities/generated/decode-data-xml.js.map +1 -0
- package/node_modules/entities/generated/encode-html.d.ts +8 -0
- package/node_modules/entities/generated/encode-html.d.ts.map +1 -0
- package/node_modules/entities/generated/encode-html.js +13 -0
- package/node_modules/entities/generated/encode-html.js.map +1 -0
- package/node_modules/entities/index.d.ts +96 -0
- package/node_modules/entities/index.d.ts.map +1 -0
- package/node_modules/entities/index.js +131 -0
- package/node_modules/entities/index.js.map +1 -0
- package/node_modules/entities/package.json +3 -0
- package/node_modules/parse5/common/doctype.d.ts +4 -0
- package/node_modules/parse5/common/doctype.js +118 -0
- package/node_modules/parse5/common/error-codes.d.ts +67 -0
- package/node_modules/parse5/common/error-codes.js +66 -0
- package/node_modules/parse5/common/foreign-content.d.ts +9 -0
- package/node_modules/parse5/common/foreign-content.js +237 -0
- package/node_modules/parse5/common/html.d.ts +289 -0
- package/node_modules/parse5/common/html.js +528 -0
- package/node_modules/parse5/common/token.d.ts +84 -0
- package/node_modules/parse5/common/token.js +24 -0
- package/node_modules/parse5/common/unicode.d.ts +42 -0
- package/node_modules/parse5/common/unicode.js +70 -0
- package/node_modules/parse5/index.d.ts +71 -0
- package/node_modules/parse5/index.js +54 -0
- package/node_modules/parse5/package.json +1 -0
- package/node_modules/parse5/parser/formatting-element-list.d.ts +36 -0
- package/node_modules/parse5/parser/formatting-element-list.js +114 -0
- package/node_modules/parse5/parser/index.d.ts +221 -0
- package/node_modules/parse5/parser/index.js +3240 -0
- package/node_modules/parse5/parser/open-element-stack.d.ts +53 -0
- package/node_modules/parse5/parser/open-element-stack.js +328 -0
- package/node_modules/parse5/serializer/index.d.ts +60 -0
- package/node_modules/parse5/serializer/index.js +172 -0
- package/node_modules/parse5/tokenizer/index.d.ts +247 -0
- package/node_modules/parse5/tokenizer/index.js +2714 -0
- package/node_modules/parse5/tokenizer/preprocessor.d.ts +36 -0
- package/node_modules/parse5/tokenizer/preprocessor.js +200 -0
- package/node_modules/parse5/tree-adapters/default.d.ts +84 -0
- package/node_modules/parse5/tree-adapters/default.js +176 -0
- package/node_modules/parse5/tree-adapters/interface.d.ts +255 -0
- package/node_modules/parse5/tree-adapters/interface.js +2 -0
- 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.
|
|
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.
|
|
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>;
|
package/dist/commands/upload.js
CHANGED
|
@@ -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
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
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:
|
|
719
|
+
command: process.execPath,
|
|
656
720
|
args: [
|
|
657
|
-
|
|
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
|
+
}
|