@playdrop/playdrop-cli 0.12.16 → 0.12.18

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "version": "0.12.8",
3
- "build": 9,
3
+ "build": 11,
4
4
  "runtimeSdkVersion": "0.12.5",
5
5
  "runtimeSdkBuild": 2,
6
6
  "clients": {
@@ -516,9 +516,14 @@ function buildClaudeExecArgs(input) {
516
516
  : input.playwrightMcp
517
517
  ? [...allowedPermissionRules, PLAYWRIGHT_MCP_ALLOWED_TOOL_RULE]
518
518
  : allowedPermissionRules;
519
+ // --safe-mode disables ALL MCP servers, including ones passed explicitly via --mcp-config
520
+ // (verified empirically on claude 2.1.207). Playwright judge sessions therefore drop it:
521
+ // their CLAUDE_CONFIG_DIR is an isolated per-task directory with no user customizations,
522
+ // so the surface --safe-mode guards is already empty, while --strict-mcp-config and the
523
+ // permission rules below stay in force.
519
524
  const args = [
520
525
  '-p',
521
- '--safe-mode',
526
+ ...(input.playwrightMcp ? [] : ['--safe-mode']),
522
527
  '--strict-mcp-config',
523
528
  '--model',
524
529
  model,
@@ -137,6 +137,8 @@ export declare function resolveWorkerClaimTaskAssignment(claim: WorkerClaimAgent
137
137
  export declare function nextClaimBackoffMs(currentMs: number): number;
138
138
  export declare function claimBackoffDelayMs(currentMs: number, random?: () => number): number;
139
139
  export declare function resolveWorkerHomeDir(): string;
140
+ export declare const WORKER_TASK_WORKSPACE_RETENTION = 20;
141
+ export declare function pruneWorkerTaskWorkspaces(incomingWorkspaceDir: string, retention?: number): Promise<string[]>;
140
142
  export declare function hasAgentTaskUploadedArtifact(task: Pick<AgentTaskResponse, 'appId' | 'appVersionId'>): boolean;
141
143
  export declare function appendWorkerTranscriptChunks(input: {
142
144
  client: Pick<ApiClient, 'workerAppendAgentTaskTranscriptChunks'>;
@@ -3,7 +3,7 @@ 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.WORKER_CONTEXT_COMMAND_NOT_ALLOWED_MESSAGE = exports.WORKER_SESSION_EXPIRED_MESSAGE = exports.runLoggedProcess = exports.readEnvBoolean = exports.readCodexSandboxMode = exports.readCodexRolloutTokenUsageForThread = exports.extractCodexTokensUsed = exports.extractCodexThreadId = exports.extractCodexRolloutTokenUsage = exports.extractAgentTokenUsage = exports.DEFAULT_WORKER_TOKEN_CAP = exports.DEFAULT_CODEX_TIMEOUT_MS = exports.buildWorkerChildEnv = exports.buildCodexExecArgs = exports.buildClaudePermissionSettings = exports.buildClaudeExecArgs = exports.assertWorkerTokenUsageWithinCap = void 0;
6
+ exports.WORKER_TASK_WORKSPACE_RETENTION = exports.WORKER_CONTEXT_COMMAND_NOT_ALLOWED_MESSAGE = exports.WORKER_SESSION_EXPIRED_MESSAGE = exports.runLoggedProcess = exports.readEnvBoolean = exports.readCodexSandboxMode = exports.readCodexRolloutTokenUsageForThread = exports.extractCodexTokensUsed = exports.extractCodexThreadId = exports.extractCodexRolloutTokenUsage = exports.extractAgentTokenUsage = exports.DEFAULT_WORKER_TOKEN_CAP = exports.DEFAULT_CODEX_TIMEOUT_MS = exports.buildWorkerChildEnv = exports.buildCodexExecArgs = exports.buildClaudePermissionSettings = exports.buildClaudeExecArgs = exports.assertWorkerTokenUsageWithinCap = void 0;
7
7
  exports.allocateWorkerDevPort = allocateWorkerDevPort;
8
8
  exports.isWorkerContextCommandAllowed = isWorkerContextCommandAllowed;
9
9
  exports.resolveWorkerExecutionTargetFromRole = resolveWorkerExecutionTargetFromRole;
@@ -11,6 +11,7 @@ exports.resolveWorkerClaimTaskAssignment = resolveWorkerClaimTaskAssignment;
11
11
  exports.nextClaimBackoffMs = nextClaimBackoffMs;
12
12
  exports.claimBackoffDelayMs = claimBackoffDelayMs;
13
13
  exports.resolveWorkerHomeDir = resolveWorkerHomeDir;
14
+ exports.pruneWorkerTaskWorkspaces = pruneWorkerTaskWorkspaces;
14
15
  exports.hasAgentTaskUploadedArtifact = hasAgentTaskUploadedArtifact;
15
16
  exports.appendWorkerTranscriptChunks = appendWorkerTranscriptChunks;
16
17
  exports.readTaskNextStepsFile = readTaskNextStepsFile;
@@ -412,6 +413,33 @@ function workerStateFilePath() {
412
413
  function workerTaskWorkspaceDirFromAssignment(assignment) {
413
414
  return node_path_1.default.join(resolveWorkerHomeDir(), 'tasks', assignment.workspace.folderName);
414
415
  }
416
+ exports.WORKER_TASK_WORKSPACE_RETENTION = 20;
417
+ // Task workspaces (including retained failed ones) otherwise grow without bound on a long-lived
418
+ // worker host. Keep only the most recently touched ones; the incoming task's own directory is
419
+ // never a prune candidate.
420
+ async function pruneWorkerTaskWorkspaces(incomingWorkspaceDir, retention = exports.WORKER_TASK_WORKSPACE_RETENTION) {
421
+ const tasksRoot = node_path_1.default.dirname(node_path_1.default.resolve(incomingWorkspaceDir));
422
+ if (!(0, node_fs_1.existsSync)(tasksRoot)) {
423
+ return [];
424
+ }
425
+ const incoming = node_path_1.default.resolve(incomingWorkspaceDir);
426
+ const entries = (0, node_fs_1.readdirSync)(tasksRoot, { withFileTypes: true })
427
+ .filter((entry) => entry.isDirectory())
428
+ .map((entry) => node_path_1.default.join(tasksRoot, entry.name))
429
+ .filter((dir) => dir !== incoming)
430
+ .map((dir) => ({ dir, mtimeMs: (0, node_fs_1.statSync)(dir).mtimeMs }))
431
+ .sort((a, b) => b.mtimeMs - a.mtimeMs);
432
+ const stale = entries.slice(Math.max(0, retention - 1));
433
+ const removed = [];
434
+ for (const entry of stale) {
435
+ await (0, promises_1.rm)(entry.dir, { recursive: true, force: true });
436
+ removed.push(entry.dir);
437
+ }
438
+ if (removed.length > 0) {
439
+ console.error(`pruned ${removed.length} stale task workspace(s), keeping the ${retention} most recent`);
440
+ }
441
+ return removed;
442
+ }
415
443
  function buildWorkerTaskContext(claim, assignment) {
416
444
  const task = claim.task;
417
445
  if (!task) {
@@ -3870,6 +3898,7 @@ async function startWorker(options = {}) {
3870
3898
  reasoningEffort = codexModel?.reasoningEffort ?? claudeModel?.effort ?? null;
3871
3899
  const taskContext = buildWorkerTaskContext(claim, assignment);
3872
3900
  workspaceDir = workerTaskWorkspaceDirFromAssignment(assignment);
3901
+ await pruneWorkerTaskWorkspaces(workspaceDir);
3873
3902
  await (0, promises_1.rm)(workspaceDir, { recursive: true, force: true });
3874
3903
  await (0, promises_1.mkdir)(workspaceDir, { recursive: true });
3875
3904
  const eventDir = node_path_1.default.join(workspaceDir, '.playdrop-task-events');
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "version": "0.12.8",
3
- "build": 9,
3
+ "build": 11,
4
4
  "runtimeSdkVersion": "0.12.5",
5
5
  "runtimeSdkBuild": 2,
6
6
  "clients": {
@@ -28,7 +28,9 @@ export type InstrumentEvidenceManifest = {
28
28
  };
29
29
  export declare const PLAYWRIGHT_MCP_SCREENSHOT_TOOL = "mcp__playwright__browser_take_screenshot";
30
30
  export declare const PLAYWRIGHT_MCP_CONTROLLED_TAB_ID = 1;
31
+ export declare const PLAYWRIGHT_MCP_SCREENSHOT_BUDGET = 100;
31
32
  export declare function isInstrumentScreenshotId(value: string): boolean;
33
+ export declare function normalizePlaywrightScreenshotId(value: unknown): string | null;
32
34
  export declare class ClaudeChromeScreenshotStreamParser {
33
35
  private readonly onScreenshot;
34
36
  private buffer;
@@ -44,9 +46,9 @@ export declare class ClaudeChromeScreenshotStreamParser {
44
46
  export declare class PlaywrightMcpScreenshotStreamParser {
45
47
  private readonly onScreenshot;
46
48
  private buffer;
47
- private readonly pendingScreenshotToolUseIds;
49
+ private readonly pendingScreenshotFilenames;
48
50
  private readonly handledToolUseIds;
49
- private sequence;
51
+ private screenshotCallCount;
50
52
  constructor(onScreenshot: (screenshot: ClaudeChromeScreenshot) => void);
51
53
  push(chunk: string): number;
52
54
  finish(): number;
@@ -1 +1 @@
1
- {"version":3,"file":"instrument-evidence.d.ts","sourceRoot":"","sources":["../src/instrument-evidence.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,yBAAyB,iDAK5B,CAAC;AAEX,MAAM,MAAM,sBAAsB,GAAG,CAAC,OAAO,yBAAyB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEhF,MAAM,MAAM,sBAAsB,GAAG;IACnC,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,YAAY,GAAG,WAAW,CAAC;IACtC,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,yBAAyB,GAAG;IACtC,IAAI,EAAE,sBAAsB,CAAC;IAC7B,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,YAAY,GAAG,WAAW,CAAC;IACtC,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,0BAA0B,GAAG;IACvC,OAAO,EAAE,CAAC,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,eAAe,EAAE,MAAM,CAAC;IACxB,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,sBAAsB,EAAE,yBAAyB,CAAC,CAAC,CAAC;CAC9E,CAAC;AAMF,eAAO,MAAM,8BAA8B,6CAA6C,CAAC;AACzF,eAAO,MAAM,gCAAgC,IAAI,CAAC;AAGlD,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAE/D;AA+CD,qBAAa,kCAAkC;IAKjC,OAAO,CAAC,QAAQ,CAAC,YAAY;IAJzC,OAAO,CAAC,MAAM,CAAM;IACpB,OAAO,CAAC,QAAQ,CAAC,yBAAyB,CAA+B;IACzE,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAqB;gBAE7B,YAAY,EAAE,CAAC,UAAU,EAAE,sBAAsB,KAAK,IAAI;IAEvF,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAqB3B,MAAM,IAAI,MAAM;IAMhB,OAAO,CAAC,WAAW;IA0BnB,OAAO,CAAC,aAAa;IAkBrB,OAAO,CAAC,iBAAiB;CAiE1B;AAMD,qBAAa,mCAAmC;IAMlC,OAAO,CAAC,QAAQ,CAAC,YAAY;IALzC,OAAO,CAAC,MAAM,CAAM;IACpB,OAAO,CAAC,QAAQ,CAAC,2BAA2B,CAAqB;IACjE,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAqB;IACvD,OAAO,CAAC,QAAQ,CAAK;gBAEQ,YAAY,EAAE,CAAC,UAAU,EAAE,sBAAsB,KAAK,IAAI;IAEvF,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAqB3B,MAAM,IAAI,MAAM;IAMhB,OAAO,CAAC,WAAW;IA0BnB,OAAO,CAAC,aAAa;IAcrB,OAAO,CAAC,iBAAiB;CA8C1B"}
1
+ {"version":3,"file":"instrument-evidence.d.ts","sourceRoot":"","sources":["../src/instrument-evidence.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,yBAAyB,iDAK5B,CAAC;AAEX,MAAM,MAAM,sBAAsB,GAAG,CAAC,OAAO,yBAAyB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEhF,MAAM,MAAM,sBAAsB,GAAG;IACnC,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,YAAY,GAAG,WAAW,CAAC;IACtC,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,yBAAyB,GAAG;IACtC,IAAI,EAAE,sBAAsB,CAAC;IAC7B,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,YAAY,GAAG,WAAW,CAAC;IACtC,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,0BAA0B,GAAG;IACvC,OAAO,EAAE,CAAC,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,eAAe,EAAE,MAAM,CAAC;IACxB,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,sBAAsB,EAAE,yBAAyB,CAAC,CAAC,CAAC;CAC9E,CAAC;AAMF,eAAO,MAAM,8BAA8B,6CAA6C,CAAC;AACzF,eAAO,MAAM,gCAAgC,IAAI,CAAC;AAGlD,eAAO,MAAM,gCAAgC,MAAM,CAAC;AAKpD,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAE/D;AAED,wBAAgB,+BAA+B,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAG7E;AA+CD,qBAAa,kCAAkC;IAKjC,OAAO,CAAC,QAAQ,CAAC,YAAY;IAJzC,OAAO,CAAC,MAAM,CAAM;IACpB,OAAO,CAAC,QAAQ,CAAC,yBAAyB,CAA+B;IACzE,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAqB;gBAE7B,YAAY,EAAE,CAAC,UAAU,EAAE,sBAAsB,KAAK,IAAI;IAEvF,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAqB3B,MAAM,IAAI,MAAM;IAMhB,OAAO,CAAC,WAAW;IA0BnB,OAAO,CAAC,aAAa;IAkBrB,OAAO,CAAC,iBAAiB;CAiE1B;AAMD,qBAAa,mCAAmC;IAMlC,OAAO,CAAC,QAAQ,CAAC,YAAY;IALzC,OAAO,CAAC,MAAM,CAAM;IACpB,OAAO,CAAC,QAAQ,CAAC,0BAA0B,CAA6B;IACxE,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAqB;IACvD,OAAO,CAAC,mBAAmB,CAAK;gBAEH,YAAY,EAAE,CAAC,UAAU,EAAE,sBAAsB,KAAK,IAAI;IAEvF,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAqB3B,MAAM,IAAI,MAAM;IAMhB,OAAO,CAAC,WAAW;IA0BnB,OAAO,CAAC,aAAa;IAwBrB,OAAO,CAAC,iBAAiB;CA+C1B"}
@@ -20,9 +20,11 @@ __export(instrument_evidence_exports, {
20
20
  ClaudeChromeScreenshotStreamParser: () => ClaudeChromeScreenshotStreamParser,
21
21
  INSTRUMENT_EVIDENCE_NAMES: () => INSTRUMENT_EVIDENCE_NAMES,
22
22
  PLAYWRIGHT_MCP_CONTROLLED_TAB_ID: () => PLAYWRIGHT_MCP_CONTROLLED_TAB_ID,
23
+ PLAYWRIGHT_MCP_SCREENSHOT_BUDGET: () => PLAYWRIGHT_MCP_SCREENSHOT_BUDGET,
23
24
  PLAYWRIGHT_MCP_SCREENSHOT_TOOL: () => PLAYWRIGHT_MCP_SCREENSHOT_TOOL,
24
25
  PlaywrightMcpScreenshotStreamParser: () => PlaywrightMcpScreenshotStreamParser,
25
- isInstrumentScreenshotId: () => isInstrumentScreenshotId
26
+ isInstrumentScreenshotId: () => isInstrumentScreenshotId,
27
+ normalizePlaywrightScreenshotId: () => normalizePlaywrightScreenshotId
26
28
  });
27
29
  module.exports = __toCommonJS(instrument_evidence_exports);
28
30
  const INSTRUMENT_EVIDENCE_NAMES = [
@@ -36,10 +38,15 @@ const SCREENSHOT_ID_IN_TEXT_PATTERN = /\bID:\s*(ss_[A-Za-z0-9_-]+)\b/g;
36
38
  const MAX_STREAM_LINE_LENGTH = 20 * 1024 * 1024;
37
39
  const PLAYWRIGHT_MCP_SCREENSHOT_TOOL = "mcp__playwright__browser_take_screenshot";
38
40
  const PLAYWRIGHT_MCP_CONTROLLED_TAB_ID = 1;
39
- const PLAYWRIGHT_SCREENSHOT_ID_PATTERN = /^pw-[1-9][0-9]*$/;
41
+ const PLAYWRIGHT_MCP_SCREENSHOT_BUDGET = 100;
42
+ const PLAYWRIGHT_SCREENSHOT_ID_PATTERN = /^[a-z0-9][a-z0-9._-]{0,63}\.(png|jpe?g)$/;
40
43
  function isInstrumentScreenshotId(value) {
41
44
  return SCREENSHOT_ID_PATTERN.test(value) || PLAYWRIGHT_SCREENSHOT_ID_PATTERN.test(value);
42
45
  }
46
+ function normalizePlaywrightScreenshotId(value) {
47
+ const id = typeof value === "string" ? value.trim().toLowerCase() : "";
48
+ return PLAYWRIGHT_SCREENSHOT_ID_PATTERN.test(id) ? id : null;
49
+ }
43
50
  function asRecord(value) {
44
51
  return value && typeof value === "object" && !Array.isArray(value) ? value : null;
45
52
  }
@@ -221,9 +228,9 @@ class ClaudeChromeScreenshotStreamParser {
221
228
  class PlaywrightMcpScreenshotStreamParser {
222
229
  onScreenshot;
223
230
  buffer = "";
224
- pendingScreenshotToolUseIds = /* @__PURE__ */ new Set();
231
+ pendingScreenshotFilenames = /* @__PURE__ */ new Map();
225
232
  handledToolUseIds = /* @__PURE__ */ new Set();
226
- sequence = 0;
233
+ screenshotCallCount = 0;
227
234
  constructor(onScreenshot) {
228
235
  this.onScreenshot = onScreenshot;
229
236
  }
@@ -287,7 +294,16 @@ class PlaywrightMcpScreenshotStreamParser {
287
294
  if (item?.["type"] !== "tool_use" || !id || name !== PLAYWRIGHT_MCP_SCREENSHOT_TOOL) {
288
295
  continue;
289
296
  }
290
- this.pendingScreenshotToolUseIds.add(id);
297
+ this.screenshotCallCount += 1;
298
+ if (this.screenshotCallCount > PLAYWRIGHT_MCP_SCREENSHOT_BUDGET) {
299
+ throw new Error(`playwright_screenshot_budget_exceeded:${PLAYWRIGHT_MCP_SCREENSHOT_BUDGET}`);
300
+ }
301
+ const input = asRecord(item?.["input"]);
302
+ const filename = normalizePlaywrightScreenshotId(input?.["filename"]);
303
+ if (!filename) {
304
+ continue;
305
+ }
306
+ this.pendingScreenshotFilenames.set(id, filename);
291
307
  }
292
308
  }
293
309
  recordToolResults(payload) {
@@ -300,11 +316,12 @@ class PlaywrightMcpScreenshotStreamParser {
300
316
  continue;
301
317
  }
302
318
  const toolUseId = typeof toolResult["tool_use_id"] === "string" ? toolResult["tool_use_id"].trim() : "";
303
- if (!this.pendingScreenshotToolUseIds.has(toolUseId) || this.handledToolUseIds.has(toolUseId)) {
319
+ const screenshotId = this.pendingScreenshotFilenames.get(toolUseId);
320
+ if (!screenshotId || this.handledToolUseIds.has(toolUseId)) {
304
321
  continue;
305
322
  }
306
323
  this.handledToolUseIds.add(toolUseId);
307
- this.pendingScreenshotToolUseIds.delete(toolUseId);
324
+ this.pendingScreenshotFilenames.delete(toolUseId);
308
325
  const resultContent = Array.isArray(toolResult["content"]) ? toolResult["content"] : [];
309
326
  const images = resultContent.map(asRecord).filter((item) => item?.["type"] === "image");
310
327
  if (images.length === 0) {
@@ -319,9 +336,8 @@ class PlaywrightMcpScreenshotStreamParser {
319
336
  if (mediaType !== "image/jpeg" && mediaType !== "image/png" || !dataBase64) {
320
337
  throw new Error(`invalid_playwright_screenshot_payload:${toolUseId}`);
321
338
  }
322
- this.sequence += 1;
323
339
  this.onScreenshot({
324
- screenshotId: `pw-${this.sequence}`,
340
+ screenshotId,
325
341
  tabId: PLAYWRIGHT_MCP_CONTROLLED_TAB_ID,
326
342
  toolUseId,
327
343
  mediaType,
@@ -339,7 +355,9 @@ class PlaywrightMcpScreenshotStreamParser {
339
355
  ClaudeChromeScreenshotStreamParser,
340
356
  INSTRUMENT_EVIDENCE_NAMES,
341
357
  PLAYWRIGHT_MCP_CONTROLLED_TAB_ID,
358
+ PLAYWRIGHT_MCP_SCREENSHOT_BUDGET,
342
359
  PLAYWRIGHT_MCP_SCREENSHOT_TOOL,
343
360
  PlaywrightMcpScreenshotStreamParser,
344
- isInstrumentScreenshotId
361
+ isInstrumentScreenshotId,
362
+ normalizePlaywrightScreenshotId
345
363
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@playdrop/playdrop-cli",
3
- "version": "0.12.16",
3
+ "version": "0.12.18",
4
4
  "description": "Official Playdrop CLI for publishing browser games, creator apps, and AI-generated game assets on playdrop.ai",
5
5
  "homepage": "https://www.playdrop.ai",
6
6
  "repository": {