@xcanwin/manyoyo 5.1.3 → 5.1.4

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/manyoyo.js CHANGED
@@ -874,7 +874,8 @@ async function setupCommander() {
874
874
  pluginName: params.pluginName || 'playwright',
875
875
  pluginScene: params.scene || 'host-headless',
876
876
  pluginHost: params.host || '',
877
- pluginExtensions: Array.isArray(params.extensions) ? params.extensions : [],
877
+ pluginExtensionPaths: Array.isArray(params.extensionPaths) ? params.extensionPaths : [],
878
+ pluginExtensionNames: Array.isArray(params.extensionNames) ? params.extensionNames : [],
878
879
  pluginProdversion: params.prodversion || ''
879
880
  });
880
881
  };
@@ -896,14 +897,16 @@ async function setupCommander() {
896
897
  .option('-r, --run <name>', '加载运行配置 (从 ~/.manyoyo/manyoyo.json 的 runs.<name> 读取)');
897
898
 
898
899
  if (action === 'up') {
899
- appendArrayOption(sceneCommand, '--ext <path>', '追加浏览器扩展目录(可多次传入;目录需包含 manifest.json)');
900
+ appendArrayOption(sceneCommand, '--ext-path <path>', '追加浏览器扩展目录(可多次传入;目录需包含 manifest.json)');
901
+ appendArrayOption(sceneCommand, '--ext-name <name>', '追加 ~/.manyoyo/plugin/playwright/extensions/ 下的扩展目录名(可多次传入)');
900
902
  }
901
903
 
902
904
  sceneCommand.action((scene, options) => selectPluginAction({
903
905
  action,
904
906
  pluginName: 'playwright',
905
907
  scene: scene || 'host-headless',
906
- extensions: action === 'up' ? (options.ext || []) : []
908
+ extensionPaths: action === 'up' ? (options.extPath || []) : [],
909
+ extensionNames: action === 'up' ? (options.extName || []) : []
907
910
  }, options));
908
911
  });
909
912
 
@@ -1114,7 +1117,8 @@ async function setupCommander() {
1114
1117
  pluginName: options.pluginName,
1115
1118
  scene: options.pluginScene || 'host-headless',
1116
1119
  host: options.pluginHost || '',
1117
- extensions: Array.isArray(options.pluginExtensions) ? options.pluginExtensions : [],
1120
+ extensionPaths: Array.isArray(options.pluginExtensionPaths) ? options.pluginExtensionPaths : [],
1121
+ extensionNames: Array.isArray(options.pluginExtensionNames) ? options.pluginExtensionNames : [],
1118
1122
  prodversion: options.pluginProdversion || ''
1119
1123
  },
1120
1124
  pluginGlobalConfig: config,
@@ -53,7 +53,8 @@ async function runPluginCommand(request, options = {}) {
53
53
  action,
54
54
  scene: request.scene,
55
55
  host: request.host,
56
- extensions: request.extensions,
56
+ extensionPaths: request.extensionPaths,
57
+ extensionNames: request.extensionNames,
57
58
  prodversion: request.prodversion
58
59
  });
59
60
  }
@@ -339,6 +339,32 @@ class PlaywrightPlugin {
339
339
  return path.join(this.config.configDir, def.configFile);
340
340
  }
341
341
 
342
+ sceneConfigMissing(sceneName) {
343
+ return !fs.existsSync(this.sceneConfigPath(sceneName));
344
+ }
345
+
346
+ defaultBrowserName(sceneName) {
347
+ const cfg = this.buildSceneConfig(sceneName);
348
+ const browserName = cfg && cfg.browser && cfg.browser.browserName;
349
+ return String(browserName || 'chromium');
350
+ }
351
+
352
+ ensureContainerScenePrerequisites(sceneName) {
353
+ if (!this.sceneConfigMissing(sceneName)) {
354
+ return;
355
+ }
356
+ const tag = String(this.config.dockerTag || 'latest').trim() || 'latest';
357
+ const image = `mcr.microsoft.com/playwright/mcp:${tag}`;
358
+ this.runCmd([this.config.containerRuntime, 'pull', image], { check: true });
359
+ }
360
+
361
+ ensureHostScenePrerequisites(sceneName) {
362
+ if (!this.sceneConfigMissing(sceneName)) {
363
+ return;
364
+ }
365
+ this.runCmd(['npx', '-y', 'playwright-core', 'install', this.defaultBrowserName(sceneName)], { check: true });
366
+ }
367
+
342
368
  scenePidFile(sceneName) {
343
369
  return path.join(this.config.runDir, `${sceneName}.pid`);
344
370
  }
