@playdrop/playdrop-cli 0.8.6 → 0.9.0

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 (38) hide show
  1. package/README.md +20 -0
  2. package/config/client-meta.json +1 -1
  3. package/dist/captureRuntime.d.ts +2 -0
  4. package/dist/captureRuntime.js +115 -0
  5. package/dist/commands/agents.d.ts +62 -0
  6. package/dist/commands/agents.js +470 -0
  7. package/dist/commands/clients.d.ts +44 -0
  8. package/dist/commands/clients.js +257 -0
  9. package/dist/commands/doctor.d.ts +51 -0
  10. package/dist/commands/doctor.js +266 -0
  11. package/dist/commands/marketing.d.ts +137 -0
  12. package/dist/commands/marketing.js +1102 -0
  13. package/dist/commands/workspaces.d.ts +47 -0
  14. package/dist/commands/workspaces.js +498 -0
  15. package/dist/index.js +153 -10
  16. package/dist/shellProbe.d.ts +6 -0
  17. package/dist/shellProbe.js +17 -0
  18. package/dist/versionCompare.d.ts +2 -0
  19. package/dist/versionCompare.js +30 -0
  20. package/node_modules/@playdrop/api-client/dist/client.d.ts +41 -1
  21. package/node_modules/@playdrop/api-client/dist/client.d.ts.map +1 -1
  22. package/node_modules/@playdrop/api-client/dist/client.js +156 -0
  23. package/node_modules/@playdrop/api-client/dist/domains/admin.d.ts +27 -1
  24. package/node_modules/@playdrop/api-client/dist/domains/admin.d.ts.map +1 -1
  25. package/node_modules/@playdrop/api-client/dist/domains/admin.js +178 -0
  26. package/node_modules/@playdrop/api-client/dist/domains/game-ideas.d.ts +2 -1
  27. package/node_modules/@playdrop/api-client/dist/domains/game-ideas.d.ts.map +1 -1
  28. package/node_modules/@playdrop/api-client/dist/domains/game-ideas.js +11 -0
  29. package/node_modules/@playdrop/api-client/dist/index.d.ts +41 -1
  30. package/node_modules/@playdrop/api-client/dist/index.d.ts.map +1 -1
  31. package/node_modules/@playdrop/api-client/dist/index.js +140 -0
  32. package/node_modules/@playdrop/config/client-meta.json +1 -1
  33. package/node_modules/@playdrop/types/dist/api.d.ts +351 -0
  34. package/node_modules/@playdrop/types/dist/api.d.ts.map +1 -1
  35. package/node_modules/@playdrop/types/dist/api.js +78 -0
  36. package/node_modules/@playdrop/types/dist/version.d.ts +2 -2
  37. package/node_modules/@playdrop/types/dist/version.d.ts.map +1 -1
  38. package/package.json +1 -1
package/README.md CHANGED
@@ -51,6 +51,10 @@ playdrop project publish --env dev .
51
51
  ## Main Commands
52
52
 
53
53
  ```bash
54
+ playdrop doctor
55
+ playdrop clients status
56
+ playdrop agents status
57
+ playdrop workspaces list
54
58
  playdrop auth login
55
59
  playdrop auth whoami --env dev
56
60
  playdrop browse
@@ -72,6 +76,22 @@ playdrop feedback send --title "Bug report" --comment "Details here."
72
76
  playdrop getting-started
73
77
  ```
74
78
 
79
+ ## Machine Setup
80
+
81
+ ```bash
82
+ playdrop doctor
83
+ playdrop clients install
84
+ playdrop agents install-plugin codex
85
+ playdrop agents install-plugin claude
86
+ playdrop workspaces init
87
+ ```
88
+
89
+ `playdrop agents install-plugin claude` adds the PlayDrop marketplace, installs the PlayDrop plugin through the Claude Code CLI, and tells you to reload plugins.
90
+
91
+ `playdrop agents install-plugin codex` configures the PlayDrop plugin marketplace and uses Codex's plugin install command when the local Codex CLI exposes one. If the installed Codex CLI only supports marketplace management, finish activation from Codex with `/plugins`.
92
+
93
+ Cursor does not currently expose documented plugin installation through its CLI. `playdrop agents install-plugin cursor` prints the manual steps instead: open Cursor and use `/add-plugin` or the Cursor Marketplace for PlayDrop.
94
+
75
95
  ## Ref Format
76
96
 
77
97
  Public content refs are always:
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.8.6",
2
+ "version": "0.9.0",
3
3
  "runtimeSdkVersion": "0.7.21",
4
4
  "build": 1,
