@guanzhu.me/pw-cli 0.0.8 → 0.0.10
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/bin/pw-cli.js +20 -17
- package/package.json +1 -1
- package/src/utils.js +24 -1
package/bin/pw-cli.js
CHANGED
|
@@ -724,14 +724,15 @@ async function main() {
|
|
|
724
724
|
}
|
|
725
725
|
|
|
726
726
|
// Ensures a browser is reachable via CDP; if not, spawns playwright-cli open first.
|
|
727
|
+
// Returns the CDP port number.
|
|
727
728
|
async function ensureBrowserRunning() {
|
|
728
729
|
const { getPlaywrightCliCdpPort } = require('../src/browser-manager');
|
|
729
730
|
const { probeCDP } = require('../src/utils');
|
|
730
731
|
const { readState } = require('../src/state');
|
|
731
732
|
const cliPort = getPlaywrightCliCdpPort();
|
|
732
|
-
if (cliPort && await probeCDP(cliPort, 2000)) return;
|
|
733
|
+
if (cliPort && await probeCDP(cliPort, 2000)) return cliPort;
|
|
733
734
|
const state = readState();
|
|
734
|
-
if (state && await probeCDP(state.port, 2000)) return;
|
|
735
|
+
if (state && await probeCDP(state.port, 2000)) return state.port;
|
|
735
736
|
// No browser reachable — start one via playwright-cli
|
|
736
737
|
const { spawnSync } = require('child_process');
|
|
737
738
|
const res = spawnSync(process.execPath, [cliPath, 'open', '--headed', '--persistent', '--profile', DEFAULT_PROFILE], {
|
|
@@ -742,33 +743,31 @@ async function main() {
|
|
|
742
743
|
process.stderr.write('pw-cli: failed to open browser\n');
|
|
743
744
|
process.exit(res.status || 1);
|
|
744
745
|
}
|
|
746
|
+
// After spawning, re-detect the port
|
|
747
|
+
const newCliPort = getPlaywrightCliCdpPort();
|
|
748
|
+
if (newCliPort) return newCliPort;
|
|
749
|
+
const newState = readState();
|
|
750
|
+
return newState ? newState.port : null;
|
|
745
751
|
}
|
|
746
752
|
|
|
747
|
-
// ── goto: navigate the
|
|
753
|
+
// ── goto: navigate the active tab (detected via CDP /json/list) ──────────
|
|
748
754
|
if (command === 'goto') {
|
|
749
755
|
const gotoIdx = rawArgv.indexOf('goto');
|
|
750
756
|
const afterGoto = rawArgv.slice(gotoIdx + 1);
|
|
751
757
|
const rawUrl = afterGoto.find(a => !a.startsWith('-'));
|
|
752
758
|
if (rawUrl) {
|
|
753
759
|
const fullUrl = /^https?:\/\//.test(rawUrl) ? rawUrl : `https://${rawUrl}`;
|
|
760
|
+
const cdpPort = await ensureBrowserRunning();
|
|
761
|
+
const { fetchActivePageUrl } = require('../src/utils');
|
|
762
|
+
const activeUrl = await fetchActivePageUrl(cdpPort);
|
|
754
763
|
const navCode = `async (page, context) => {
|
|
755
764
|
const pages = context.pages();
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
p.evaluate(() => document.hidden),
|
|
760
|
-
p.evaluate(() => document.hasFocus()),
|
|
761
|
-
]);
|
|
762
|
-
return { p, hidden, focused };
|
|
763
|
-
} catch { return { p, hidden: true, focused: false }; }
|
|
764
|
-
}));
|
|
765
|
-
const focused = info.find(v => v.focused);
|
|
766
|
-
const visible = info.filter(v => !v.hidden);
|
|
767
|
-
const target = (focused || visible[visible.length - 1] || info[info.length - 1]).p;
|
|
765
|
+
let target = pages[pages.length - 1] || page;
|
|
766
|
+
${activeUrl ? `const match = pages.find(p => p.url() === ${JSON.stringify(activeUrl)});
|
|
767
|
+
if (match) target = match;` : ''}
|
|
768
768
|
await target.goto(${JSON.stringify(fullUrl)}, { waitUntil: 'domcontentloaded', timeout: 0 });
|
|
769
769
|
return target.url();
|
|
770
770
|
}`;
|
|
771
|
-
await ensureBrowserRunning();
|
|
772
771
|
await handleRunCode(['run-code', navCode]);
|
|
773
772
|
return;
|
|
774
773
|
}
|
|
@@ -815,7 +814,11 @@ async function main() {
|
|
|
815
814
|
const rawUrlArg = afterOpen.find(a => !a.startsWith('-') && /^(https?:\/\/|[a-zA-Z0-9]([a-zA-Z0-9-]*\.)+[a-zA-Z]{2,})/.test(a));
|
|
816
815
|
const urlArg = rawUrlArg && !/^https?:\/\//.test(rawUrlArg) ? `https://${rawUrlArg}` : rawUrlArg;
|
|
817
816
|
if (urlArg) {
|
|
818
|
-
const navCode = `async page => {
|
|
817
|
+
const navCode = `async page => {
|
|
818
|
+
const newPage = await page.context().newPage();
|
|
819
|
+
await newPage.goto(${JSON.stringify(urlArg)}, { waitUntil: 'domcontentloaded', timeout: 0 });
|
|
820
|
+
return newPage.url();
|
|
821
|
+
}`;
|
|
819
822
|
await ensureBrowserRunning();
|
|
820
823
|
await handleRunCode(['run-code', navCode]);
|
|
821
824
|
return;
|
package/package.json
CHANGED
package/src/utils.js
CHANGED
|
@@ -52,4 +52,27 @@ function sleep(ms) {
|
|
|
52
52
|
return new Promise(r => setTimeout(r, ms));
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
|
|
55
|
+
/**
|
|
56
|
+
* Fetch the URL of the most recently active page tab via Chrome's /json/list endpoint.
|
|
57
|
+
* Chrome returns targets ordered by most-recently-activated first.
|
|
58
|
+
* Returns the URL string, or null if no page target found.
|
|
59
|
+
*/
|
|
60
|
+
function fetchActivePageUrl(port) {
|
|
61
|
+
return new Promise(resolve => {
|
|
62
|
+
const req = http.get(`http://127.0.0.1:${port}/json/list`, { timeout: 3000 }, res => {
|
|
63
|
+
let data = '';
|
|
64
|
+
res.on('data', chunk => { data += chunk; });
|
|
65
|
+
res.on('end', () => {
|
|
66
|
+
try {
|
|
67
|
+
const targets = JSON.parse(data);
|
|
68
|
+
const page = targets.find(t => t.type === 'page');
|
|
69
|
+
resolve(page ? page.url : null);
|
|
70
|
+
} catch { resolve(null); }
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
req.on('error', () => resolve(null));
|
|
74
|
+
req.on('timeout', () => { req.destroy(); resolve(null); });
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
module.exports = { readStdin, die, probeCDP, findFreePort, sleep, fetchActivePageUrl };
|