@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.
- package/README.md +20 -0
- package/config/client-meta.json +1 -1
- package/dist/captureRuntime.d.ts +2 -0
- package/dist/captureRuntime.js +115 -0
- package/dist/commands/agents.d.ts +62 -0
- package/dist/commands/agents.js +470 -0
- package/dist/commands/clients.d.ts +44 -0
- package/dist/commands/clients.js +257 -0
- package/dist/commands/doctor.d.ts +51 -0
- package/dist/commands/doctor.js +266 -0
- package/dist/commands/marketing.d.ts +137 -0
- package/dist/commands/marketing.js +1102 -0
- package/dist/commands/workspaces.d.ts +47 -0
- package/dist/commands/workspaces.js +498 -0
- package/dist/index.js +153 -10
- package/dist/shellProbe.d.ts +6 -0
- package/dist/shellProbe.js +17 -0
- package/dist/versionCompare.d.ts +2 -0
- package/dist/versionCompare.js +30 -0
- package/node_modules/@playdrop/api-client/dist/client.d.ts +41 -1
- package/node_modules/@playdrop/api-client/dist/client.d.ts.map +1 -1
- package/node_modules/@playdrop/api-client/dist/client.js +156 -0
- package/node_modules/@playdrop/api-client/dist/domains/admin.d.ts +27 -1
- package/node_modules/@playdrop/api-client/dist/domains/admin.d.ts.map +1 -1
- package/node_modules/@playdrop/api-client/dist/domains/admin.js +178 -0
- package/node_modules/@playdrop/api-client/dist/domains/game-ideas.d.ts +2 -1
- package/node_modules/@playdrop/api-client/dist/domains/game-ideas.d.ts.map +1 -1
- package/node_modules/@playdrop/api-client/dist/domains/game-ideas.js +11 -0
- package/node_modules/@playdrop/api-client/dist/index.d.ts +41 -1
- package/node_modules/@playdrop/api-client/dist/index.d.ts.map +1 -1
- package/node_modules/@playdrop/api-client/dist/index.js +140 -0
- package/node_modules/@playdrop/config/client-meta.json +1 -1
- package/node_modules/@playdrop/types/dist/api.d.ts +351 -0
- package/node_modules/@playdrop/types/dist/api.d.ts.map +1 -1
- package/node_modules/@playdrop/types/dist/api.js +78 -0
- package/node_modules/@playdrop/types/dist/version.d.ts +2 -2
- package/node_modules/@playdrop/types/dist/version.d.ts.map +1 -1
- 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:
|
package/config/client-meta.json
CHANGED
package/dist/captureRuntime.d.ts
CHANGED
package/dist/captureRuntime.js
CHANGED
|
@@ -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 {};
|