@xcanwin/manyoyo 5.7.9 → 5.7.12

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/README.md CHANGED
@@ -52,10 +52,11 @@ AI Agent CLI 往往需要:
52
52
 
53
53
  ```bash
54
54
  npm install -g @xcanwin/manyoyo
55
- podman pull ubuntu:24.04 # 仅 Podman 需要
55
+ podman pull ubuntu:24.04 # 仅 Podman 需要
56
56
  manyoyo build --iv 1.9.0-common
57
57
  manyoyo init all
58
58
  manyoyo run -r claude
59
+ manyoyo serve 127.0.0.1:3000 -U admin -P 123456 # Web UI 模式
59
60
  ```
60
61
 
61
62
  系统要求:
@@ -122,7 +123,7 @@ manyoyo images
122
123
  manyoyo run -n my-dev -x /bin/bash
123
124
  manyoyo rm my-dev
124
125
 
125
- # Web 模式
126
+ # Web UI 模式
126
127
  manyoyo serve 127.0.0.1:3000
127
128
  manyoyo serve 127.0.0.1:3000 -U admin -P 123456
128
129
  manyoyo serve 127.0.0.1:3000 -U admin -P 123456 -d
@@ -801,6 +801,25 @@ class PlaywrightPlugin {
801
801
  launchOptions.args.push(...DISABLE_WEBRTC_LAUNCH_ARGS);
802
802
  }
803
803
 
804
+ const contextOptions = {
805
+ userAgent: DEFAULT_FINGERPRINT_PROFILE.userAgent,
806
+ locale: DEFAULT_FINGERPRINT_PROFILE.locale,
807
+ timezoneId: DEFAULT_FINGERPRINT_PROFILE.timezoneId,
808
+ extraHTTPHeaders: {
809
+ 'Accept-Language': DEFAULT_FINGERPRINT_PROFILE.acceptLanguage
810
+ }
811
+ };
812
+ if (sceneName !== 'mcp-host-headed') {
813
+ contextOptions.viewport = {
814
+ width: DEFAULT_FINGERPRINT_PROFILE.width,
815
+ height: DEFAULT_FINGERPRINT_PROFILE.height
816
+ };
817
+ contextOptions.screen = {
818
+ width: DEFAULT_FINGERPRINT_PROFILE.width,
819
+ height: DEFAULT_FINGERPRINT_PROFILE.height
820
+ };
821
+ }
822
+
804
823
  return {
805
824
  outputDir: '/tmp/.playwright-mcp',
806
825
  server: {
@@ -818,22 +837,7 @@ class PlaywrightPlugin {
818
837
  browserName: 'chromium',
819
838
  initScript,
820
839
  launchOptions,
821
- contextOptions: {
822
- userAgent: DEFAULT_FINGERPRINT_PROFILE.userAgent,
823
- locale: DEFAULT_FINGERPRINT_PROFILE.locale,
824
- timezoneId: DEFAULT_FINGERPRINT_PROFILE.timezoneId,
825
- viewport: {
826
- width: DEFAULT_FINGERPRINT_PROFILE.width,
827
- height: DEFAULT_FINGERPRINT_PROFILE.height
828
- },
829
- screen: {
830
- width: DEFAULT_FINGERPRINT_PROFILE.width,
831
- height: DEFAULT_FINGERPRINT_PROFILE.height
832
- },
833
- extraHTTPHeaders: {
834
- 'Accept-Language': DEFAULT_FINGERPRINT_PROFILE.acceptLanguage
835
- }
836
- }
840
+ contextOptions
837
841
  }
838
842
  };
839
843
  }
@@ -226,6 +226,7 @@
226
226
  <script src="/app/vendor/xterm-addon-fit.js"></script>
227
227
  <script src="/app/vendor/marked.min.js"></script>
228
228
  <script src="/app/frontend/markdown-renderer.js"></script>
229
+ <script src="/app/frontend/path-picker-utils.js"></script>
229
230
  <script src="/app/frontend/app.js"></script>
230
231
  </body>
231
232
  </html>
@@ -59,6 +59,7 @@
59
59
  sessionDetailError: '',
60
60
  sessionDetailRequestId: 0,
61
61
  createAgentPromptAuto: false,
62
+ createContainerPathBase: '',
62
63
  createDefaults: null,
63
64
  createRuns: {},
64
65
  sessionNodeMap: new Map(),
@@ -77,6 +78,7 @@
77
78
  tip: '',
78
79
  currentPath: '',
79
80
  basePath: '',
81
+ baseContainerPath: '',
80
82
  entries: [],
81
83
  error: ''
82
84
  },
@@ -218,6 +220,9 @@
218
220
  && typeof window.ManyoyoMarkdown.render === 'function'
