@xcanwin/manyoyo 5.11.10 → 5.11.11
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/lib/plugin/index.js +3 -1
- package/lib/plugin/playwright.js +123 -30
- package/package.json +1 -1
package/lib/plugin/index.js
CHANGED
|
@@ -31,7 +31,9 @@ function createPlugin(pluginName, options = {}) {
|
|
|
31
31
|
stdout: options.stdout,
|
|
32
32
|
stderr: options.stderr,
|
|
33
33
|
globalConfig: cfg.globalPluginConfig,
|
|
34
|
-
runConfig: cfg.runPluginConfig
|
|
34
|
+
runConfig: cfg.runPluginConfig,
|
|
35
|
+
rootGlobalConfig: asObject(options.globalConfig),
|
|
36
|
+
rootRunConfig: asObject(options.runConfig)
|
|
35
37
|
});
|
|
36
38
|
}
|
|
37
39
|
|
package/lib/plugin/playwright.js
CHANGED
|
@@ -312,6 +312,8 @@ class PlaywrightPlugin {
|
|
|
312
312
|
this.stderr = options.stderr || process.stderr;
|
|
313
313
|
this.globalConfig = asObject(options.globalConfig);
|
|
314
314
|
this.runConfig = asObject(options.runConfig);
|
|
315
|
+
this.rootGlobalConfig = asObject(options.rootGlobalConfig);
|
|
316
|
+
this.rootRunConfig = asObject(options.rootRunConfig);
|
|
315
317
|
this.config = this.resolveConfig();
|
|
316
318
|
}
|
|
317
319
|
|
|
@@ -421,7 +423,7 @@ class PlaywrightPlugin {
|
|
|
421
423
|
if (sceneName !== 'cli-host-headed') {
|
|
422
424
|
return;
|
|
423
425
|
}
|
|
424
|
-
if (this.
|
|
426
|
+
if (this.cliHostContainerAttachConfigReady()) {
|
|
425
427
|
return;
|
|
426
428
|
}
|
|
427
429
|
this.writeStdout('[tip] 如果希望容器内 manyoyo run 自动附着到当前 CLI 宿主场景,请在 ~/.manyoyo/manyoyo.json 中设置:');
|
|
@@ -473,20 +475,17 @@ class PlaywrightPlugin {
|
|
|
473
475
|
return false;
|
|
474
476
|
}
|
|
475
477
|
|
|
476
|
-
|
|
477
|
-
this.writeStdout(
|
|
478
|
-
this.writeStdout('
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
this.writeStdout('
|
|
483
|
-
this.writeStdout('
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
this.writeStdout(' }');
|
|
488
|
-
this.writeStdout(' }');
|
|
489
|
-
this.writeStdout('}');
|
|
478
|
+
writeDevHostUsage(configPath) {
|
|
479
|
+
this.writeStdout('');
|
|
480
|
+
this.writeStdout('若用容器 Agent 操作宿主机浏览器,在宿主机执行:');
|
|
481
|
+
['claude', 'codex', 'gemini'].forEach(runName => {
|
|
482
|
+
this.writeStdout(`my run -r ${runName}`);
|
|
483
|
+
});
|
|
484
|
+
this.writeStdout('');
|
|
485
|
+
this.writeStdout('若用宿主机 Agent 操作宿主机浏览器,在宿主机执行:');
|
|
486
|
+
['claude', 'codex', 'gemini'].forEach(command => {
|
|
487
|
+
this.writeStdout(this.devHostAttachCommand(configPath, command));
|
|
488
|
+
});
|
|
490
489
|
}
|
|
491
490
|
|
|
492
491
|
randomAlnum(length = 16) {
|
|
@@ -594,6 +593,109 @@ class PlaywrightPlugin {
|
|
|
594
593
|
fs.rmSync(this.sceneCliAttachConfigPath(sceneName), { force: true });
|
|
595
594
|
}
|
|
596
595
|
|
|
596
|
+
buildDevHostAttachConfig(endpoint, cdpHost) {
|
|
597
|
+
return {
|
|
598
|
+
outputDir: '/tmp/.playwright-cli',
|
|
599
|
+
browser: {
|
|
600
|
+
cdpEndpoint: `ws://${cdpHost}:${endpoint.port}${endpoint.wsPath}`,
|
|
601
|
+
cdpHeaders: {
|
|
602
|
+
Host: `127.0.0.1:${endpoint.port}`
|
|
603
|
+
},
|
|
604
|
+
cdpTimeout: this.config.devtoolsCdpTimeout
|
|
605
|
+
}
|
|
606
|
+
};
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
writeDevHostAttachConfig(sceneName, endpoint) {
|
|
610
|
+
fs.mkdirSync(this.config.configDir, { recursive: true });
|
|
611
|
+
const filePath = this.sceneConfigPath(sceneName);
|
|
612
|
+
fs.writeFileSync(filePath, `${JSON.stringify(this.buildDevHostAttachConfig(endpoint, '127.0.0.1'), null, 4)}\n`, 'utf8');
|
|
613
|
+
return filePath;
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
removeDevHostAttachConfig(sceneName) {
|
|
617
|
+
fs.rmSync(this.sceneConfigPath(sceneName), { force: true });
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
userDisplayPath(filePath) {
|
|
621
|
+
const normalizedPath = path.resolve(filePath);
|
|
622
|
+
const normalizedHome = path.resolve(this.config.homeDir);
|
|
623
|
+
if (normalizedPath === normalizedHome) {
|
|
624
|
+
return '~';
|
|
625
|
+
}
|
|
626
|
+
if (normalizedPath.startsWith(`${normalizedHome}${path.sep}`)) {
|
|
627
|
+
return `~${normalizedPath.slice(normalizedHome.length)}`;
|
|
628
|
+
}
|
|
629
|
+
return filePath;
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
shellValue(value) {
|
|
633
|
+
const text = String(value);
|
|
634
|
+
if (/^[A-Za-z0-9_@%+=:,./~-]+$/.test(text)) {
|
|
635
|
+
return text;
|
|
636
|
+
}
|
|
637
|
+
return `'${text.replace(/'/g, "'\\''")}'`;
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
devHostAttachEnvEntries(configPath) {
|
|
641
|
+
return [
|
|
642
|
+
`PLAYWRIGHT_MCP_CONFIG=${this.shellValue(this.userDisplayPath(configPath))}`
|
|
643
|
+
];
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
devHostAttachCommand(configPath, command) {
|
|
647
|
+
return `${this.devHostAttachEnvEntries(configPath).join(' ')} ${command}`;
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
expandHomePath(value) {
|
|
651
|
+
const text = String(value || '').trim();
|
|
652
|
+
if (text === '~') {
|
|
653
|
+
return this.config.homeDir;
|
|
654
|
+
}
|
|
655
|
+
if (text.startsWith('~/')) {
|
|
656
|
+
return path.join(this.config.homeDir, text.slice(2));
|
|
657
|
+
}
|
|
658
|
+
return text;
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
parseVolumeEntry(value) {
|
|
662
|
+
const parts = String(value || '').split(':');
|
|
663
|
+
if (parts.length < 2) {
|
|
664
|
+
return null;
|
|
665
|
+
}
|
|
666
|
+
return {
|
|
667
|
+
hostPath: path.resolve(this.expandHomePath(parts[0])),
|
|
668
|
+
containerPath: parts[1]
|
|
669
|
+
};
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
mergedRootVolumes() {
|
|
673
|
+
return [
|
|
674
|
+
...asStringArray(this.rootGlobalConfig.volumes, []),
|
|
675
|
+
...asStringArray(this.rootRunConfig.volumes, []),
|
|
676
|
+
...asStringArray(this.globalConfig.volumes, []),
|
|
677
|
+
...asStringArray(this.runConfig.volumes, [])
|
|
678
|
+
];
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
hasRootVolume(required) {
|
|
682
|
+
const parsedRequired = this.parseVolumeEntry(required);
|
|
683
|
+
if (!parsedRequired) {
|
|
684
|
+
return false;
|
|
685
|
+
}
|
|
686
|
+
return this.mergedRootVolumes().some(item => {
|
|
687
|
+
const parsed = this.parseVolumeEntry(item);
|
|
688
|
+
return parsed
|
|
689
|
+
&& parsed.hostPath === parsedRequired.hostPath
|
|
690
|
+
&& parsed.containerPath === parsedRequired.containerPath;
|
|
691
|
+
});
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
cliHostContainerAttachConfigReady() {
|
|
695
|
+
return this.config.cliSessionScene === 'cli-host-headed'
|
|
696
|
+
&& this.hasRootVolume('~/.manyoyo/.cache/ms-playwright:/root/.cache/ms-playwright');
|
|
697
|
+
}
|
|
698
|
+
|
|
597
699
|
devtoolsActivePortCandidates() {
|
|
598
700
|
const homeDir = this.config.homeDir;
|
|
599
701
|
const configured = this.config.devtoolsActivePortPath;
|
|
@@ -1168,24 +1270,13 @@ class PlaywrightPlugin {
|
|
|
1168
1270
|
const endpoint = this.readDevToolsActivePort();
|
|
1169
1271
|
const normalizedDockerCmd = String(dockerCmd || '').trim().toLowerCase();
|
|
1170
1272
|
const connectHost = normalizedDockerCmd === 'podman' ? 'host.containers.internal' : 'host.docker.internal';
|
|
1171
|
-
const cdpEndpoint = `ws://${connectHost}:${endpoint.port}${endpoint.wsPath}`;
|
|
1172
1273
|
const hostConfigPath = this.sceneCliAttachConfigPath(sceneName);
|
|
1173
1274
|
const containerConfigPath = `/tmp/manyoyo-playwright/${sceneName}.cli-attach.json`;
|
|
1174
1275
|
|
|
1175
|
-
this.writeSceneCliAttachConfig(sceneName,
|
|
1176
|
-
outputDir: '/tmp/.playwright-cli',
|
|
1177
|
-
browser: {
|
|
1178
|
-
cdpEndpoint,
|
|
1179
|
-
cdpHeaders: {
|
|
1180
|
-
Host: `127.0.0.1:${endpoint.port}`
|
|
1181
|
-
},
|
|
1182
|
-
cdpTimeout: this.config.devtoolsCdpTimeout
|
|
1183
|
-
}
|
|
1184
|
-
});
|
|
1276
|
+
this.writeSceneCliAttachConfig(sceneName, this.buildDevHostAttachConfig(endpoint, connectHost));
|
|
1185
1277
|
|
|
1186
1278
|
const envEntries = [
|
|
1187
|
-
`PLAYWRIGHT_MCP_CONFIG=${containerConfigPath}
|
|
1188
|
-
'PW_CHROMIUM_ATTACH_TO_OTHER=1'
|
|
1279
|
+
`PLAYWRIGHT_MCP_CONFIG=${containerConfigPath}`
|
|
1189
1280
|
];
|
|
1190
1281
|
const extraArgs = normalizedDockerCmd === 'docker'
|
|
1191
1282
|
? ['--add-host', 'host.docker.internal:host-gateway']
|
|
@@ -1506,12 +1597,13 @@ class PlaywrightPlugin {
|
|
|
1506
1597
|
if (!(await this.portReady(endpoint.port))) {
|
|
1507
1598
|
throw new Error(`DevToolsActivePort 指向 127.0.0.1:${endpoint.port},但该端口不可连接;请确认 Chrome remote debugging 已启用,或重新打开 Chrome 后再试。`);
|
|
1508
1599
|
}
|
|
1600
|
+
const cfgPath = this.writeDevHostAttachConfig(sceneName, endpoint);
|
|
1509
1601
|
this.writeStdout(`[up] ${sceneName} ready via DevToolsActivePort (${endpoint.filePath}, 127.0.0.1:${endpoint.port})`);
|
|
1510
|
-
this.
|
|
1602
|
+
this.writeStdout(`[tip] 已尝试打开 ${this.remoteDebuggingPageUrl()},请确认 remote debugging 已启用。`);
|
|
1603
|
+
this.writeDevHostUsage(cfgPath);
|
|
1511
1604
|
return 0;
|
|
1512
1605
|
} catch (error) {
|
|
1513
1606
|
this.writeStderr(`[up] ${sceneName} failed: ${error.message || String(error)}`);
|
|
1514
|
-
this.remindDevHostCliSessionScene();
|
|
1515
1607
|
return 1;
|
|
1516
1608
|
}
|
|
1517
1609
|
}
|
|
@@ -1559,6 +1651,7 @@ class PlaywrightPlugin {
|
|
|
1559
1651
|
stopDevHost(sceneName) {
|
|
1560
1652
|
this.removeSceneEndpoint(sceneName);
|
|
1561
1653
|
this.removeSceneCliAttachConfig(sceneName);
|
|
1654
|
+
this.removeDevHostAttachConfig(sceneName);
|
|
1562
1655
|
this.writeStdout(`[down] ${sceneName} no managed process`);
|
|
1563
1656
|
return 0;
|
|
1564
1657
|
}
|