feat(doctor): print cli version in doctor report
This commit is contained in:
1 parent
1aaafed2db
commit
cef50dc8bf
8 files changed
+293
-2
No files matched your search
@@ -0,0 +1,32 @@
|
||||
import { PlaywrightMCP } from './src/browser.js';
|
||||
import { browserSession, runWithTimeout } from './src/runtime.js';
|
||||
import * as fs from 'fs';
|
||||
|
||||
async function main() {
|
||||
console.log("Starting browser session...");
|
||||
await browserSession(PlaywrightMCP, async (page) => {
|
||||
await page.goto('https://x.com/vikingmute/status/2033156347504767135');
|
||||
await page.wait(5); // Wait for hydration
|
||||
|
||||
console.log("Analyzing data-testids...");
|
||||
const result = await page.evaluate(`(async () => {
|
||||
const elements = document.querySelectorAll('*[data-testid]');
|
||||
const testIds = Array.from(elements).map(el => el.getAttribute('data-testid'));
|
||||
const uniqueIds = [...new Set(testIds)];
|
||||
|
||||
// Focus on action buttons
|
||||
const actionIds = uniqueIds.filter(id =>
|
||||
id.toLowerCase().includes('like') ||
|
||||
id.toLowerCase().includes('heart') ||
|
||||
id.toLowerCase().includes('retweet') ||
|
||||
id.toLowerCase().includes('reply')
|
||||
);
|
||||
return { actionIds, all: uniqueIds };
|
||||
})()`);
|
||||
|
||||
fs.writeFileSync('like_testids.json', JSON.stringify(result, null, 2));
|
||||
console.log(`Captured ${result.actionIds.length} potential action test IDs. Saved to like_testids.json`);
|
||||
});
|
||||
}
|
||||
|
||||
main().catch(console.error);
|
||||
@@ -0,0 +1,24 @@
|
||||
import { PlaywrightMCP } from './src/browser.js';
|
||||
import { browserSession } from './src/runtime.js';
|
||||
import * as fs from 'fs';
|
||||
|
||||
async function main() {
|
||||
console.log("Starting browser session...");
|
||||
await browserSession(PlaywrightMCP, async (page) => {
|
||||
await page.installInterceptor('graphql');
|
||||
|
||||
console.log("Navigating to user lists...");
|
||||
await page.goto('https://x.com/jakevin7/lists');
|
||||
await page.wait(5); // Wait for list APIs to load
|
||||
|
||||
const requests = await page.getInterceptedRequests();
|
||||
const listRequests = requests.filter((r: any) =>
|
||||
r.url.includes('ListsManagementPageTimeline') ||
|
||||
r.url.includes('List')
|
||||
);
|
||||
fs.writeFileSync('list_payload.json', JSON.stringify(listRequests, null, 2));
|
||||
console.log(`Captured ${listRequests.length} List requests. Saved to list_payload.json`);
|
||||
});
|
||||
}
|
||||
|
||||
main().catch(console.error);
|
||||
@@ -0,0 +1,29 @@
|
||||
import { PlaywrightMCP } from './src/browser.js';
|
||||
import { browserSession, runWithTimeout } from './src/runtime.js';
|
||||
import * as fs from 'fs';
|
||||
|
||||
async function main() {
|
||||
console.log("Starting browser session...");
|
||||
await browserSession(PlaywrightMCP, async (page) => {
|
||||
await page.goto('https://x.com/vikingmute/status/2033156347504767135');
|
||||
await page.wait(5); // Wait for hydration
|
||||
|
||||
console.log("Clicking like...");
|
||||
const result = await page.evaluate(`(async () => {
|
||||
let likeBtn = document.querySelector('[data-testid="like"]');
|
||||
if (likeBtn) likeBtn.click();
|
||||
await new Promise(r => setTimeout(r, 2000));
|
||||
|
||||
const elements = document.querySelectorAll('*[data-testid]');
|
||||
const testIds = Array.from(elements).map(el => el.getAttribute('data-testid'));
|
||||
const uniqueIds = [...new Set(testIds)];
|
||||
|
||||
return { uniqueIds };
|
||||
})()`);
|
||||
|
||||
fs.writeFileSync('unlike_testids.json', JSON.stringify(result, null, 2));
|
||||
console.log(`Saved resulting test ids to unlike_testids.json`);
|
||||
});
|
||||
}
|
||||
|
||||
main().catch(console.error);
|
||||
@@ -0,0 +1,68 @@
|
||||
{
|
||||
"actionIds": [
|
||||
"reply",
|
||||
"retweet",
|
||||
"like",
|
||||
"inline_reply_offscreen"
|
||||
],
|
||||
"all": [
|
||||
"GrokDrawer",
|
||||
"GrokDrawerHeader",
|
||||
"chat-drawer-root",
|
||||
"chat-drawer-main",
|
||||
"BottomBar",
|
||||
"AppTabBar_Home_Link",
|
||||
"AppTabBar_Explore_Link",
|
||||
"AppTabBar_Notifications_Link",
|
||||
"AppTabBar_DirectMessage_Link",
|
||||
"premium-hub-tab",
|
||||
"AppTabBar_Profile_Link",
|
||||
"AppTabBar_More_Menu",
|
||||
"SideNav_NewTweet_Button",
|
||||
"SideNav_AccountSwitcher_Button",
|
||||
"UserAvatar-Container-jakevin7",
|
||||
"icon-verified",
|
||||
"primaryColumn",
|
||||
"app-bar-back",
|
||||
"pillLabel",
|
||||
"cellInnerDiv",
|
||||
"tweet",
|
||||
"Tweet-User-Avatar",
|
||||
"UserAvatar-Container-vikingmute",
|
||||
"User-Name",
|
||||
"caret",
|
||||
"tweetText",
|
||||
"tweetPhoto",
|
||||
"app-text-transition-container",
|
||||
"reply",
|
||||
"retweet",
|
||||
"like",
|
||||
"removeBookmark",
|
||||
"inline_reply_offscreen",
|
||||
"progressBar-bar",
|
||||
"tweetTextarea_0_label",
|
||||
"tweetTextarea_0RichTextInputContainer",
|
||||
"tweetTextarea_0",
|
||||
"tweetButtonInline",
|
||||
"UserAvatar-Container-xiaojiang1115",
|
||||
"bookmark",
|
||||
"UserAvatar-Container-jeff180639",
|
||||
"UserAvatar-Container-oran_ge",
|
||||
"UserAvatar-Container-xleaps",
|
||||
"article-cover-image",
|
||||
"UserAvatar-Container-frxiaobei",
|
||||
"UserAvatar-Container-GoJun315",
|
||||
"testCondensedMedia",
|
||||
"previewInterstitial",
|
||||
"UserAvatar-Container-astaxie",
|
||||
"sidebarColumn",
|
||||
"SearchBox_Search_Input_label",
|
||||
"SearchBox_Search_Input",
|
||||
"UserCell",
|
||||
"296593919-follow",
|
||||
"placementTracking",
|
||||
"UserAvatar-Container-unknown",
|
||||
"pill-contents-container",
|
||||
"trend"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
import { cli, Strategy } from '../../registry.js';
|
||||
import type { IPage } from '../../types.js';
|
||||
|
||||
cli({
|
||||
site: 'twitter',
|
||||
name: 'like',
|
||||
description: 'Like a specific tweet',
|
||||
domain: 'x.com',
|
||||
strategy: Strategy.UI, // Utilizes internal DOM flows for interaction
|
||||
browser: true,
|
||||
args: [
|
||||
{ name: 'url', type: 'string', required: true, help: 'The URL of the tweet to like' },
|
||||
],
|
||||
columns: ['status', 'message'],
|
||||
func: async (page: IPage | null, kwargs: any) => {
|
||||
if (!page) throw new Error('Requires browser');
|
||||
|
||||
console.log(`Navigating to tweet: ${kwargs.url}`);
|
||||
await page.goto(kwargs.url);
|
||||
await page.wait(5); // Wait for tweet to load completely
|
||||
|
||||
const result = await page.evaluate(`(async () => {
|
||||
try {
|
||||
// Poll for the tweet to render
|
||||
let attempts = 0;
|
||||
let likeBtn = null;
|
||||
let unlikeBtn = null;
|
||||
|
||||
while (attempts < 20) {
|
||||
unlikeBtn = document.querySelector('[data-testid="unlike"]');
|
||||
likeBtn = document.querySelector('[data-testid="like"]');
|
||||
|
||||
if (unlikeBtn || likeBtn) break;
|
||||
|
||||
await new Promise(r => setTimeout(r, 500));
|
||||
attempts++;
|
||||
}
|
||||
|
||||
// Check if it's already liked
|
||||
if (unlikeBtn) {
|
||||
return { ok: true, message: 'Tweet is already liked.' };
|
||||
}
|
||||
|
||||
if (!likeBtn) {
|
||||
return { ok: false, message: 'Could not find the Like button on this tweet after waiting 10 seconds. Are you logged in?' };
|
||||
}
|
||||
|
||||
// Click Like
|
||||
likeBtn.click();
|
||||
await new Promise(r => setTimeout(r, 1000));
|
||||
|
||||
// Verify success by checking if the 'unlike' button appeared
|
||||
const verifyBtn = document.querySelector('[data-testid="unlike"]');
|
||||
if (verifyBtn) {
|
||||
return { ok: true, message: 'Tweet successfully liked.' };
|
||||
} else {
|
||||
return { ok: false, message: 'Like action was initiated but UI did not update as expected.' };
|
||||
}
|
||||
} catch (e) {
|
||||
return { ok: false, message: e.toString() };
|
||||
}
|
||||
})()`);
|
||||
|
||||
if (result.ok) {
|
||||
// Wait for the like network request to be processed
|
||||
await page.wait(2);
|
||||
}
|
||||
|
||||
return [{
|
||||
status: result.ok ? 'success' : 'failed',
|
||||
message: result.message
|
||||
}];
|
||||
}
|
||||
});
|
||||
+4
-1
@@ -17,6 +17,7 @@ export type DoctorOptions = {
|
||||
shellRc?: string;
|
||||
configPaths?: string[];
|
||||
token?: string;
|
||||
cliVersion?: string;
|
||||
};
|
||||
|
||||
export type ShellFileStatus = {
|
||||
@@ -39,6 +40,7 @@ export type McpConfigStatus = {
|
||||
};
|
||||
|
||||
export type DoctorReport = {
|
||||
cliVersion?: string;
|
||||
envToken: string | null;
|
||||
envFingerprint: string | null;
|
||||
shellFiles: ShellFileStatus[];
|
||||
@@ -284,6 +286,7 @@ export async function runBrowserDoctor(opts: DoctorOptions = {}): Promise<Doctor
|
||||
const recommendedToken = opts.token ?? envToken ?? (uniqueTokens.length === 1 ? uniqueTokens[0] : cdpToken) ?? null;
|
||||
|
||||
const report: DoctorReport = {
|
||||
cliVersion: opts.cliVersion,
|
||||
envToken,
|
||||
envFingerprint: getTokenFingerprint(envToken ?? undefined),
|
||||
shellFiles,
|
||||
@@ -322,7 +325,7 @@ export function renderBrowserDoctorReport(report: DoctorReport): string {
|
||||
].filter((value): value is string => !!value);
|
||||
const uniqueFingerprints = [...new Set(tokenFingerprints)];
|
||||
const hasMismatch = uniqueFingerprints.length > 1;
|
||||
const lines = ['opencli doctor', ''];
|
||||
const lines = [`opencli v${report.cliVersion ?? 'unknown'} doctor`, ''];
|
||||
lines.push(statusLine(report.remoteDebuggingEnabled ? 'OK' : 'WARN', `Chrome remote debugging: ${report.remoteDebuggingEnabled ? 'enabled' : 'disabled'}`));
|
||||
if (report.remoteDebuggingEndpoint) lines.push(` ${report.remoteDebuggingEndpoint}`);
|
||||
|
||||
|
||||
+1
-1
@@ -101,7 +101,7 @@ program.command('doctor')
|
||||
.action(async (opts) => {
|
||||
const { runBrowserDoctor, renderBrowserDoctorReport, applyBrowserDoctorFix } = await import('./doctor.js');
|
||||
const configPaths = opts.mcpConfig ? String(opts.mcpConfig).split(',').map((s: string) => s.trim()).filter(Boolean) : undefined;
|
||||
const report = await runBrowserDoctor({ token: opts.token, shellRc: opts.shellRc, configPaths });
|
||||
const report = await runBrowserDoctor({ token: opts.token, shellRc: opts.shellRc, configPaths, cliVersion: PKG_VERSION });
|
||||
console.log(renderBrowserDoctorReport(report));
|
||||
if (opts.fix) {
|
||||
const written = await applyBrowserDoctorFix(report, { fix: true, yes: opts.yes, token: opts.token, shellRc: opts.shellRc, configPaths });
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
{
|
||||
"uniqueIds": [
|
||||
"GrokDrawer",
|
||||
"GrokDrawerHeader",
|
||||
"chat-drawer-root",
|
||||
"chat-drawer-main",
|
||||
"BottomBar",
|
||||
"AppTabBar_Home_Link",
|
||||
"AppTabBar_Explore_Link",
|
||||
"AppTabBar_Notifications_Link",
|
||||
"AppTabBar_DirectMessage_Link",
|
||||
"premium-hub-tab",
|
||||
"AppTabBar_Profile_Link",
|
||||
"AppTabBar_More_Menu",
|
||||
"SideNav_NewTweet_Button",
|
||||
"SideNav_AccountSwitcher_Button",
|
||||
"UserAvatar-Container-jakevin7",
|
||||
"icon-verified",
|
||||
"primaryColumn",
|
||||
"app-bar-back",
|
||||
"pillLabel",
|
||||
"cellInnerDiv",
|
||||
"tweet",
|
||||
"Tweet-User-Avatar",
|
||||
"UserAvatar-Container-vikingmute",
|
||||
"User-Name",
|
||||
"caret",
|
||||
"tweetText",
|
||||
"tweetPhoto",
|
||||
"app-text-transition-container",
|
||||
"reply",
|
||||
"retweet",
|
||||
"unlike",
|
||||
"removeBookmark",
|
||||
"inline_reply_offscreen",
|
||||
"progressBar-bar",
|
||||
"tweetTextarea_0_label",
|
||||
"tweetTextarea_0RichTextInputContainer",
|
||||
"tweetTextarea_0",
|
||||
"tweetButtonInline",
|
||||
"UserAvatar-Container-xiaojiang1115",
|
||||
"like",
|
||||
"bookmark",
|
||||
"UserAvatar-Container-jeff180639",
|
||||
"UserAvatar-Container-astaxie",
|
||||
"UserAvatar-Container-sanbuphy",
|
||||
"UserAvatar-Container-alswl",
|
||||
"UserAvatar-Container-HiTw93",
|
||||
"article-cover-image",
|
||||
"UserAvatar-Container-oran_ge",
|
||||
"sidebarColumn",
|
||||
"SearchBox_Search_Input_label",
|
||||
"SearchBox_Search_Input",
|
||||
"UserCell",
|
||||
"296593919-follow",
|
||||
"placementTracking",
|
||||
"UserAvatar-Container-unknown",
|
||||
"pill-contents-container",
|
||||
"trend"
|
||||
]
|
||||
}
|
||||
Reference in new issue
Block a user