219
221
  ? window.ManyoyoMarkdown
220
222
  : null;
223
+ const pathPickerUtils = window.ManyoyoPathPickerUtils && typeof window.ManyoyoPathPickerUtils === 'object'
224
+ ? window.ManyoyoPathPickerUtils
225
+ : {};
221
226
 
222
227
  function normalizeBooleanMap(source) {
223
228
  const result = {};
@@ -647,10 +652,16 @@
647
652
  }
648
653
 
649
654
  function normalizeSlashPath(value) {
655
+ if (typeof pathPickerUtils.normalizeSlashPath === 'function') {
656
+ return pathPickerUtils.normalizeSlashPath(value);
657
+ }
650
658
  return String(value || '').replace(/\\/g, '/');
651
659
  }
652
660
 
653
661
  function isChildPath(basePath, targetPath) {
662
+ if (typeof pathPickerUtils.isChildPath === 'function') {
663
+ return pathPickerUtils.isChildPath(basePath, targetPath);
664
+ }
654
665
  const normalizedBase = normalizeSlashPath(basePath).replace(/\/+$/, '');
655
666
  const normalizedTarget = normalizeSlashPath(targetPath).replace(/\/+$/, '');
656
667
  if (!normalizedBase) {
@@ -660,6 +671,9 @@
660
671
  }
661
672
 
662
673
  function buildContainerPathFromHostSelection(baseHostPath, baseContainerPath, selectedHostPath) {
674
+ if (typeof pathPickerUtils.buildContainerPathFromHostSelection === 'function') {
675
+ return pathPickerUtils.buildContainerPathFromHostSelection(baseHostPath, baseContainerPath, selectedHostPath);
676
+ }
663
677
  const normalizedBaseHost = normalizeSlashPath(baseHostPath).replace(/\/+$/, '');
664
678
  const normalizedContainer = normalizeSlashPath(baseContainerPath).replace(/\/+$/, '') || '/workspace';
665
679
  const normalizedSelected = normalizeSlashPath(selectedHostPath).replace(/\/+$/, '');
@@ -860,6 +874,7 @@
860
874
  createContainerName.value = value.containerName || '';
861
875
  createHostPath.value = value.hostPath || '';
862
876
  createContainerPath.value = value.containerPath || '';
877
+ state.createContainerPathBase = String(value.containerPath || '').trim();
863
878
  createImageName.value = value.imageName || '';
864
879
  createImageVersion.value = value.imageVersion || '';
865
880
  createContainerMode.value = value.containerMode || '';
@@ -2074,6 +2089,7 @@
2074
2089
  state.directoryPicker.tip = '';
2075
2090
  state.directoryPicker.currentPath = '';
2076
2091
  state.directoryPicker.basePath = '';
2092
+ state.directoryPicker.baseContainerPath = '';
2077
2093
  state.directoryPicker.parentPath = '';
2078
2094
  state.directoryPicker.entries = [];
2079
2095
  state.directoryPicker.error = '';
@@ -2089,11 +2105,12 @@
2089
2105
  createHostPath.value = picker.currentPath;
2090
2106
  if (!(createContainerPath.value || '').trim()) {
2091
2107
  createContainerPath.value = '/workspace';
2108
+ state.createContainerPathBase = '/workspace';
2092
2109
  }
2093
2110
  } else if (picker.mode === 'container') {
2094
2111
  const mapped = buildContainerPathFromHostSelection(
2095
2112
  picker.basePath,
2096
- (createContainerPath.value || '').trim() || '/workspace',
2113
+ picker.baseContainerPath || '/workspace',
2097
2114
  picker.currentPath
2098
2115
  );
2099
2116
  createContainerPath.value = mapped;
@@ -2120,12 +2137,16 @@
2120
2137
  picker.title = '选择 containerPath 对应目录';
2121
2138
  picker.tip = '从 hostPath 下选择子目录,结果会映射到容器路径。';
2122
2139
  picker.basePath = baseHostPath;
2140
+ picker.baseContainerPath = typeof pathPickerUtils.resolveContainerPickerBase === 'function'
2141
+ ? pathPickerUtils.resolveContainerPickerBase(state.createContainerPathBase, createContainerPath.value)
2142
+ : (String(state.createContainerPathBase || '').trim() || String(createContainerPath.value || '').trim() || '/workspace');
2123
2143
  picker.currentPath = baseHostPath;
2124
2144
  } else {
2125
2145
  picker.mode = 'host';
2126
2146
  picker.title = '选择 hostPath';
2127
2147
  picker.tip = '浏览宿主机目录,选中后会回填 create 表单。';
2128
2148
  picker.basePath = '';
2149
+ picker.baseContainerPath = '';
2129
2150
  picker.currentPath = (createHostPath.value || '').trim() || '/';
2130
2151
  }
2131
2152
  renderDirectoryPicker();
@@ -3313,6 +3334,12 @@
3313
3334
  });
