@playdrop/playdrop-cli 0.12.20 → 0.12.22

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": 13,
3
+ "build": 15,
4
4
  "runtimeSdkVersion": "0.12.5",
5
5
  "runtimeSdkBuild": 2,
6
6
  "clients": {
@@ -9,7 +9,7 @@ export declare function saveInstrumentEvidenceCapture(input: {
9
9
  evidenceDir: string;
10
10
  groupId: string;
11
11
  name: string;
12
- screenshotId: string;
12
+ screenshotId?: string;
13
13
  }): Promise<InstrumentEvidenceCapture>;
14
14
  export declare function readAndValidateInstrumentEvidenceManifest(input: {
15
15
  workspaceDir: string;
@@ -99,6 +99,35 @@ function createWorkerInstrumentScreenshotCollector(workspaceDir) {
99
99
  finish: () => chromeParser.finish() + playwrightParser.finish(),
100
100
  };
101
101
  }
102
+ function resolveLatestUnusedScreenshotId(workspaceDir, index) {
103
+ const used = new Set();
104
+ const evidenceRoot = node_path_1.default.resolve(workspaceDir);
105
+ const walk = (dir) => {
106
+ for (const entry of (0, node_fs_1.existsSync)(dir) ? (0, node_fs_1.readdirSync)(dir, { withFileTypes: true }) : []) {
107
+ const entryPath = node_path_1.default.join(dir, entry.name);
108
+ if (entry.isDirectory()) {
109
+ walk(entryPath);
110
+ }
111
+ else if (entry.name === exports.INSTRUMENT_EVIDENCE_MANIFEST_FILE) {
112
+ const manifest = readJsonRecord(entryPath, 'invalid_instrument_evidence_manifest');
113
+ for (const capture of Object.values(manifest.captures ?? {})) {
114
+ if (capture?.screenshotId) {
115
+ used.add(capture.screenshotId);
116
+ }
117
+ }
118
+ }
119
+ }
120
+ };
121
+ walk(evidenceRoot);
122
+ const candidates = Object.values(index.screenshots)
123
+ .filter((screenshot) => !used.has(screenshot.screenshotId))
124
+ .sort((a, b) => a.capturedAt.localeCompare(b.capturedAt));
125
+ const latest = candidates.at(-1);
126
+ if (!latest) {
127
+ throw new Error('instrument_screenshot_none_available');
128
+ }
129
+ return latest.screenshotId;
130
+ }
102
131
  function normalizeEvidenceName(value) {
103
132
  const normalized = value.trim();
104
133
  if (!types_1.INSTRUMENT_EVIDENCE_NAMES.includes(normalized)) {
@@ -131,8 +160,11 @@ function readManifestIfPresent(evidenceDir) {
131
160
  async function saveInstrumentEvidenceCapture(input) {
132
161
  const evidenceName = normalizeEvidenceName(input.name);
133
162
  const groupId = normalizeGroupId(input.groupId);
134
- const screenshotId = input.screenshotId.trim();
135
163
  const index = readScreenshotIndex(input.workspaceDir);
164
+ const requestedId = input.screenshotId?.trim() ?? '';
165
+ // With no id, persist the capture the judge just took: the most recent one not already used as
166
+ // evidence. The judge never has to track ids, and a failed capture simply is not there to pick.
167
+ const screenshotId = requestedId || resolveLatestUnusedScreenshotId(input.workspaceDir, index);
136
168
  const screenshot = index.screenshots[screenshotId];
137
169
  if (!screenshot) {
138
170
  throw new Error(`instrument_screenshot_not_found:${screenshotId}`);
@@ -4892,9 +4892,10 @@ async function saveTaskEvidence(options) {
4892
4892
  }
4893
4893
  const evidenceDir = options.evidenceDir?.trim();
4894
4894
  const name = options.name?.trim();
4895
+ // --screenshot-id is optional: with no id the worker persists the capture the agent just took.
4895
4896
  const screenshotId = options.screenshotId?.trim();
4896
4897
  const groupId = options.group?.trim() || (taskContext.kind === 'GAME_REVIEW' ? 'review' : '');
4897
- if (!evidenceDir || !name || !screenshotId || !groupId) {
4898
+ if (!evidenceDir || !name || !groupId) {
4898
4899
  throw new Error('task_evidence_options_required');
4899
4900
  }
4900
4901
  const capture = await (0, instrument_evidence_1.saveInstrumentEvidenceCapture)({
@@ -4902,9 +4903,9 @@ async function saveTaskEvidence(options) {
4902
4903
  evidenceDir,
4903
4904
  groupId,
4904
4905
  name,
4905
- screenshotId,
4906
+ ...(screenshotId ? { screenshotId } : {}),
4906
4907
  });
4907
- (0, output_1.printSuccess)(`Saved ${capture.name} evidence from Chrome screenshot ${capture.screenshotId} on controlled tab ${capture.tabId} to ${capture.fileName}.`);
4908
+ (0, output_1.printSuccess)(`Saved ${capture.name} evidence from screenshot ${capture.screenshotId} to ${capture.fileName}.`);
4908
4909
  }
4909
4910
  const INSTRUMENT_ERROR_REASONS = new Set([
4910
4911
  'auth_state',
package/dist/index.js CHANGED
@@ -287,9 +287,9 @@ task
287
287
  });
288
288
  task
289
289
  .command('evidence')
290
- .description('Persist a Claude Chrome screenshot as task evidence')
290
+ .description('Persist the screenshot you just took as task evidence')
291
291
  .requiredOption('--name <name>', 'Evidence state: first-frame, core, win, or loss')
292
- .requiredOption('--screenshot-id <id>', 'Claude Chrome screenshot id')
292
+ .option('--screenshot-id <id>', 'Screenshot id; omit to persist the capture you just took')
293
293
  .requiredOption('--evidence-dir <path>', 'Evidence output directory')
294
294
  .option('--group <id>', 'Evidence group id; required for GAME_EVAL')
295
295
  .action(async (opts) => {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "version": "0.12.8",
3
- "build": 13,
3
+ "build": 15,
4
4
  "runtimeSdkVersion": "0.12.5",
5
5
  "runtimeSdkBuild": 2,
6
6
  "clients": {
@@ -30,7 +30,6 @@ export declare const PLAYWRIGHT_MCP_SCREENSHOT_TOOL = "mcp__playwright__browser_
30
30
  export declare const PLAYWRIGHT_MCP_CONTROLLED_TAB_ID = 1;
31
31
  export declare const PLAYWRIGHT_MCP_SCREENSHOT_BUDGET = 100;
32
32
  export declare function isInstrumentScreenshotId(value: string): boolean;
33
- export declare function normalizePlaywrightScreenshotId(value: unknown): string | null;
34
33
  export declare class ClaudeChromeScreenshotStreamParser {
35
34
  private readonly onScreenshot;
36
35
  private buffer;
@@ -46,9 +45,10 @@ export declare class ClaudeChromeScreenshotStreamParser {
46
45
  export declare class PlaywrightMcpScreenshotStreamParser {
47
46
  private readonly onScreenshot;
48
47
  private buffer;
49
- private readonly pendingScreenshotFilenames;
48
+ private readonly pendingScreenshotToolUseIds;
50
49
  private readonly handledToolUseIds;
51
50
  private screenshotCallCount;
51
+ private sequence;
52
52
  constructor(onScreenshot: (screenshot: ClaudeChromeScreenshot) => void);
53
53
  push(chunk: string): number;
54
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,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"}
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;AAiDD,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;IAOlC,OAAO,CAAC,QAAQ,CAAC,YAAY;IANzC,OAAO,CAAC,MAAM,CAAM;IACpB,OAAO,CAAC,QAAQ,CAAC,2BAA2B,CAAqB;IACjE,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAqB;IACvD,OAAO,CAAC,mBAAmB,CAAK;IAChC,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;IAsBrB,OAAO,CAAC,iBAAiB;CA+C1B"}
@@ -23,8 +23,7 @@ __export(instrument_evidence_exports, {
23
23
  PLAYWRIGHT_MCP_SCREENSHOT_BUDGET: () => PLAYWRIGHT_MCP_SCREENSHOT_BUDGET,
24
24
  PLAYWRIGHT_MCP_SCREENSHOT_TOOL: () => PLAYWRIGHT_MCP_SCREENSHOT_TOOL,
25
25
  PlaywrightMcpScreenshotStreamParser: () => PlaywrightMcpScreenshotStreamParser,
26
- isInstrumentScreenshotId: () => isInstrumentScreenshotId,
27
- normalizePlaywrightScreenshotId: () => normalizePlaywrightScreenshotId
26
+ isInstrumentScreenshotId: () => isInstrumentScreenshotId
28
27
  });
29
28
  module.exports = __toCommonJS(instrument_evidence_exports);
30
29
  const INSTRUMENT_EVIDENCE_NAMES = [
@@ -39,14 +38,10 @@ const MAX_STREAM_LINE_LENGTH = 20 * 1024 * 1024;
39
38
  const PLAYWRIGHT_MCP_SCREENSHOT_TOOL = "mcp__playwright__browser_take_screenshot";
40
39
  const PLAYWRIGHT_MCP_CONTROLLED_TAB_ID = 1;
41
40
  const PLAYWRIGHT_MCP_SCREENSHOT_BUDGET = 100;
42
- const PLAYWRIGHT_SCREENSHOT_ID_PATTERN = /^[a-z0-9][a-z0-9._-]{0,63}\.(png|jpe?g)$/;
41
+ const PLAYWRIGHT_SCREENSHOT_ID_PATTERN = /^pw-[1-9][0-9]*$/;
43
42
  function isInstrumentScreenshotId(value) {
44
43
  return SCREENSHOT_ID_PATTERN.test(value) || PLAYWRIGHT_SCREENSHOT_ID_PATTERN.test(value);
45
44
  }
46
- function normalizePlaywrightScreenshotId(value) {
47
- const id = typeof value === "string" ? value.trim().toLowerCase() : "";
48
- return PLAYWRIGHT_SCREENSHOT_ID_PATTERN.test(id) ? id : null;
49
- }
50
45
  function asRecord(value) {
51
46
  return value && typeof value === "object" && !Array.isArray(value) ? value : null;
52
47
  }
@@ -228,9 +223,10 @@ class ClaudeChromeScreenshotStreamParser {
228
223
  class PlaywrightMcpScreenshotStreamParser {
229
224
  onScreenshot;
230
225
  buffer = "";
231
- pendingScreenshotFilenames = /* @__PURE__ */ new Map();
226
+ pendingScreenshotToolUseIds = /* @__PURE__ */ new Set();
232
227
  handledToolUseIds = /* @__PURE__ */ new Set();
233
228
  screenshotCallCount = 0;
229
+ sequence = 0;
234
230
  constructor(onScreenshot) {
235
231
  this.onScreenshot = onScreenshot;
236
232
  }
@@ -298,12 +294,7 @@ class PlaywrightMcpScreenshotStreamParser {
298
294
  if (this.screenshotCallCount > PLAYWRIGHT_MCP_SCREENSHOT_BUDGET) {
299
295
  throw new Error(`playwright_screenshot_budget_exceeded:${PLAYWRIGHT_MCP_SCREENSHOT_BUDGET}`);
300
296
  }
301
- const input = asRecord(item?.["input"]);
302
- const filename = normalizePlaywrightScreenshotId(input?.["filename"]);
303
- if (!filename) {
304
- continue;
305
- }
306
- this.pendingScreenshotFilenames.set(id, filename);
297
+ this.pendingScreenshotToolUseIds.add(id);
307
298
  }
308
299
  }
309
300
  recordToolResults(payload) {
@@ -316,12 +307,11 @@ class PlaywrightMcpScreenshotStreamParser {
316
307
  continue;
317
308
  }
318
309
  const toolUseId = typeof toolResult["tool_use_id"] === "string" ? toolResult["tool_use_id"].trim() : "";
319
- const screenshotId = this.pendingScreenshotFilenames.get(toolUseId);
320
- if (!screenshotId || this.handledToolUseIds.has(toolUseId)) {
310
+ if (!this.pendingScreenshotToolUseIds.has(toolUseId) || this.handledToolUseIds.has(toolUseId)) {
321
311
  continue;
322
312
  }
323
313
  this.handledToolUseIds.add(toolUseId);
324
- this.pendingScreenshotFilenames.delete(toolUseId);
314
+ this.pendingScreenshotToolUseIds.delete(toolUseId);
325
315
  const resultContent = Array.isArray(toolResult["content"]) ? toolResult["content"] : [];
326
316
  const images = resultContent.map(asRecord).filter((item) => item?.["type"] === "image");
327
317
  if (images.length === 0) {
@@ -336,8 +326,9 @@ class PlaywrightMcpScreenshotStreamParser {
336
326
  if (mediaType !== "image/jpeg" && mediaType !== "image/png" || !dataBase64) {
337
327
  throw new Error(`invalid_playwright_screenshot_payload:${toolUseId}`);
338
328
  }
329
+ this.sequence += 1;
339
330
  this.onScreenshot({
340
- screenshotId,
331
+ screenshotId: `pw-${this.sequence}`,
341
332
  tabId: PLAYWRIGHT_MCP_CONTROLLED_TAB_ID,
342
333
  toolUseId,
343
334
  mediaType,
@@ -358,6 +349,5 @@ class PlaywrightMcpScreenshotStreamParser {
358
349
  PLAYWRIGHT_MCP_SCREENSHOT_BUDGET,
359
350
  PLAYWRIGHT_MCP_SCREENSHOT_TOOL,
360
351
  PlaywrightMcpScreenshotStreamParser,
361
- isInstrumentScreenshotId,
362
- normalizePlaywrightScreenshotId
352
+ isInstrumentScreenshotId
363
353
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@playdrop/playdrop-cli",
3
- "version": "0.12.20",
3
+ "version": "0.12.22",
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": {