5
5
  "clients": {
@@ -41,6 +41,8 @@ export type CaptureHostedLaunchState = {
41
41
  };
42
42
  export type CaptureRunResult = {
43
43
  errorCount: number;
44
+ warningCount: number;
45
+ warnings: string[];
44
46
  finalUrl: string;
45
47
  hostedLaunchState: CaptureHostedLaunchState | null;
46
48
  };
@@ -11,6 +11,93 @@ const sessionCookie_1 = require("./sessionCookie");
11
11
  const FRAME_SELECTOR = 'iframe[title="Game"]';
12
12
  exports.CAPTURE_LOG_LEVEL_VALUES = ['debug', 'info', 'warn', 'error'];
13
13
  exports.MAX_CAPTURE_TIMEOUT_SECONDS = 600;
14
+ const GOOGLE_TELEMETRY_HOSTS = [
15
+ 'googletagmanager.com',
16
+ 'google-analytics.com',
17
+ 'googleadservices.com',
18
+ 'doubleclick.net',
19
+ ];
20
+ const GOOGLE_COUNTRY_SECOND_LEVEL_DOMAINS = new Set(['ac', 'co', 'com', 'edu', 'gov', 'net', 'org']);
21
+ function isHostOrSubdomain(hostname, domain) {
22
+ return hostname === domain || hostname.endsWith(`.${domain}`);
23
+ }
24
+ function isGoogleSearchAdCollectionUrl(parsed) {
25
+ const hostname = parsed.hostname.toLowerCase();
26
+ if (hostname !== 'www.google.com') {
27
+ const suffix = hostname.startsWith('www.google.') ? hostname.slice('www.google.'.length) : '';
28
+ const labels = suffix.split('.');
29
+ const isCountryDomain = labels.length === 1
30
+ ? /^[a-z]{2}$/.test(labels[0])
31
+ : labels.length === 2
32
+ && GOOGLE_COUNTRY_SECOND_LEVEL_DOMAINS.has(labels[0])
33
+ && /^[a-z]{2}$/.test(labels[1]);
34
+ if (!isCountryDomain) {
35
+ return false;
36
+ }
37
+ }
38
+ const pathname = parsed.pathname.toLowerCase();
39
+ return pathname.startsWith('/ccm/collect')
40
+ || pathname.startsWith('/rmkt/collect')
41
+ || pathname.startsWith('/pagead/');
42
+ }
43
+ function isLoopbackOrLocalUrl(rawUrl) {
44
+ let parsed;
45
+ try {
46
+ parsed = new URL(rawUrl);
47
+ }
48
+ catch {
49
+ return false;
50
+ }
51
+ const hostname = parsed.hostname.toLowerCase();
52
+ return hostname === 'localhost'
53
+ || hostname === '127.0.0.1'
54
+ || hostname === '::1'
55
+ || hostname.endsWith('.localhost');
56
+ }
57
+ function isKnownGoogleTelemetryUrl(rawUrl) {
58
+ let parsed;
59
+ try {
60
+ parsed = new URL(rawUrl);
61
+ }
62
+ catch {
63
+ return false;
64
+ }
65
+ const hostname = parsed.hostname.toLowerCase();
66
+ if (hostname === 'accounts.google.com' || hostname.endsWith('.accounts.google.com')) {
67
+ return false;
68
+ }
69
+ return GOOGLE_TELEMETRY_HOSTS.some(domain => isHostOrSubdomain(hostname, domain))
70
+ || isGoogleSearchAdCollectionUrl(parsed);
71
+ }
72
+ function extractHttpUrls(text) {
73
+ const matches = text.match(/https?:\/\/[^\s"'<>]+/gi);
74
+ if (!matches) {
75
+ return [];
76
+ }
77
+ return matches.map(match => match.replace(/[\])}.,;]+$/g, ''));
78
+ }
79
+ function extractRefusedResourceUrls(text) {
80
+ const urls = [];
81
+ const refusedPattern = /Refused to [^']*'(https?:\/\/[^']+)'/gi;
82
+ let match = refusedPattern.exec(text);
83
+ while (match) {
84
+ urls.push(match[1]);
85
+ match = refusedPattern.exec(text);
86
+ }
87
+ return urls;
88
+ }
89
+ function isKnownGoogleTelemetryConsoleIssue(text, locationUrl) {
90
+ if (/Content Security Policy/i.test(text)) {
91
+ return extractRefusedResourceUrls(text).some(isKnownGoogleTelemetryUrl);
92
+ }
93
+ if (!/ERR_BLOCKED_BY_CLIENT/i.test(text)) {
94
+ return false;
95
+ }
96
+ const messageUrls = extractHttpUrls(text);
97
+ return (locationUrl !== null && isKnownGoogleTelemetryUrl(locationUrl))
98
+ || (messageUrls.some(isKnownGoogleTelemetryUrl)
99
+ && !messageUrls.some(isLoopbackOrLocalUrl));
100
+ }
14
101
  function formatConsoleValue(value) {
15
102
  if (typeof value === 'string')
16
103
  return value;
@@ -176,6 +263,7 @@ function validateCaptureTimeout(value) {
176
263
  }
177
264
  async function runCapture(options) {
178
265
  const errors = [];
266
+ const warnings = [];
179
267
  const outputLines = [];
180
268
  const expectedUrl = options.expectedUrl ? normalizeComparableUrl(options.expectedUrl) : null;
181
269
  const expectedHostedLaunchState = options.requireHostedLaunchReady
@@ -208,6 +296,15 @@ async function runCapture(options) {
208
296
  errors.push(message);
209
297
  record('error', message);
210
298
  };
299
+ const recordWarning = (line, lineAlreadyRecorded = false) => {
300
+ warnings.push(line);
301
+ if (!lineAlreadyRecorded) {
302
+ outputLines.push(line);
303
+ }
304
+ if (shouldEmit('warn', options.minimumLogLevel)) {
305
+ console.warn(line);
306
+ }
307
+ };
211
308
  try {
212
309
  await (0, playwright_1.withChromiumPage)(async ({ context, page }) => {
213
310
  const targetOrigin = new URL(options.targetUrl).origin;
@@ -343,6 +440,14 @@ async function runCapture(options) {
343
440
  effectiveLevel = 'debug';
344
441
  }
345
442
  if (type === 'error' || type === 'assert' || type === 'trace') {
443
+ const location = typeof message.location === 'function' ? message.location() : null;
444
+ const locationUrl = typeof location?.url === 'string' && location.url.trim().length > 0
445
+ ? location.url
446
+ : null;
447
+ if (isKnownGoogleTelemetryConsoleIssue(rendered, locationUrl)) {
448
+ recordWarning(line, true);
449
+ return;
450
+ }
346
451
  errors.push(line);
347
452
  if (shouldEmit(effectiveLevel, options.minimumLogLevel)) {
348
453
  console.error(line);
@@ -383,6 +488,10 @@ async function runCapture(options) {
383
488
  const failure = request.failure();
384
489
  const errorText = failure?.errorText ?? '';
385
490
  const text = `${request.method()} ${request.url()} - ${errorText || 'failed'}`;
491
+ if (isKnownGoogleTelemetryUrl(request.url())) {
492
+ recordWarning(`[capture][requestfailed] ${text}`);
493
+ return;
494
+ }
386
495
  if (/ERR_ABORTED/i.test(errorText) || /ERR_HTTP2_PROTOCOL_ERROR/i.test(errorText)) {
387
496
  const line = `[capture][requestcancelled] ${text}`;
388
497
  outputLines.push(line);
@@ -411,6 +520,10 @@ async function runCapture(options) {
411
520
  }
412
521
  return;
413
522
  }
523
+ if (isKnownGoogleTelemetryUrl(response.url())) {
524
+ recordWarning(`[capture][response] ${text}`);
525
+ return;
526
+ }
414
527
  errors.push(text);
415
528
  outputLines.push(`[capture][response] ${text}`);
416
529
  if (shouldEmit('warn', options.minimumLogLevel)) {
@@ -528,6 +641,8 @@ async function runCapture(options) {
528
641
  }
529
642
  return {
530
643
  errorCount: errors.length,
644
+ warningCount: warnings.length,
645
+ warnings,
531
646
  finalUrl,
532
647
  hostedLaunchState,
533
648
  };
@@ -0,0 +1,62 @@
1
+ type AgentID = 'codex' | 'claude' | 'cursor';
2
+ interface ShellResult {
3
+ exitCode: number;
4
+ output: string;
5
+ }
6
+ interface ToolStatus {
7
+ installed: boolean;
8
+ path?: string;
9
+ version?: string;
10
+ }
11
+ interface PluginStatus {
12
+ installed: boolean;
13
+ status?: 'installed' | 'missing' | 'activation-required' | 'manual-verification-required' | 'unknown';
14
+ id?: string;
15
+ path?: string;
16
+ version?: string;
17
+ latestVersion?: string;
18
+ updateAvailable?: boolean;
19
+ enabled?: boolean;
20
+ scope?: string;
21
+ installableFromCli?: boolean;
22
+ message?: string;
23
+ }
24
+ export interface AgentStatus {
25
+ id: AgentID;
26
+ name: string;
27
+ app: ToolStatus;
28
+ cli: ToolStatus;
29
+ account?: {
30
+ identity?: string;
31
+ subscription?: string;
32
+ signedIn: boolean | null;
33
+ };
34
+ plugin: PluginStatus;
35
+ nextAction: {
36
+ command: string;
37
+ reason: string;
38
+ } | null;
39
+ }
40
+ export interface AgentsStatus {
41
+ agents: AgentStatus[];
42
+ }
43
+ interface AgentsStatusOptions {
44
+ homeDir?: string;
45
+ latestPluginVersion?: string;
46
+ runShell?: (command: string) => Promise<ShellResult>;
47
+ appExists?: (path: string) => boolean;
48
+ json?: boolean;
49
+ }
50
+ interface AgentActionOptions {
51
+ runCommand?: (command: string, args: string[]) => {
52
+ status: number | null;
53
+ stdout?: string;
54
+ stderr?: string;
55
+ };
56
+ homeDir?: string;
57
+ }
58
+ export declare function showAgentsStatus(options?: AgentsStatusOptions): Promise<AgentsStatus>;
59
+ export declare function getAgentsStatus(options?: AgentsStatusOptions): Promise<AgentsStatus>;
60
+ export declare function installPlugin(agentID: string, options?: AgentActionOptions): Promise<void>;
61
+ export declare function updatePlugin(agentID: string, options?: AgentActionOptions): Promise<void>;
62
+ export {};