@xcanwin/manyoyo 5.9.2 → 5.9.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/README.md CHANGED
@@ -129,6 +129,7 @@ manyoyo serve 127.0.0.1:3000 -U admin -P 123456
129
129
  manyoyo serve 127.0.0.1:3000 -U admin -P 123456 -d
130
130
  manyoyo serve 127.0.0.1:3000 -d # 未设置密码时会打印本次随机密码
131
131
  manyoyo serve 127.0.0.1:3000 --stop # 停止指定后台服务
132
+ manyoyo serve 127.0.0.1:3000 -U admin -P 123456 -d --restart # 重启指定后台服务
132
133
 
133
134
  # 查看配置与命令拼装
134
135
  manyoyo config show
package/bin/manyoyo.js CHANGED
@@ -1128,6 +1128,7 @@ async function setupCommander() {
1128
1128
  ${MANYOYO_NAME} serve 127.0.0.1:3000 启动本机网页服务
1129
1129
  ${MANYOYO_NAME} serve 127.0.0.1:3000 -d 后台启动;未设密码时会打印本次随机密码
1130
1130
  ${MANYOYO_NAME} serve 0.0.0.0:3000 -U admin -P 123 -d 后台启动并监听全部网卡
1131
+ ${MANYOYO_NAME} serve 0.0.0.0:3000 -U admin -P 123 -d --restart 重启指定后台网页服务
1131
1132
  ${MANYOYO_NAME} playwright up mcp-host-headless 启动 playwright MCP 宿主场景(默认/推荐)
1132
1133
  ${MANYOYO_NAME} playwright up cli-host-headless 启动 playwright CLI 宿主场景(供容器内 playwright-cli 附着)
1133
1134
  ${MANYOYO_NAME} run -n test -q tip -q cmd 多次使用静默选项
@@ -1176,6 +1177,7 @@ Notes:
1176
1177
  applyRunStyleOptions(serveCommand, { includeRmOnExit: false, includeWebAuthOptions: true });
1177
1178
  serveCommand.option('-d, --detach', '后台启动网页服务并立即返回');
1178
1179
  serveCommand.option('--stop', '停止后台网页服务;必须显式传入 listen');
1180
+ serveCommand.option('--restart', '重启后台网页服务;必须显式传入 listen');
1179
1181
  serveCommand.action((listen, options) => {
1180
1182
  selectAction('serve', {
1181
1183
  ...options,
@@ -1278,6 +1280,11 @@ Notes:
1278
1280
  const isShowCommandMode = selectedAction === 'config-command';
1279
1281
  const isServerMode = options.server !== undefined;
1280
1282
  const isServerStopMode = Boolean(selectedAction === 'serve' && options.stop);
1283
+ const isServerRestartMode = Boolean(selectedAction === 'serve' && options.restart);
1284
+
1285
+ if (isServerStopMode && isServerRestartMode) {
1286
+ throw new Error('serve --stop 与 --restart 不能同时使用');
1287
+ }
1281
1288
 
1282
1289
  const noDockerActions = new Set(['init', 'update', 'install', 'config-show', 'plugin']);
1283
1290
  if (isServerStopMode) {
@@ -1472,6 +1479,7 @@ Notes:
1472
1479
  isShowCommandMode,
1473
1480
  isServerMode,
1474
1481
  isServerStop: isServerStopMode,
1482
+ isServerRestart: isServerRestartMode,
1475
1483
  isServerDetach: Boolean(selectedAction === 'serve' && options.detach),
1476
1484
  isServerListenSpecified: Boolean(isServerMode && options.server !== true),
1477
1485
  isPluginMode: false
@@ -1502,6 +1510,7 @@ function createRuntimeContext(modeState = {}) {
1502
1510
  rmOnExit: RM_ON_EXIT,
1503
1511
  serverMode: Boolean(modeState.isServerMode),
1504
1512
  serverStop: Boolean(modeState.isServerStop),
1513
+ serverRestart: Boolean(modeState.isServerRestart),
1505
1514
  serverDetach: Boolean(modeState.isServerDetach),
1506
1515
  serverListenSpecified: Boolean(modeState.isServerListenSpecified),
1507
1516
  serverHost: SERVER_HOST,
@@ -1553,7 +1562,7 @@ function buildDetachedServeArgv(argv) {
1553
1562
  const result = [];
1554
1563
  for (let i = 0; i < argv.length; i++) {
1555
1564
  const arg = String(argv[i] || '');
1556
- if (arg === '-d' || arg === '--detach') {
1565
+ if (arg === '-d' || arg === '--detach' || arg === '--restart') {
1557
1566
  continue;
1558
1567
  }
1559
1568
  result.push(arg);
@@ -1663,15 +1672,16 @@ function writeServePidFile(runtime, serverHandle) {
1663
1672
  return pidFile.path;
1664
1673
  }
1665
1674
 
1666
- async function stopServeProcess(runtime) {
1675
+ async function stopServeProcess(runtime, options = {}) {
1676
+ const commandName = options.commandName || '--stop';
1667
1677
  if (!runtime || !runtime.serverListenSpecified) {
1668
- throw new Error('serve --stop 必须显式传入 listen,例如 manyoyo serve 127.0.0.1:3000 --stop');
1678
+ throw new Error(`serve ${commandName} 必须显式传入 listen,例如 manyoyo serve 127.0.0.1:3000 ${commandName}`);
1669
1679
  }
1670
1680
  const target = getServePidTarget(runtime.serverHost, runtime.serverPort);
1671
1681
  if (!target) {
1672
1682
  const label = buildServeListenLabel(runtime.serverHost, runtime.serverPort);
1673
1683
  console.log(`${YELLOW}⚠️ 未发现运行中的 serve 实例: ${label}${NC}`);
1674
- return;
1684
+ return false;
1675
1685
  }
1676
1686
  try {
1677
1687
  process.kill(target.pid, 'SIGTERM');
@@ -1692,6 +1702,7 @@ async function stopServeProcess(runtime) {
1692
1702
  }
1693
1703
  removeServePidFile(target.path);
1694
1704
  console.log(`${GREEN}✅ 已停止 serve: ${target.listen} (pid: ${target.pid})${NC}`);
1705
+ return true;
1695
1706
  }
1696
1707
 
1697
1708
  function relaunchServeDetached(runtime) {
@@ -1711,7 +1722,7 @@ function relaunchServeDetached(runtime) {
1711
1722
  });
1712
1723
  child.unref();
1713
1724
 
1714
- console.log(`${GREEN}✅ serve 已转入后台运行${NC}`);
1725
+ console.log(`${GREEN}✅ MANYOYO Web 服务已在后台启动: http://${buildServeListenLabel(runtime.serverHost, runtime.serverPort)}${NC}`);
1715
1726
  console.log(`PID: ${child.pid}`);
1716
1727
  console.log(`日志: ${serveLog.path}`);
1717
1728
  console.log(`登录用户名: ${runtime.serverAuthUser}`);
@@ -2064,6 +2075,9 @@ async function main() {
2064
2075
  await stopServeProcess(runtime);
2065
2076
  return;
2066
2077
  }
2078
+ if (runtime.serverRestart) {
2079
+ await stopServeProcess(runtime, { commandName: '--restart' });
2080
+ }
2067
2081
  if (runtime.serverDetach) {
2068
2082
  relaunchServeDetached(runtime);
2069
2083
  return;
@@ -371,13 +371,17 @@ textarea:focus-visible {
371
371
  min-height: 340px;
372
372
  border: 1px solid var(--line);
373
373
  border-radius: 10px;
374
+ overflow: hidden;
374
375
  background: #fffdfa;
375
- color: var(--text);
376
- font-family: var(--font-mono);
376
+ }
377
+
378
+ .config-editor .cm-editor {
379
+ height: 340px;
377
380
  font-size: 13px;
378
- line-height: 1.5;
379
- padding: 12px;
380
- resize: vertical;
381
+ }
382
+
383
+ .config-editor .cm-scroller {
384
+ overflow: auto;
381
385
  }
382
386
 
383
387
  .form-grid {
@@ -929,33 +933,23 @@ button.tree-toggle:active {
929
933
  }
930
934
 
931
935
  .dir-picker-toolbar {
932
- display: flex;
933
- justify-content: space-between;
934
- gap: 8px;
935
936
  margin-bottom: 10px;
937
+ padding-left: 0;
938
+ padding-right: 0;
939
+ border-bottom: 0;
940
+ background: transparent;
936
941
  }
937
942
 
938
- .dir-picker-current {
939
- margin-bottom: 10px;
940
- padding: 10px 12px;
941
- border: 1px solid rgba(181, 146, 99, 0.38);
942
- border-radius: 10px;
943
- background: rgba(255, 251, 244, 0.92);
944
- color: var(--text);
945
- font-family: var(--font-mono);
946
- font-size: 12px;
947
- word-break: break-all;
943
+ .dir-picker-toolbar-meta {
944
+ flex-wrap: wrap;
948
945
  }
949
946
 
950
947
  .dir-picker-list {
951
- display: flex;
952
- flex-direction: column;
953
- gap: 8px;
954
- }
955
-
956
- .dir-picker-item {
957
- width: 100%;
958
- text-align: left;
948
+ max-height: min(52vh, 420px);
949
+ border: 1px solid var(--line);
950
+ border-radius: 14px;
951
+ overflow: auto;
952
+ background: rgba(255, 255, 255, 0.86);
959
953
  }
960
954
 
961
955
  .empty {
@@ -1160,12 +1154,21 @@ body.mobile-actions-open .header-actions {
1160
1154
  display: flex;
1161
1155
  align-items: center;
1162
1156
  gap: 8px;
1157
+ flex-wrap: wrap;
1163
1158
  padding: 12px 14px;
1164
1159
  border-bottom: 1px solid var(--line);
1165
1160
  background: rgba(255, 251, 244, 0.96);
1166
1161
  }
1167
1162
 
1168
- .files-toolbar-path {
1163
+ .files-toolbar-path-group {
1164
+ flex: 1;
1165
+ min-width: 0;
1166
+ display: flex;
1167
+ align-items: center;
1168
+ gap: 8px;
1169
+ }
1170
+
1171
+ .files-toolbar-path-input {
1169
1172
  flex: 1;
1170
1173
  min-width: 0;
1171
1174
  padding: 8px 10px;
@@ -1176,7 +1179,12 @@ body.mobile-actions-open .header-actions {
1176
1179
  font-family: var(--font-mono);
1177
1180
  font-size: 12px;
1178
1181
  line-height: 1.5;
1179
- word-break: break-all;
1182
+ }
1183
+
1184
+ .files-toolbar-path-input:focus {
1185
+ outline: none;
1186
+ border-color: rgba(120, 78, 27, 0.45);
1187
+ box-shadow: 0 0 0 3px rgba(181, 146, 99, 0.12);
1180
1188
  }
1181
1189
 
1182
1190
  .files-toolbar-status {
@@ -1184,63 +1192,91 @@ body.mobile-actions-open .header-actions {
1184
1192
  font-size: 12px;
1185
1193
  }
1186
1194
 
1195
+ .files-toolbar-meta {
1196
+ display: flex;
1197
+ align-items: center;
1198
+ gap: 8px;
1199
+ margin-left: auto;
1200
+ }
1201
+
1187
1202
  .files-layout {
1188
1203
  min-height: 0;
1189
1204
  display: grid;
1190
- grid-template-columns: minmax(240px, 320px) minmax(0, 1fr);
1205
+ grid-template-columns: minmax(220px, 300px) minmax(0, 1fr);
1191
1206
  }
1192
1207
 
1193
1208
  .files-sidebar {
1194
1209
  min-height: 0;
1195
1210
  border-right: 1px solid var(--line);
1196
- background: rgba(255, 251, 244, 0.84);
1211
+ background: rgba(255, 255, 255, 0.86);
1197
1212
  overflow: auto;
1198
1213
  }
1199
1214
 
1200
1215
  .files-list {
1201
1216
  display: flex;
1202
1217
  flex-direction: column;
1203
- gap: 6px;
1204
- padding: 12px;
1218
+ gap: 0;
1219
+ padding: 4px 0;
1205
1220
  }
1206
1221
 
1207
1222
  .files-entry {
1208
1223
  width: 100%;
1209
- display: flex;
1210
- align-items: center;
1211
- justify-content: space-between;
1224
+ display: grid;
1225
+ grid-template-columns: minmax(0, 1fr) auto;
1226
+ align-items: start;
1212
1227
  gap: 10px;
1213
- padding: 10px 12px;
1214
- border: 1px solid rgba(181, 146, 99, 0.28);
1215
- border-radius: 12px;
1216
- background: rgba(255, 255, 255, 0.92);
1228
+ padding: 7px 12px;
1229
+ border: 0;
1230
+ border-bottom: 1px solid rgba(181, 146, 99, 0.18);
1231
+ border-radius: 0;
1232
+ background: transparent;
1217
1233
  color: var(--text);
1218
1234
  text-align: left;
1219
1235
  cursor: pointer;
1220
1236
  }
1221
1237
 
1238
+ .files-entry:hover {
1239
+ background: rgba(255, 247, 233, 0.72);
1240
+ }
1241
+
1222
1242
  .files-entry.is-active {
1223
- border-color: rgba(120, 78, 27, 0.45);
1224
- background: rgba(255, 244, 224, 0.9);
1243
+ background: rgba(255, 244, 224, 0.95);
1244
+ box-shadow: inset 3px 0 0 rgba(120, 78, 27, 0.58);
1245
+ }
1246
+
1247
+ .files-entry-parent {
1248
+ font-style: italic;
1225
1249
  }
1226
1250
 
1227
1251
  .files-entry-name {
1252
+ flex: 1;
1228
1253
  min-width: 0;
1229
- display: flex;
1230
- flex-direction: column;
1231
- gap: 0;
1232
1254
  }
1233
1255
 
1234
1256
  .files-entry-title {
1235
1257
  font-size: 13px;
1236
1258
  font-weight: 600;
1237
- word-break: break-word;
1259
+ white-space: normal;
1260
+ word-break: break-all;
1261
+ overflow-wrap: anywhere;
1238
1262
  }
1239
1263
 
1240
1264
  .files-entry-meta {
1265
+ flex-shrink: 0;
1241
1266
  color: var(--muted);
1242
1267
  font-size: 11px;
1243
1268
  white-space: nowrap;
1269
+ text-align: right;
1270
+ }
1271
+
1272
+ .files-list > .files-empty {
1273
+ padding: 8px 12px;
1274
+ border: 0;
1275
+ border-bottom: 1px solid rgba(181, 146, 99, 0.18);
1276
+ border-radius: 0;
1277
+ background: transparent;
1278
+ color: var(--muted);
1279
+ line-height: 1.5;
1244
1280
  }
1245
1281
 
1246
1282
  .files-preview {
@@ -1251,34 +1287,54 @@ body.mobile-actions-open .header-actions {
1251
1287
 
1252
1288
  .files-preview-head {
1253
1289
  display: flex;
1254
- flex-direction: column;
1255
- gap: 6px;
1256
- padding: 12px 14px;
1290
+ align-items: flex-start;
1291
+ justify-content: space-between;
1292
+ gap: 12px;
1293
+ flex-wrap: wrap;
1294
+ padding: 10px 12px;
1257
1295
  border-bottom: 1px solid var(--line);
1258
1296
  background: rgba(255, 251, 244, 0.96);
1259
1297
  }
1260
1298
 
1299
+ .files-preview-head-main {
1300
+ flex: 1 1 280px;
1301
+ min-width: 0;
1302
+ display: flex;
1303
+ flex-direction: column;
1304
+ gap: 6px;
1305
+ }
1306
+
1307
+ .files-preview-actions {
1308
+ flex-shrink: 0;
1309
+ display: flex;
1310
+ align-items: center;
1311
+ gap: 8px;
1312
+ margin-left: auto;
1313
+ }
1314
+
1261
1315
  .files-preview-title {
1262
1316
  font-family: var(--font-display);
1263
- font-size: 15px;
1317
+ font-size: 14px;
1264
1318
  font-weight: 700;
1319
+ word-break: break-all;
1320
+ overflow-wrap: anywhere;
1265
1321
  }
1266
1322
 
1267
1323
  .files-preview-meta {
1268
1324
  color: var(--muted);
1269
- font-size: 12px;
1325
+ font-size: 11px;
1270
1326
  word-break: break-all;
1271
1327
  }
1272
1328
 
1273
1329
  .files-preview-body {
1274
1330
  min-height: 0;
1275
1331
  overflow: auto;
1276
- padding: 14px;
1332
+ padding: 8px;
1277
1333
  }
1278
1334
 
1279
1335
  .files-empty,
1280
1336
  .files-note {
1281
- padding: 18px;
1337
+ padding: 14px;
1282
1338
  border: 1px dashed rgba(181, 146, 99, 0.45);
1283
1339
  border-radius: 12px;
1284
1340
  background: rgba(255, 255, 255, 0.7);
@@ -1301,14 +1357,24 @@ body.mobile-actions-open .header-actions {
1301
1357
 
1302
1358
  .files-editor-host .cm-editor {
1303
1359
  height: 100%;
1304
- border: 1px solid rgba(181, 146, 99, 0.32);
1305
- border-radius: 12px;
1360
+ border: 1px solid rgba(181, 146, 99, 0.2);
1361
+ border-radius: 8px;
1306
1362
  overflow: hidden;
1307
- background: rgba(255, 255, 255, 0.94);
1363
+ background: rgba(255, 255, 255, 0.98);
1308
1364
  }
1309
1365
 
1310
1366
  .files-editor-host .cm-scroller {
1311
1367
  font-family: var(--font-mono);
1368
+ line-height: 1.45;
1369
+ }
1370
+
1371
+ .files-editor-host .cm-gutters {
1372
+ border-right: 1px solid rgba(181, 146, 99, 0.14);
1373
+ background: rgba(252, 248, 241, 0.92);
1374
+ }
1375
+
1376
+ .files-editor-host .cm-lineNumbers .cm-gutterElement {
1377
+ font-size: 11px;
1312
1378
  }
1313
1379
 
1314
1380
  .inspector-pane {
@@ -58,9 +58,10 @@
58
58
  >更多</button>
59
59
  <div class="header-actions" id="headerActions">
60
60
  <button type="button" id="refreshBtn" class="secondary">刷新</button>
61
- <button type="button" id="addAgentBtn" class="secondary">新建AGENT</button>
62
- <button type="button" id="removeBtn" class="danger-outline">删除容器</button>
63
- <button type="button" id="removeAllBtn" class="danger">删除对话</button>
61
+ <button type="button" id="openCreateMenuBtn" class="secondary">新建容器</button>
62
+ <button type="button" id="removeBtn" class="danger">删除容器</button>
63
+ <button type="button" id="addAgentBtn" class="secondary">新建 AGENT</button>
64
+ <button type="button" id="removeAllBtn" class="danger">删除 AGENT</button>
64
65
  </div>
65
66
  </div>
66
67
  </div>
@@ -137,7 +138,7 @@
137
138
  </header>
138
139
  <div class="modal-body">
139
140
  <div id="configPath" class="modal-tip"></div>
140
- <textarea id="configEditor" class="config-editor" spellcheck="false"></textarea>
141
+ <div id="configEditor" class="config-editor"></div>
141
142
  <div id="configStatus" class="modal-success" hidden></div>
142
143
  <div id="configError" class="modal-error" hidden></div>
143
144
  </div>
@@ -219,13 +220,19 @@
219
220
  </header>
220
221
  <div class="modal-body">
221
222
  <div id="directoryPickerTip" class="modal-tip"></div>
222
- <div class="dir-picker-toolbar">
223
- <button type="button" id="directoryPickerUpBtn" class="secondary">上一级</button>
224
- <button type="button" id="directoryPickerSelectBtn">使用当前目录</button>
223
+ <div class="files-toolbar dir-picker-toolbar">
224
+ <div class="files-toolbar-path-group">
225
+ <input type="text" id="directoryPickerPathInput" class="files-toolbar-path-input" value="/" spellcheck="false" />
226
+ <button type="button" id="directoryPickerVisitBtn" class="secondary">访问</button>
227
+ </div>
228
+ <div class="files-toolbar-meta dir-picker-toolbar-meta">
229
+ <div id="directoryPickerStatus" class="files-toolbar-status">未加载</div>
230
+ <button type="button" id="directoryPickerMkdirBtn" class="secondary">新建目录</button>
231
+ <button type="button" id="directoryPickerSelectBtn">使用当前目录</button>
232
+ </div>
225
233
  </div>
226
- <div id="directoryPickerCurrent" class="dir-picker-current"></div>
227
234
  <div id="directoryPickerError" class="modal-error" hidden></div>
228
- <div id="directoryPickerList" class="dir-picker-list"></div>
235
+ <div id="directoryPickerList" class="dir-picker-list files-list"></div>
229
236
  </div>
230
237
  </section>
231
238
  </div>