3314
3335
  }
3315
3336
 
3337
+ if (createContainerPath) {
3338
+ createContainerPath.addEventListener('input', function () {
3339
+ state.createContainerPathBase = String(createContainerPath.value || '').trim();
3340
+ });
3341
+ }
3342
+
3316
3343
  if (createForm) {
3317
3344
  createForm.addEventListener('submit', async function (event) {
3318
3345
  event.preventDefault();
@@ -0,0 +1,57 @@
1
+ (function (root, factory) {
2
+ const api = factory();
3
+ if (typeof module === 'object' && module.exports) {
4
+ module.exports = api;
5
+ }
6
+ if (root && typeof root === 'object') {
7
+ root.ManyoyoPathPickerUtils = api;
8
+ }
9
+ }(typeof globalThis !== 'undefined' ? globalThis : this, function () {
10
+ function normalizeSlashPath(value) {
11
+ return String(value || '').replace(/\\/g, '/');
12
+ }
13
+
14
+ function isChildPath(basePath, targetPath) {
15
+ const normalizedBase = normalizeSlashPath(basePath).replace(/\/+$/, '');
16
+ const normalizedTarget = normalizeSlashPath(targetPath).replace(/\/+$/, '');
17
+ if (!normalizedBase) {
18
+ return false;
19
+ }
20
+ return normalizedTarget === normalizedBase || normalizedTarget.startsWith(normalizedBase + '/');
21
+ }
22
+
23
+ function resolveContainerPickerBase(baseContainerPath, currentContainerPath) {
24
+ return String(baseContainerPath || '').trim()
25
+ || String(currentContainerPath || '').trim()
26
+ || '/workspace';
27
+ }
28
+
29
+ function buildContainerPathFromHostSelection(baseHostPath, baseContainerPath, selectedHostPath) {
30
+ const normalizedBaseHost = normalizeSlashPath(baseHostPath).replace(/\/+$/, '');
31
+ const normalizedContainer = normalizeSlashPath(baseContainerPath).replace(/\/+$/, '') || '/workspace';
32
+ const normalizedSelected = normalizeSlashPath(selectedHostPath).replace(/\/+$/, '');
33
+ if (!normalizedBaseHost || !isChildPath(normalizedBaseHost, normalizedSelected)) {
34
+ return normalizedContainer;
35
+ }
36
+ const relative = normalizedSelected === normalizedBaseHost
37
+ ? ''
38
+ : normalizedSelected.slice(normalizedBaseHost.length + 1);
39
+ return relative ? `${normalizedContainer}/${relative}`.replace(/\/+/g, '/') : normalizedContainer;
40
+ }
41
+
42
+ function applyContainerPathSelection(baseHostPath, baseContainerPath, currentContainerPath, selectedHostPath) {
43
+ return buildContainerPathFromHostSelection(
44
+ baseHostPath,
45
+ resolveContainerPickerBase(baseContainerPath, currentContainerPath),
46
+ selectedHostPath
47
+ );
48
+ }
49
+
50
+ return {
51
+ normalizeSlashPath,
52
+ isChildPath,
53
+ resolveContainerPickerBase,
54
+ buildContainerPathFromHostSelection,
55
+ applyContainerPathSelection
56
+ };
57
+ }));
package/lib/web/server.js CHANGED
@@ -3542,7 +3542,7 @@ async function startWebServer(options) {
3542
3542
  const appFrontendMatch = pathname.match(/^\/app\/frontend\/([A-Za-z0-9._-]+)$/);
3543
3543
  if (req.method === 'GET' && appFrontendMatch) {
3544
3544
  const assetName = appFrontendMatch[1];
3545
- if (!(assetName === 'app.css' || assetName === 'app.js' || assetName === 'markdown.css' || assetName === 'markdown-renderer.js')) {
3545
+ if (!(assetName === 'app.css' || assetName === 'app.js' || assetName === 'markdown.css' || assetName === 'markdown-renderer.js' || assetName === 'path-picker-utils.js')) {
3546
3546
  sendHtml(res, 404, '<h1>404 Not Found</h1>');
3547
3547
  return;
3548
3548
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xcanwin/manyoyo",
3
- "version": "5.7.9",
3
+ "version": "5.7.12",
4
4
  "imageVersion": "1.9.0-common",
5
5
  "playwrightCliVersion": "0.1.1",
6
6
  "description": "AI Agent CLI Security Sandbox for Docker and Podman",