@xcanwin/manyoyo 5.1.6 → 5.1.9
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/playwright.js +59 -18
- package/package.json +3 -1
package/lib/plugin/playwright.js
CHANGED
|
@@ -4,6 +4,7 @@ const fs = require('fs');
|
|
|
4
4
|
const net = require('net');
|
|
5
5
|
const os = require('os');
|
|
6
6
|
const path = require('path');
|
|
7
|
+
const crypto = require('crypto');
|
|
7
8
|
const { spawn, spawnSync } = require('child_process');
|
|
8
9
|
|
|
9
10
|
const EXTENSIONS = [
|
|
@@ -235,8 +236,7 @@ class PlaywrightPlugin {
|
|
|
235
236
|
hostListen: '127.0.0.1',
|
|
236
237
|
mcpDefaultHost: 'host.docker.internal',
|
|
237
238
|
dockerTag: process.env.PLAYWRIGHT_MCP_DOCKER_TAG || 'latest',
|
|
238
|
-
|
|
239
|
-
containerRuntime: 'podman',
|
|
239
|
+
containerRuntime: '',
|
|
240
240
|
vncPasswordEnvKey: 'VNC_PASSWORD',
|
|
241
241
|
headedImage: 'localhost/xcanwin/manyoyo-playwright-headed',
|
|
242
242
|
configDir: path.join(pluginRootDir, 'config'),
|
|
@@ -272,6 +272,7 @@ class PlaywrightPlugin {
|
|
|
272
272
|
this.runConfig.enabledScenes,
|
|
273
273
|
asStringArray(this.globalConfig.enabledScenes, [...defaultConfig.enabledScenes])
|
|
274
274
|
);
|
|
275
|
+
merged.containerRuntime = this.resolveContainerRuntime(merged.containerRuntime);
|
|
275
276
|
|
|
276
277
|
if (merged.enabledScenes.length === 0) {
|
|
277
278
|
throw new Error('playwright.enabledScenes 不能为空');
|
|
@@ -285,6 +286,22 @@ class PlaywrightPlugin {
|
|
|
285
286
|
return merged;
|
|
286
287
|
}
|
|
287
288
|
|
|
289
|
+
resolveContainerRuntime(configuredRuntime) {
|
|
290
|
+
const configured = String(configuredRuntime || '').trim().toLowerCase();
|
|
291
|
+
if (configured) {
|
|
292
|
+
return configured;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
const candidates = ['docker', 'podman'];
|
|
296
|
+
for (const cmd of candidates) {
|
|
297
|
+
if (this.ensureCommandAvailable(cmd)) {
|
|
298
|
+
return cmd;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
return 'docker';
|
|
303
|
+
}
|
|
304
|
+
|
|
288
305
|
writeStdout(line = '') {
|
|
289
306
|
this.stdout.write(`${line}\n`);
|
|
290
307
|
}
|
|
@@ -293,6 +310,15 @@ class PlaywrightPlugin {
|
|
|
293
310
|
this.stderr.write(`${line}\n`);
|
|
294
311
|
}
|
|
295
312
|
|
|
313
|
+
randomAlnum(length = 16) {
|
|
314
|
+
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
|
315
|
+
let out = '';
|
|
316
|
+
for (let i = 0; i < length; i += 1) {
|
|
317
|
+
out += chars[crypto.randomInt(0, chars.length)];
|
|
318
|
+
}
|
|
319
|
+
return out;
|
|
320
|
+
}
|
|
321
|
+
|
|
296
322
|
runCmd(args, { env = null, captureOutput = false, check = true } = {}) {
|
|
297
323
|
const result = spawnSync(args[0], args.slice(1), {
|
|
298
324
|
encoding: 'utf8',
|
|
@@ -370,7 +396,7 @@ class PlaywrightPlugin {
|
|
|
370
396
|
if (!this.sceneConfigMissing(sceneName)) {
|
|
371
397
|
return;
|
|
372
398
|
}
|
|
373
|
-
this.runCmd(['
|
|
399
|
+
this.runCmd([this.localBinPath('playwright'), 'install', '--with-deps', this.defaultBrowserName(sceneName)], { check: true });
|
|
374
400
|
}
|
|
375
401
|
|
|
376
402
|
scenePidFile(sceneName) {
|
|
@@ -381,6 +407,15 @@ class PlaywrightPlugin {
|
|
|
381
407
|
return path.join(this.config.runDir, `${sceneName}.log`);
|
|
382
408
|
}
|
|
383
409
|
|
|
410
|
+
localBinPath(binName) {
|
|
411
|
+
const filename = process.platform === 'win32' ? `${binName}.cmd` : binName;
|
|
412
|
+
const binPath = path.join(this.projectRoot, 'node_modules', '.bin', filename);
|
|
413
|
+
if (!fs.existsSync(binPath)) {
|
|
414
|
+
throw new Error(`local binary not found: ${binPath}. Run npm install first.`);
|
|
415
|
+
}
|
|
416
|
+
return binPath;
|
|
417
|
+
}
|
|
418
|
+
|
|
384
419
|
extensionDirPath() {
|
|
385
420
|
return path.join(os.homedir(), '.manyoyo', 'plugin', 'playwright', 'extensions');
|
|
386
421
|
}
|
|
@@ -600,7 +635,7 @@ class PlaywrightPlugin {
|
|
|
600
635
|
}
|
|
601
636
|
|
|
602
637
|
async waitForPort(port) {
|
|
603
|
-
for (let i = 0; i <
|
|
638
|
+
for (let i = 0; i < 60; i += 1) {
|
|
604
639
|
// eslint-disable-next-line no-await-in-loop
|
|
605
640
|
if (await this.portReady(port)) {
|
|
606
641
|
return true;
|
|
@@ -626,13 +661,14 @@ class PlaywrightPlugin {
|
|
|
626
661
|
|
|
627
662
|
if (sceneName === 'cont-headed') {
|
|
628
663
|
const envKey = this.config.vncPasswordEnvKey;
|
|
629
|
-
|
|
630
|
-
if (!password
|
|
631
|
-
|
|
664
|
+
let password = process.env[envKey];
|
|
665
|
+
if (!password) {
|
|
666
|
+
password = this.randomAlnum(16);
|
|
667
|
+
if (requireVncPassword) {
|
|
668
|
+
this.writeStdout(`[up] cont-headed ${envKey} not set; generated random 16-char password: ${password}`);
|
|
669
|
+
}
|
|
632
670
|
}
|
|
633
|
-
|
|
634
|
-
// Keep `up` strict, but use a non-empty placeholder for non-up actions.
|
|
635
|
-
env.VNC_PASSWORD = password || '__MANYOYO_PLACEHOLDER__';
|
|
671
|
+
env.VNC_PASSWORD = password;
|
|
636
672
|
}
|
|
637
673
|
|
|
638
674
|
return env;
|
|
@@ -813,8 +849,8 @@ class PlaywrightPlugin {
|
|
|
813
849
|
return cp.returncode === 0 ? 0 : 1;
|
|
814
850
|
}
|
|
815
851
|
|
|
816
|
-
spawnHostProcess(cfgPath, logFd) {
|
|
817
|
-
return spawn(
|
|
852
|
+
spawnHostProcess(mcpBinPath, cfgPath, logFd) {
|
|
853
|
+
return spawn(mcpBinPath, ['--config', String(cfgPath)], {
|
|
818
854
|
detached: true,
|
|
819
855
|
stdio: ['ignore', logFd, logFd]
|
|
820
856
|
});
|
|
@@ -872,14 +908,10 @@ class PlaywrightPlugin {
|
|
|
872
908
|
}
|
|
873
909
|
|
|
874
910
|
async startHost(sceneName, options = {}) {
|
|
875
|
-
if (!this.ensureCommandAvailable('npx')) {
|
|
876
|
-
this.writeStderr(`[up] ${sceneName} failed: npx command not found.`);
|
|
877
|
-
return 1;
|
|
878
|
-
}
|
|
879
|
-
|
|
880
911
|
try {
|
|
881
912
|
this.ensureHostScenePrerequisites(sceneName);
|
|
882
913
|
} catch (error) {
|
|
914
|
+
this.writeStderr(`[up] ${sceneName} failed: ${error.message || String(error)}`);
|
|
883
915
|
return error.returncode || 1;
|
|
884
916
|
}
|
|
885
917
|
|
|
@@ -903,7 +935,16 @@ class PlaywrightPlugin {
|
|
|
903
935
|
|
|
904
936
|
fs.rmSync(pidFile, { force: true });
|
|
905
937
|
const logFd = fs.openSync(logFile, 'a');
|
|
906
|
-
|
|
938
|
+
let mcpBinPath = '';
|
|
939
|
+
try {
|
|
940
|
+
mcpBinPath = this.localBinPath('playwright-mcp');
|
|
941
|
+
} catch (error) {
|
|
942
|
+
fs.closeSync(logFd);
|
|
943
|
+
this.writeStderr(`[up] ${sceneName} failed: ${error.message || String(error)}`);
|
|
944
|
+
return 1;
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
const starter = this.spawnHostProcess(mcpBinPath, cfgPath, logFd);
|
|
907
948
|
fs.closeSync(logFd);
|
|
908
949
|
if (typeof starter.unref === 'function') {
|
|
909
950
|
starter.unref();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xcanwin/manyoyo",
|
|
3
|
-
"version": "5.1.
|
|
3
|
+
"version": "5.1.9",
|
|
4
4
|
"imageVersion": "1.8.1-common",
|
|
5
5
|
"description": "AI Agent CLI Security Sandbox for Docker and Podman",
|
|
6
6
|
"keywords": [
|
|
@@ -53,10 +53,12 @@
|
|
|
53
53
|
"config.example.json"
|
|
54
54
|
],
|
|
55
55
|
"dependencies": {
|
|
56
|
+
"@playwright/mcp": "0.0.68",
|
|
56
57
|
"@xterm/addon-fit": "^0.11.0",
|
|
57
58
|
"@xterm/xterm": "^6.0.0",
|
|
58
59
|
"commander": "^12.0.0",
|
|
59
60
|
"json5": "^2.2.3",
|
|
61
|
+
"playwright": "1.58.2",
|
|
60
62
|
"ws": "^8.19.0"
|
|
61
63
|
},
|
|
62
64
|
"devDependencies": {
|