@playdrop/playdrop-cli 0.12.14 → 0.12.16

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": 6,
3
+ "build": 9,
4
4
  "runtimeSdkVersion": "0.12.5",
5
5
  "runtimeSdkBuild": 2,
6
6
  "clients": {
@@ -66,7 +66,7 @@ function extensionForMediaType(mediaType) {
66
66
  }
67
67
  function createWorkerInstrumentScreenshotCollector(workspaceDir) {
68
68
  const resolvedWorkspace = node_path_1.default.resolve(workspaceDir);
69
- const parser = new types_1.ClaudeChromeScreenshotStreamParser((screenshot) => {
69
+ const store = (screenshot) => {
70
70
  const buffer = Buffer.from(screenshot.dataBase64, 'base64');
71
71
  if (buffer.length <= 0) {
72
72
  throw new Error(`invalid_claude_screenshot_payload:${screenshot.screenshotId}`);
@@ -89,10 +89,14 @@ function createWorkerInstrumentScreenshotCollector(workspaceDir) {
89
89
  height: screenshot.height,
90
90
  };
91
91
  writeJsonAtomic(screenshotIndexPath(resolvedWorkspace), index);
92
- });
92
+ };
93
+ // Both parsers watch the same stream: their tool names and id namespaces are disjoint, so a
94
+ // session only ever populates the store through the browser integration it actually used.
95
+ const chromeParser = new types_1.ClaudeChromeScreenshotStreamParser(store);
96
+ const playwrightParser = new types_1.PlaywrightMcpScreenshotStreamParser(store);
93
97
  return {
94
- push: (chunk) => parser.push(chunk),
95
- finish: () => parser.finish(),
98
+ push: (chunk) => chromeParser.push(chunk) + playwrightParser.push(chunk),
99
+ finish: () => chromeParser.finish() + playwrightParser.finish(),
96
100
  };
97
101
  }
98
102
  function normalizeEvidenceName(value) {
@@ -68,10 +68,14 @@ export declare function buildClaudeExecArgs(input: {
68
68
  model: string;
69
69
  effort?: string | null;
70
70
  chrome?: boolean;
71
+ playwrightMcp?: boolean;
72
+ playwrightMcpConfigPath?: string | null;
71
73
  workspaceDir?: string | null;
72
74
  denyReadRoots?: string[] | null;
73
75
  pluginDir?: string | null;
74
76
  }): string[];
77
+ export declare const PLAYWRIGHT_MCP_VERSION = "0.0.78";
78
+ export declare function buildPlaywrightMcpServerConfig(): Record<string, unknown>;
75
79
  export declare function buildClaudePermissionSettings(input?: {
76
80
  workspaceDir?: string | null;
77
81
  denyReadRoots?: string[];
@@ -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.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_CODEX_TIMEOUT_MS = void 0;
7
7
  exports.readPositiveEnvInt = readPositiveEnvInt;
8
8
  exports.readEnvBoolean = readEnvBoolean;
9
9
  exports.extractAgentTokenUsage = extractAgentTokenUsage;
@@ -16,6 +16,7 @@ exports.runLoggedProcess = runLoggedProcess;
16
16
  exports.buildCodexExecArgs = buildCodexExecArgs;
17
17
  exports.readCodexSandboxMode = readCodexSandboxMode;
18
18
  exports.buildClaudeExecArgs = buildClaudeExecArgs;
19
+ exports.buildPlaywrightMcpServerConfig = buildPlaywrightMcpServerConfig;
19
20
  exports.buildClaudePermissionSettings = buildClaudePermissionSettings;
20
21
  exports.buildClaudeDeniedPermissionRules = buildClaudeDeniedPermissionRules;
21
22
  exports.buildWorkerChildEnv = buildWorkerChildEnv;
@@ -488,18 +489,33 @@ function buildClaudeExecArgs(input) {
488
489
  if (!model) {
489
490
  throw new Error('agent_task_assignment_model_missing');
490
491
  }
492
+ if (input.chrome && input.playwrightMcp) {
493
+ throw new Error('claude_exec_browser_mode_conflict');
494
+ }
495
+ const playwrightMcpConfigPath = typeof input.playwrightMcpConfigPath === 'string'
496
+ ? input.playwrightMcpConfigPath.trim()
497
+ : '';
498
+ if (input.playwrightMcp && !playwrightMcpConfigPath) {
499
+ throw new Error('playwright_mcp_config_path_missing');
500
+ }
491
501
  const permissionSettings = buildClaudePermissionSettings({
492
502
  workspaceDir: input.workspaceDir,
493
503
  denyReadRoots: input.denyReadRoots ?? [],
494
504
  });
495
- const permissionMode = input.chrome ? 'bypassPermissions' : 'acceptEdits';
505
+ const permissionMode = input.chrome || input.playwrightMcp ? 'bypassPermissions' : 'acceptEdits';
506
+ // MCP tools are deferred behind ToolSearch in the Claude CLI; without it in the toolset a
507
+ // session cannot reach any MCP server's tools no matter what --mcp-config provides.
496
508
  const tools = input.chrome
497
509
  ? [...CLAUDE_BASE_TOOL_NAMES, ...CLAUDE_CHROME_TOOL_NAMES].join(',')
498
- : CLAUDE_BASE_TOOL_NAMES.join(',');
510
+ : input.playwrightMcp
511
+ ? [...CLAUDE_BASE_TOOL_NAMES, 'ToolSearch'].join(',')
512
+ : CLAUDE_BASE_TOOL_NAMES.join(',');
499
513
  const allowedPermissionRules = buildClaudeAllowedPermissionRules(input.workspaceDir);
500
514
  const allowedTools = input.chrome
501
515
  ? [...allowedPermissionRules, ...CLAUDE_CHROME_TOOL_NAMES]
502
- : allowedPermissionRules;
516
+ : input.playwrightMcp
517
+ ? [...allowedPermissionRules, PLAYWRIGHT_MCP_ALLOWED_TOOL_RULE]
518
+ : allowedPermissionRules;
503
519
  const args = [
504
520
  '-p',
505
521
  '--safe-mode',
@@ -525,6 +541,9 @@ function buildClaudeExecArgs(input) {
525
541
  if (input.chrome) {
526
542
  args.unshift('--chrome');
527
543
  }
544
+ if (input.playwrightMcp) {
545
+ args.push('--mcp-config', playwrightMcpConfigPath);
546
+ }
528
547
  const pluginDir = typeof input.pluginDir === 'string' ? input.pluginDir.trim() : '';
529
548
  if (pluginDir) {
530
549
  args.push('--plugin-dir', pluginDir);
@@ -543,6 +562,20 @@ const CLAUDE_BASE_TOOL_NAMES = [
543
562
  'Glob',
544
563
  'Grep',
545
564
  ];
565
+ // Pinned deliberately: agent-CLI and MCP versions on workers only change through releases,
566
+ // never through @latest drift (see the 2026-07-13 auto-update incident).
567
+ exports.PLAYWRIGHT_MCP_VERSION = '0.0.78';
568
+ const PLAYWRIGHT_MCP_ALLOWED_TOOL_RULE = 'mcp__playwright';
569
+ function buildPlaywrightMcpServerConfig() {
570
+ return {
571
+ mcpServers: {
572
+ playwright: {
573
+ command: 'npx',
574
+ args: ['-y', `@playwright/mcp@${exports.PLAYWRIGHT_MCP_VERSION}`, '--browser', 'chrome', '--isolated'],
575
+ },
576
+ },
577
+ };
578
+ }
546
579
  const CLAUDE_CHROME_TOOL_NAMES = [
547
580
  'mcp__claude-in-chrome__browser_batch',
548
581
  'mcp__claude-in-chrome__computer',
@@ -2102,9 +2102,14 @@ async function runClaude(input) {
2102
2102
  envName: input.envName,
2103
2103
  });
2104
2104
  const denyReadRoots = resolveClaudeDenyReadRoots(input.workspaceDir);
2105
- const screenshotCollector = input.enableChrome
2105
+ const screenshotCollector = input.enableChrome || input.enablePlaywrightMcp
2106
2106
  ? (0, instrument_evidence_1.createWorkerInstrumentScreenshotCollector)(input.workspaceDir)
2107
2107
  : null;
2108
+ let playwrightMcpConfigPath = null;
2109
+ if (input.enablePlaywrightMcp) {
2110
+ playwrightMcpConfigPath = node_path_1.default.join(claudeConfigDir, 'playwright-mcp.json');
2111
+ (0, node_fs_1.writeFileSync)(playwrightMcpConfigPath, `${JSON.stringify((0, runtime_1.buildPlaywrightMcpServerConfig)(), null, 2)}\n`, 'utf8');
2112
+ }
2108
2113
  const result = await (0, runtime_1.runLoggedProcess)({
2109
2114
  command: 'claude',
2110
2115
  args: (0, runtime_1.buildClaudeExecArgs)({
@@ -2113,6 +2118,8 @@ async function runClaude(input) {
2113
2118
  denyReadRoots,
2114
2119
  pluginDir: input.taskPluginRoot,
2115
2120
  chrome: input.enableChrome,
2121
+ playwrightMcp: input.enablePlaywrightMcp,
2122
+ playwrightMcpConfigPath,
2116
2123
  }),
2117
2124
  cwd: input.workspaceDir,
2118
2125
  env: (0, runtime_1.buildWorkerChildEnv)({
@@ -4090,7 +4097,8 @@ async function startWorker(options = {}) {
4090
4097
  binDir,
4091
4098
  eventDir,
4092
4099
  prompt,
4093
- enableChrome: task.kind === 'GAME_REVIEW' || task.kind === 'GAME_EVAL',
4100
+ enableChrome: false,
4101
+ enablePlaywrightMcp: task.kind === 'GAME_REVIEW' || task.kind === 'GAME_EVAL',
4094
4102
  envName: env,
4095
4103
  workerUsername: username,
4096
4104
  taskId: task.id,
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "version": "0.12.8",
3
- "build": 6,
3
+ "build": 9,
4
4
  "runtimeSdkVersion": "0.12.5",
5
5
  "runtimeSdkBuild": 2,
6
6
  "clients": {
@@ -26,6 +26,9 @@ export type InstrumentEvidenceManifest = {
26
26
  controlledTabId: number;
27
27
  captures: Partial<Record<InstrumentEvidenceName, InstrumentEvidenceCapture>>;
28
28
  };
29
+ export declare const PLAYWRIGHT_MCP_SCREENSHOT_TOOL = "mcp__playwright__browser_take_screenshot";
30
+ export declare const PLAYWRIGHT_MCP_CONTROLLED_TAB_ID = 1;
31
+ export declare function isInstrumentScreenshotId(value: string): boolean;
29
32
  export declare class ClaudeChromeScreenshotStreamParser {
30
33
  private readonly onScreenshot;
31
34
  private buffer;
@@ -38,4 +41,17 @@ export declare class ClaudeChromeScreenshotStreamParser {
38
41
  private recordToolUse;
39
42
  private recordToolResults;
40
43
  }
44
+ export declare class PlaywrightMcpScreenshotStreamParser {
45
+ private readonly onScreenshot;
46
+ private buffer;
47
+ private readonly pendingScreenshotToolUseIds;
48
+ private readonly handledToolUseIds;
49
+ private sequence;
50
+ constructor(onScreenshot: (screenshot: ClaudeChromeScreenshot) => void);
51
+ push(chunk: string): number;
52
+ finish(): number;
53
+ private processLine;
54
+ private recordToolUse;
55
+ private recordToolResults;
56
+ }
41
57
  //# sourceMappingURL=instrument-evidence.d.ts.map
@@ -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;AAmDF,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"}
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"}
@@ -18,7 +18,11 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
18
18
  var instrument_evidence_exports = {};
19
19
  __export(instrument_evidence_exports, {
20
20
  ClaudeChromeScreenshotStreamParser: () => ClaudeChromeScreenshotStreamParser,
21
- INSTRUMENT_EVIDENCE_NAMES: () => INSTRUMENT_EVIDENCE_NAMES
21
+ INSTRUMENT_EVIDENCE_NAMES: () => INSTRUMENT_EVIDENCE_NAMES,
22
+ PLAYWRIGHT_MCP_CONTROLLED_TAB_ID: () => PLAYWRIGHT_MCP_CONTROLLED_TAB_ID,
23
+ PLAYWRIGHT_MCP_SCREENSHOT_TOOL: () => PLAYWRIGHT_MCP_SCREENSHOT_TOOL,
24
+ PlaywrightMcpScreenshotStreamParser: () => PlaywrightMcpScreenshotStreamParser,
25
+ isInstrumentScreenshotId: () => isInstrumentScreenshotId
22
26
  });
23
27
  module.exports = __toCommonJS(instrument_evidence_exports);
24
28
  const INSTRUMENT_EVIDENCE_NAMES = [
@@ -30,6 +34,12 @@ const INSTRUMENT_EVIDENCE_NAMES = [
30
34
  const SCREENSHOT_ID_PATTERN = /^ss_[A-Za-z0-9_-]+$/;
31
35
  const SCREENSHOT_ID_IN_TEXT_PATTERN = /\bID:\s*(ss_[A-Za-z0-9_-]+)\b/g;
32
36
  const MAX_STREAM_LINE_LENGTH = 20 * 1024 * 1024;
37
+ const PLAYWRIGHT_MCP_SCREENSHOT_TOOL = "mcp__playwright__browser_take_screenshot";
38
+ const PLAYWRIGHT_MCP_CONTROLLED_TAB_ID = 1;
39
+ const PLAYWRIGHT_SCREENSHOT_ID_PATTERN = /^pw-[1-9][0-9]*$/;
40
+ function isInstrumentScreenshotId(value) {
41
+ return SCREENSHOT_ID_PATTERN.test(value) || PLAYWRIGHT_SCREENSHOT_ID_PATTERN.test(value);
42
+ }
33
43
  function asRecord(value) {
34
44
  return value && typeof value === "object" && !Array.isArray(value) ? value : null;
35
45
  }
@@ -208,8 +218,128 @@ class ClaudeChromeScreenshotStreamParser {
208
218
  return emitted;
209
219
  }
210
220
  }
221
+ class PlaywrightMcpScreenshotStreamParser {
222
+ onScreenshot;
223
+ buffer = "";
224
+ pendingScreenshotToolUseIds = /* @__PURE__ */ new Set();
225
+ handledToolUseIds = /* @__PURE__ */ new Set();
226
+ sequence = 0;
227
+ constructor(onScreenshot) {
228
+ this.onScreenshot = onScreenshot;
229
+ }
230
+ push(chunk) {
231
+ if (!chunk) {
232
+ return 0;
233
+ }
234
+ this.buffer += chunk;
235
+ if (this.buffer.length > MAX_STREAM_LINE_LENGTH && !this.buffer.includes("\n")) {
236
+ throw new Error("claude_stream_json_line_too_large");
237
+ }
238
+ let emitted = 0;
239
+ for (; ; ) {
240
+ const newlineIndex = this.buffer.indexOf("\n");
241
+ if (newlineIndex < 0) {
242
+ break;
243
+ }
244
+ const line = this.buffer.slice(0, newlineIndex);
245
+ this.buffer = this.buffer.slice(newlineIndex + 1);
246
+ emitted += this.processLine(line);
247
+ }
248
+ return emitted;
249
+ }
250
+ finish() {
251
+ const line = this.buffer;
252
+ this.buffer = "";
253
+ return line.trim() ? this.processLine(line) : 0;
254
+ }
255
+ processLine(line) {
256
+ const trimmed = line.trim();
257
+ if (!trimmed) {
258
+ return 0;
259
+ }
260
+ let payload;
261
+ try {
262
+ const parsed = JSON.parse(trimmed);
263
+ const record = asRecord(parsed);
264
+ if (!record) {
265
+ throw new Error("invalid_claude_stream_json");
266
+ }
267
+ payload = record;
268
+ } catch (error) {
269
+ throw new Error(`invalid_claude_stream_json:${error instanceof Error ? error.message : String(error)}`);
270
+ }
271
+ if (payload["type"] === "assistant") {
272
+ this.recordToolUse(payload);
273
+ return 0;
274
+ }
275
+ if (payload["type"] === "user") {
276
+ return this.recordToolResults(payload);
277
+ }
278
+ return 0;
279
+ }
280
+ recordToolUse(payload) {
281
+ const message = asRecord(payload["message"]);
282
+ const content = Array.isArray(message?.["content"]) ? message["content"] : [];
283
+ for (const value of content) {
284
+ const item = asRecord(value);
285
+ const id = typeof item?.["id"] === "string" ? item["id"].trim() : "";
286
+ const name = typeof item?.["name"] === "string" ? item["name"].trim() : "";
287
+ if (item?.["type"] !== "tool_use" || !id || name !== PLAYWRIGHT_MCP_SCREENSHOT_TOOL) {
288
+ continue;
289
+ }
290
+ this.pendingScreenshotToolUseIds.add(id);
291
+ }
292
+ }
293
+ recordToolResults(payload) {
294
+ const message = asRecord(payload["message"]);
295
+ const content = Array.isArray(message?.["content"]) ? message["content"] : [];
296
+ let emitted = 0;
297
+ for (const value of content) {
298
+ const toolResult = asRecord(value);
299
+ if (toolResult?.["type"] !== "tool_result") {
300
+ continue;
301
+ }
302
+ const toolUseId = typeof toolResult["tool_use_id"] === "string" ? toolResult["tool_use_id"].trim() : "";
303
+ if (!this.pendingScreenshotToolUseIds.has(toolUseId) || this.handledToolUseIds.has(toolUseId)) {
304
+ continue;
305
+ }
306
+ this.handledToolUseIds.add(toolUseId);
307
+ this.pendingScreenshotToolUseIds.delete(toolUseId);
308
+ const resultContent = Array.isArray(toolResult["content"]) ? toolResult["content"] : [];
309
+ const images = resultContent.map(asRecord).filter((item) => item?.["type"] === "image");
310
+ if (images.length === 0) {
311
+ continue;
312
+ }
313
+ if (images.length > 1) {
314
+ throw new Error(`playwright_screenshot_multiple_images:${toolUseId}`);
315
+ }
316
+ const source = asRecord(images[0]?.["source"]);
317
+ const mediaType = source?.["media_type"];
318
+ const dataBase64 = typeof source?.["data"] === "string" ? source["data"] : "";
319
+ if (mediaType !== "image/jpeg" && mediaType !== "image/png" || !dataBase64) {
320
+ throw new Error(`invalid_playwright_screenshot_payload:${toolUseId}`);
321
+ }
322
+ this.sequence += 1;
323
+ this.onScreenshot({
324
+ screenshotId: `pw-${this.sequence}`,
325
+ tabId: PLAYWRIGHT_MCP_CONTROLLED_TAB_ID,
326
+ toolUseId,
327
+ mediaType,
328
+ dataBase64,
329
+ width: null,
330
+ height: null
331
+ });
332
+ emitted += 1;
333
+ }
334
+ return emitted;
335
+ }
336
+ }
211
337
  // Annotate the CommonJS export names for ESM import in node:
212
338
  0 && (module.exports = {
213
339
  ClaudeChromeScreenshotStreamParser,
214
- INSTRUMENT_EVIDENCE_NAMES
340
+ INSTRUMENT_EVIDENCE_NAMES,
341
+ PLAYWRIGHT_MCP_CONTROLLED_TAB_ID,
342
+ PLAYWRIGHT_MCP_SCREENSHOT_TOOL,
343
+ PlaywrightMcpScreenshotStreamParser,
344
+ isInstrumentScreenshotId
215
345
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@playdrop/playdrop-cli",
3
- "version": "0.12.14",
3
+ "version": "0.12.16",
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": {