@@ -430,6 +456,24 @@ class PlaywrightPlugin {
430
456
  return uniquePaths;
431
457
  }
432
458
 
459
+ resolveNamedExtensionPaths(extensionNames = []) {
460
+ const names = asStringArray(extensionNames, []);
461
+ const extensionRoot = path.resolve(this.extensionDirPath());
462
+
463
+ return names.map(name => {
464
+ if (name.includes('/') || name.includes('\\') || name === '.' || name === '..') {
465
+ throw new Error(`扩展名称无效: ${name}`);
466
+ }
467
+ return path.join(extensionRoot, name);
468
+ });
469
+ }
470
+
471
+ resolveExtensionInputs(options = {}) {
472
+ const extensionPaths = asStringArray(options.extensionPaths, []);
473
+ const namedPaths = this.resolveNamedExtensionPaths(options.extensionNames || []);
474
+ return this.resolveExtensionPaths([...extensionPaths, ...namedPaths]);
475
+ }
476
+
433
477
  buildExtensionLaunchArgs(extensionPaths) {
434
478
  const joined = extensionPaths.join(',');
435
479
  return [
@@ -601,6 +645,12 @@ class PlaywrightPlugin {
601
645
  return 1;
602
646
  }
603
647
 
648
+ try {
649
+ this.ensureContainerScenePrerequisites(sceneName);
650
+ } catch (error) {
651
+ return error.returncode || 1;
652
+ }
653
+
604
654
  const incomingExtensionPaths = asStringArray(options.extensionPaths, []);
605
655
  let configOptions = { ...options, extensionPaths: incomingExtensionPaths };
606
656
  const composeFiles = [this.containerComposePath(sceneName)];
@@ -798,6 +848,12 @@ class PlaywrightPlugin {
798
848
  return 1;
799
849
  }
800
850
 
851
+ try {
852
+ this.ensureHostScenePrerequisites(sceneName);
853
+ } catch (error) {
854
+ return error.returncode || 1;
855
+ }
856
+
801
857
  fs.mkdirSync(this.config.runDir, { recursive: true });
802
858
  const cfgPath = this.ensureSceneConfig(sceneName, options);
803
859
  const pidFile = this.scenePidFile(sceneName);
@@ -1137,7 +1193,7 @@ class PlaywrightPlugin {
1137
1193
  return 1;
1138
1194
  }
1139
1195
 
1140
- async run({ action, scene = 'host-headless', host = '', extensions = [], prodversion = '' }) {
1196
+ async run({ action, scene = 'host-headless', host = '', extensionPaths = [], extensionNames = [], prodversion = '' }) {
1141
1197
  if (action === 'ls') {
1142
1198
  return this.printSummary();
1143
1199
  }
@@ -1160,14 +1216,14 @@ class PlaywrightPlugin {
1160
1216
  return 1;
1161
1217
  }
1162
1218
 
1163
- const extensionPaths = action === 'up'
1164
- ? this.resolveExtensionPaths(extensions)
1219
+ const resolvedExtensionPaths = action === 'up'
1220
+ ? this.resolveExtensionInputs({ extensionPaths, extensionNames })
1165
1221
  : [];
1166
1222
 
1167
1223
  let rc = 0;
1168
1224
  for (const sceneName of targets) {
1169
1225
  // eslint-disable-next-line no-await-in-loop
1170
- const code = await this.runOnScene(action, sceneName, { extensionPaths });
1226
+ const code = await this.runOnScene(action, sceneName, { extensionPaths: resolvedExtensionPaths });
1171
1227
  if (code !== 0) {
1172
1228
  rc = 1;
1173
1229
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xcanwin/manyoyo",
3
- "version": "5.1.3",
3
+ "version": "5.1.4",
4
4
  "imageVersion": "1.8.1-common",
5
5
  "description": "AI Agent CLI Security Sandbox for Docker and Podman",
6
6
  "keywords": [