@xcanwin/manyoyo 3.1.0 → 3.4.0

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
@@ -1,4 +1,4 @@
1
- [English](docs/README_EN.md) | [ [中文](README.md) ]
1
+ [English](docs/README_EN.md) | << [中文](README.md) >>
2
2
 
3
3
  ---
4
4
 
@@ -49,15 +49,23 @@ npm install -g .
49
49
  # 拉取基础镜像
50
50
  podman pull ubuntu:24.04
51
51
 
52
- # 使用 manyoyo 构建镜像(推荐)
53
- manyoyo --ib all # 构建 all 版本(包含所有工具)
54
- manyoyo --ib common # 构建 common 版本(基础版本)
55
- manyoyo --ib go,codex,java,gemini # 构建 go 版本(包含 go,codex,java,gemini 工具)
52
+ # 使用 manyoyo 构建镜像(推荐,自动使用缓存加速)
53
+ manyoyo --ib all # 构建 all 版本(自动使用缓存,首次下载后 2 天内极速构建)
54
+ manyoyo --ib common # 构建 common 版本
55
+ manyoyo --ib go,codex,java,gemini # 构建自定义组合版本
56
+
57
+ # 工作原理:
58
+ # - 首次构建:自动下载 Node.js、JDT LSP、gopls 等到 docker/cache/
59
+ # - 2天内再次构建:直接使用本地缓存,速度提升约 5 倍
60
+ # - 缓存过期后:自动重新下载最新版本
56
61
 
57
62
  # 自定义镜像名称和版本
58
63
  manyoyo --ib all --in myimage --iv 2.0.0
59
64
  # 构建:myimage:2.0.0-all
60
65
 
66
+ # 清理镜像
67
+ manyoyo --ip # 清理悬空镜像和 <none> 镜像
68
+
61
69
  # 或手动构建(不推荐)
62
70
  iv=1.4.0 && podman build -t localhost/xcanwin/manyoyo:$iv-all -f docker/manyoyo.Dockerfile . --build-arg EXT=all --no-cache
63
71
  podman image prune -f
@@ -173,14 +181,18 @@ manyoyo -n docker-dev -m dind -x /bin/bash
173
181
  nohup dockerd &
174
182
 
175
183
  # 现在可以在容器内使用 docker 命令
176
- docker run hello-world
184
+ docker ps -a
177
185
  ```
178
186
 
179
187
  #### 挂载 Docker Socket 开发
180
188
 
181
189
  ```bash
182
- # 挂载 Docker Socket(危险 - 容器可以访问宿主机)
183
- manyoyo -n socket-dev -m mdsock -x docker ps
190
+ # 挂载 Docker Socket(危险的!!!容器可以访问和执行宿主机的一切)
191
+ # 创建挂载 /var/run/docker.sock 的容器
192
+ manyoyo -n socket-dev -m mdsock -x /bin/bash
193
+
194
+ # 现在可以在容器内使用 docker 命令
195
+ docker ps -a
184
196
  ```
185
197
 
186
198
  ### 命令行选项
@@ -203,7 +215,8 @@ manyoyo -n socket-dev -m mdsock -x docker ps
203
215
  | `-x CMD` | `--sf`, `--shell-full` | 完整命令(替代 --sp, -s 和 --) |
204
216
  | `-y CLI` | `--yolo` | 无需确认运行 AI 智能体 |
205
217
  | `-m MODE` | `--cm`, `--cont-mode` | 设置容器模式(common, dind, mdsock) |
206
- | `--ib EXT` | `--image-build` | 构建镜像,EXT 为镜像变体(all, go, common) |
218
+ | `--ib EXT` | `--image-build` | 构建镜像,EXT 为镜像变体,自动使用缓存加速 |
219
+ | `--ip` | `--image-prune` | 清理悬空镜像和 `<none>` 镜像 |
207
220
  | `--install NAME` | | 安装 manyoyo 命令 |
208
221
  | `-V` | `--version` | 显示版本 |
209
222
  | `-h` | `--help` | 显示帮助 |
package/bin/manyoyo.js CHANGED
@@ -87,6 +87,8 @@ function showHelp() {
87
87
  console.log(" 例如 common, dind, mdsock");
88
88
  console.log(" --ib|--image-build EXT 构建镜像,EXT 为镜像变体,逗号分割");
89
89
  console.log(" 例如 \"common\" (默认值), \"all\", \"go,codex,java,gemini\" ...");
90
+ console.log(" (自动使用缓存加速,缓存过期后自动重新下载)");
91
+ console.log(" --ip|--image-prune 清理悬空镜像和 <none> 镜像");
90
92
  console.log(" --install NAME 安装manyoyo命令");
91
93
  console.log(" 例如 docker-cli-plugin");
92
94
  console.log(" -V|--version 显示版本");
@@ -214,7 +216,7 @@ function setContMode(mode) {
214
216
  case 'mount-docker-socket':
215
217
  case 'mdsock':
216
218
  case 's':
217
- CONT_MODE = "--volume /var/run/docker.sock:/var/run/docker.sock";
219
+ CONT_MODE = "--privileged --volume /var/run/docker.sock:/var/run/docker.sock";
218
220
  console.log(`${RED}⚠️ 开启危险的容器嵌套容器模式, 危害: 容器可访问宿主机文件${NC}`);
219
221
  break;
220
222
  default:
@@ -300,6 +302,179 @@ function getContList() {
300
302
  }
301
303
  }
302
304
 
305
+ function pruneDanglingImages() {
306
+ console.log(`\n${YELLOW}清理悬空镜像...${NC}`);
307
+ execSync(`${DOCKER_CMD} image prune -f`, { stdio: 'inherit' });
308
+
309
+ // Remove remaining <none> images
310
+ try {
311
+ const imagesOutput = execSync(`${DOCKER_CMD} images -a --format "{{.ID}} {{.Repository}}"`, { encoding: 'utf-8' });
312
+ const noneImages = imagesOutput
313
+ .split('\n')
314
+ .filter(line => line.includes('<none>'))
315
+ .map(line => line.split(' ')[0])
316
+ .filter(id => id);
317
+
318
+ if (noneImages.length > 0) {
319
+ console.log(`${YELLOW}清理剩余的 <none> 镜像 (${noneImages.length} 个)...${NC}`);
320
+ execSync(`${DOCKER_CMD} rmi -f ${noneImages.join(' ')}`, { stdio: 'inherit' });
321
+ }
322
+ } catch (e) {
323
+ // Ignore errors if no <none> images found
324
+ }
325
+
326
+ console.log(`${GREEN}✅ 清理完成${NC}`);
327
+ }
328
+
329
+ async function prepareBuildCache(ext) {
330
+ const cacheDir = path.join(__dirname, '../docker/cache');
331
+ const timestampFile = path.join(cacheDir, '.timestamps.json');
332
+ const cacheTTLDays = 2;
333
+
334
+ console.log(`\n${CYAN}准备构建缓存...${NC}`);
335
+
336
+ // Create cache directory
337
+ if (!fs.existsSync(cacheDir)) {
338
+ fs.mkdirSync(cacheDir, { recursive: true });
339
+ }
340
+
341
+ // Load timestamps
342
+ let timestamps = {};
343
+ if (fs.existsSync(timestampFile)) {
344
+ try {
345
+ timestamps = JSON.parse(fs.readFileSync(timestampFile, 'utf-8'));
346
+ } catch (e) {
347
+ timestamps = {};
348
+ }
349
+ }
350
+
351
+ const now = new Date();
352
+ const isExpired = (key) => {
353
+ if (!timestamps[key]) return true;
354
+ const cachedTime = new Date(timestamps[key]);
355
+ const diffDays = (now - cachedTime) / (1000 * 60 * 60 * 24);
356
+ return diffDays > cacheTTLDays;
357
+ };
358
+
359
+ // Determine architecture
360
+ const arch = process.arch === 'x64' ? 'amd64' : process.arch === 'arm64' ? 'arm64' : process.arch;
361
+ const archNode = arch === 'amd64' ? 'x64' : 'arm64';
362
+
363
+ // Prepare Node.js cache
364
+ const nodeCacheDir = path.join(cacheDir, 'node');
365
+ const nodeVersion = 24;
366
+ const nodeKey = 'node/'; // 使用目录级别的相对路径
367
+
368
+ if (!fs.existsSync(nodeCacheDir)) {
369
+ fs.mkdirSync(nodeCacheDir, { recursive: true });
370
+ }
371
+
372
+ const hasNodeCache = fs.existsSync(nodeCacheDir) && fs.readdirSync(nodeCacheDir).some(f => f.startsWith('node-') && f.includes(`linux-${archNode}`));
373
+ if (!hasNodeCache || isExpired(nodeKey)) {
374
+ console.log(`${YELLOW}下载 Node.js ${nodeVersion} (${archNode})...${NC}`);
375
+ const mirror = 'https://mirrors.tencent.com/nodejs-release';
376
+ try {
377
+ const shasum = execSync(`curl -sL ${mirror}/latest-v${nodeVersion}.x/SHASUMS256.txt | grep linux-${archNode}.tar.gz | awk '{print $2}'`, { encoding: 'utf-8' }).trim();
378
+ const nodeUrl = `${mirror}/latest-v${nodeVersion}.x/${shasum}`;
379
+ const nodeTargetPath = path.join(nodeCacheDir, shasum);
380
+ execSync(`curl -fsSL "${nodeUrl}" -o "${nodeTargetPath}"`, { stdio: 'inherit' });
381
+ timestamps[nodeKey] = now.toISOString();
382
+ fs.writeFileSync(timestampFile, JSON.stringify(timestamps, null, 2));
383
+ console.log(`${GREEN}✓ Node.js 下载完成${NC}`);
384
+ } catch (e) {
385
+ console.error(`${RED}错误: Node.js 下载失败${NC}`);
386
+ throw e;
387
+ }
388
+ } else {
389
+ console.log(`${GREEN}✓ Node.js 缓存已存在${NC}`);
390
+ }
391
+
392
+ // Prepare JDT LSP cache (for java variant)
393
+ if (ext === 'all' || ext.includes('java')) {
394
+ const jdtlsCacheDir = path.join(cacheDir, 'jdtls');
395
+ const jdtlsKey = 'jdtls/jdt-language-server-latest.tar.gz'; // 使用相对路径
396
+ const jdtlsPath = path.join(cacheDir, jdtlsKey);
397
+
398
+ if (!fs.existsSync(jdtlsCacheDir)) {
399
+ fs.mkdirSync(jdtlsCacheDir, { recursive: true });
400
+ }
401
+
402
+ if (!fs.existsSync(jdtlsPath) || isExpired(jdtlsKey)) {
403
+ console.log(`${YELLOW}下载 JDT Language Server...${NC}`);
404
+ const jdtUrl = 'https://download.eclipse.org/jdtls/snapshots/jdt-language-server-latest.tar.gz';
405
+ try {
406
+ execSync(`curl -fsSL "${jdtUrl}" -o "${jdtlsPath}"`, { stdio: 'inherit' });
407
+ timestamps[jdtlsKey] = now.toISOString();
408
+ fs.writeFileSync(timestampFile, JSON.stringify(timestamps, null, 2));
409
+ console.log(`${GREEN}✓ JDT LSP 下载完成${NC}`);
410
+ } catch (e) {
411
+ console.error(`${RED}错误: JDT LSP 下载失败${NC}`);
412
+ throw e;
413
+ }
414
+ } else {
415
+ console.log(`${GREEN}✓ JDT LSP 缓存已存在${NC}`);
416
+ }
417
+ }
418
+
419
+ // Prepare gopls cache (for go variant)
420
+ if (ext === 'all' || ext.includes('go')) {
421
+ const goplsCacheDir = path.join(cacheDir, 'gopls');
422
+ const goplsKey = `gopls/gopls-linux-${arch}`; // 使用相对路径
423
+ const goplsPath = path.join(cacheDir, goplsKey);
424
+
425
+ if (!fs.existsSync(goplsCacheDir)) {
426
+ fs.mkdirSync(goplsCacheDir, { recursive: true });
427
+ }
428
+
429
+ if (!fs.existsSync(goplsPath) || isExpired(goplsKey)) {
430
+ console.log(`${YELLOW}下载 gopls (${arch})...${NC}`);
431
+ try {
432
+ // Download using go install in temporary environment
433
+ const tmpGoPath = path.join(cacheDir, '.tmp-go');
434
+
435
+ // Clean up existing temp directory (with go clean for mod cache)
436
+ if (fs.existsSync(tmpGoPath)) {
437
+ try {
438
+ execSync(`GOPATH="${tmpGoPath}" go clean -modcache 2>/dev/null || true`, { stdio: 'inherit' });
439
+ execSync(`chmod -R u+w "${tmpGoPath}" 2>/dev/null || true`, { stdio: 'inherit' });
440
+ execSync(`rm -rf "${tmpGoPath}"`, { stdio: 'inherit' });
441
+ } catch (e) {
442
+ // Ignore cleanup errors
443
+ }
444
+ }
445
+ fs.mkdirSync(tmpGoPath, { recursive: true });
446
+
447
+ execSync(`GOPATH="${tmpGoPath}" GOOS=linux GOARCH=${arch} go install golang.org/x/tools/gopls@latest`, { stdio: 'inherit' });
448
+ execSync(`cp "${tmpGoPath}/bin/linux_${arch}/gopls" "${goplsPath}" || cp "${tmpGoPath}/bin/gopls" "${goplsPath}"`, { stdio: 'inherit' });
449
+ execSync(`chmod +x "${goplsPath}"`, { stdio: 'inherit' });
450
+
451
+ // Save timestamp immediately after successful download
452
+ timestamps[goplsKey] = now.toISOString();
453
+ fs.writeFileSync(timestampFile, JSON.stringify(timestamps, null, 2));
454
+ console.log(`${GREEN}✓ gopls 下载完成${NC}`);
455
+
456
+ // Clean up temp directory (with go clean for mod cache)
457
+ try {
458
+ execSync(`GOPATH="${tmpGoPath}" go clean -modcache 2>/dev/null || true`, { stdio: 'inherit' });
459
+ execSync(`chmod -R u+w "${tmpGoPath}" 2>/dev/null || true`, { stdio: 'inherit' });
460
+ execSync(`rm -rf "${tmpGoPath}"`, { stdio: 'inherit' });
461
+ } catch (e) {
462
+ console.log(`${YELLOW}提示: 临时目录清理失败,可手动删除 ${tmpGoPath}${NC}`);
463
+ }
464
+ } catch (e) {
465
+ console.error(`${RED}错误: gopls 下载失败${NC}`);
466
+ throw e;
467
+ }
468
+ } else {
469
+ console.log(`${GREEN}✓ gopls 缓存已存在${NC}`);
470
+ }
471
+ }
472
+
473
+ // Save timestamps
474
+ fs.writeFileSync(timestampFile, JSON.stringify(timestamps, null, 2));
475
+ console.log(`${GREEN}✅ 构建缓存准备完成${NC}\n`);
476
+ }
477
+
303
478
  async function buildImage(ext, imageName, imageVersion) {
304
479
  // Use package.json imageVersion if not specified
305
480
  const version = imageVersion || IMAGE_VERSION_BASE;
@@ -308,6 +483,9 @@ async function buildImage(ext, imageName, imageVersion) {
308
483
  console.log(`${CYAN}🔨 正在构建镜像: ${YELLOW}${fullImageTag}${NC}`);
309
484
  console.log(`${BLUE}构建参数: EXT=${ext}${NC}\n`);
310
485
 
486
+ // Prepare cache (自动检测并下载缺失的文件)
487
+ await prepareBuildCache(ext);
488
+
311
489
  // Find Dockerfile path
312
490
  const dockerfilePath = path.join(__dirname, '../docker/manyoyo.Dockerfile');
313
491
  if (!fs.existsSync(dockerfilePath)) {
@@ -331,9 +509,7 @@ async function buildImage(ext, imageName, imageVersion) {
331
509
  console.log(` manyoyo -n test --in ${imageName} --iv ${version}-${ext} -y c`);
332
510
 
333
511
  // Prune dangling images
334
- console.log(`\n${YELLOW}清理悬空镜像...${NC}`);
335
- execSync(`${DOCKER_CMD} image prune -f`, { stdio: 'inherit' });
336
- console.log(`${GREEN}✅ 清理完成${NC}`);
512
+ pruneDanglingImages();
337
513
  } catch (e) {
338
514
  console.error(`${RED}错误: 镜像构建失败${NC}`);
339
515
  process.exit(1);
@@ -491,6 +667,11 @@ function parseArguments(argv) {
491
667
  i += 2;
492
668
  break;
493
669
 
670
+ case '--ip':
671
+ case '--image-prune':
672
+ pruneDanglingImages();
673
+ process.exit(0);
674
+
494
675
  case '--install':
495
676
  installManyoyo(args[i + 1]);
496
677
  process.exit(0);
@@ -1,3 +1,60 @@
1
+ # ==============================================================================
2
+ # Stage 1: 缓存准备阶段 - 智能检测缓存或下载
3
+ # ==============================================================================
4
+ FROM ubuntu:24.04 AS cache-stage
5
+
6
+ ARG TARGETARCH
7
+
8
+ # 复制缓存目录(可能为空)
9
+ COPY ./docker/cache/ /cache/
10
+
11
+ RUN <<EOX
12
+ # 确定架构
13
+ case "$TARGETARCH" in
14
+ amd64) ARCH_NODE="x64"; ARCH_GO="amd64" ;;
15
+ arm64) ARCH_NODE="arm64"; ARCH_GO="arm64" ;;
16
+ *) ARCH_NODE="$TARGETARCH"; ARCH_GO="$TARGETARCH" ;;
17
+ esac
18
+
19
+ # Node.js: 检测缓存,不存在则下载
20
+ mkdir -p /opt/node
21
+ if ls /cache/node/node-*-linux-${ARCH_NODE}.tar.gz 1> /dev/null 2>&1; then
22
+ echo "使用 Node.js 缓存"
23
+ NODE_TAR=$(ls /cache/node/node-*-linux-${ARCH_NODE}.tar.gz | head -1)
24
+ tar -xzf ${NODE_TAR} -C /opt/node --strip-components=1 --exclude='*.md' --exclude='LICENSE'
25
+ else
26
+ echo "下载 Node.js"
27
+ NVM_NODEJS_ORG_MIRROR=https://mirrors.tencent.com/nodejs-release/
28
+ NODE_TAR=$(curl -sL ${NVM_NODEJS_ORG_MIRROR}/latest-v24.x/SHASUMS256.txt | grep linux-${ARCH_NODE}.tar.gz | awk '{print $2}')
29
+ curl -fsSL ${NVM_NODEJS_ORG_MIRROR}/latest-v24.x/${NODE_TAR} | tar -xz -C /opt/node --strip-components=1 --exclude='*.md' --exclude='LICENSE'
30
+ fi
31
+
32
+ # JDT LSP: 检测缓存,不存在则下载
33
+ mkdir -p /opt/jdtls
34
+ if [ -f /cache/jdtls/jdt-language-server-latest.tar.gz ]; then
35
+ echo "使用 JDT LSP 缓存"
36
+ tar -xzf /cache/jdtls/jdt-language-server-latest.tar.gz -C /opt/jdtls
37
+ else
38
+ echo "下载 JDT LSP"
39
+ curl -fsSL https://download.eclipse.org/jdtls/snapshots/jdt-language-server-latest.tar.gz | tar -xz -C /opt/jdtls
40
+ fi
41
+
42
+ # gopls: 检测缓存,不存在则下载
43
+ mkdir -p /opt/gopls
44
+ if [ -f /cache/gopls/gopls-linux-${ARCH_GO} ]; then
45
+ echo "使用 gopls 缓存"
46
+ cp /cache/gopls/gopls-linux-${ARCH_GO} /opt/gopls/gopls
47
+ chmod +x /opt/gopls/gopls
48
+ else
49
+ echo "下载 gopls (需要 go 环境)"
50
+ # gopls 需要编译,这里跳过,在最终阶段处理
51
+ touch /opt/gopls/.no-cache
52
+ fi
53
+ EOX
54
+
55
+ # ==============================================================================
56
+ # Stage 2: 最终镜像
57
+ # ==============================================================================
1
58
  FROM ubuntu:24.04
2
59
 
3
60
  ARG TARGETARCH
@@ -45,16 +102,11 @@ RUN <<EOX
45
102
  rm -rf /tmp/* /var/tmp/* /var/log/apt /var/log/*.log /var/lib/apt/lists/* ~/.cache ~/.npm ~/go/pkg/mod/cache
46
103
  EOX
47
104
 
105
+ # 从 cache-stage 复制 Node.js(缓存或下载)
106
+ COPY --from=cache-stage /opt/node /usr/local
107
+
48
108
  RUN <<EOX
49
- # 安装 node.js
50
- case "$TARGETARCH" in
51
- amd64) ARCH_NODE="x64" ;;
52
- arm64) ARCH_NODE="arm64" ;;
53
- *) ARCH_NODE="$TARGETARCH" ;;
54
- esac
55
- NVM_NODEJS_ORG_MIRROR=https://mirrors.tencent.com/nodejs-release/
56
- NODE_TAR=$(curl -sL ${NVM_NODEJS_ORG_MIRROR}/latest-v${NODE_VERSION}.x/SHASUMS256.txt | grep linux-${ARCH_NODE}.tar.gz | awk '{print $2}')
57
- curl -fsSL ${NVM_NODEJS_ORG_MIRROR}/latest-v${NODE_VERSION}.x/${NODE_TAR} | tar -xz -C /usr/local --strip-components=1 --exclude='*.md' --exclude='LICENSE'
109
+ # 配置 node.js
58
110
  npm config set registry=https://mirrors.tencent.com/npm/
59
111
  npm install -g npm
60
112
 
@@ -164,18 +216,16 @@ EOF
164
216
  rm -rf /tmp/* /var/tmp/* /var/log/apt /var/log/*.log /var/lib/apt/lists/* ~/.cache ~/.npm ~/go/pkg/mod/cache
165
217
  EOX
166
218
 
167
- COPY ./docker/lib/jdt-language-server-latest.tar.gz /tmp/
219
+ # 从 cache-stage 复制 JDT LSP(缓存或下载)
220
+ COPY --from=cache-stage /opt/jdtls /root/.local/share/jdtls
221
+
168
222
  RUN <<EOX
169
223
  # 安装 java
170
224
  case ",$EXT," in *,all,*|*,java,*)
171
225
  apt-get update -y
172
226
  apt-get install -y --no-install-recommends openjdk-21-jdk maven
173
227
 
174
- # 安装 LSP服务(java)
175
- mkdir -p ~/.local/share/jdtls
176
- # wget -O /tmp/jdt-language-server-latest.tar.gz https://download.eclipse.org/jdtls/snapshots/jdt-language-server-latest.tar.gz
177
- tar -xzf /tmp/jdt-language-server-latest.tar.gz -C ~/.local/share/jdtls
178
- rm -f /tmp/jdt-language-server-latest.tar.gz
228
+ # 配置 LSP服务(java)
179
229
  ln -sf ~/.local/share/jdtls/bin/jdtls /usr/local/bin/jdtls
180
230
 
181
231
  # 清理
@@ -184,6 +234,9 @@ RUN <<EOX
184
234
  ;; esac
185
235
  EOX
186
236
 
237
+ # 从 cache-stage 复制 gopls(缓存或下载)
238
+ COPY --from=cache-stage /opt/gopls /tmp/gopls-cache
239
+
187
240
  RUN <<EOX
188
241
  # 安装 go
189
242
  case ",$EXT," in *,all,*|*,go,*)
@@ -192,8 +245,16 @@ RUN <<EOX
192
245
  go env -w GOPROXY=https://mirrors.tencent.com/go
193
246
 
194
247
  # 安装 LSP服务(go)
195
- go install golang.org/x/tools/gopls@latest
196
- ln -sf ~/go/bin/gopls /usr/local/bin/gopls
248
+ if [ -f /tmp/gopls-cache/gopls ] && [ ! -f /tmp/gopls-cache/.no-cache ]; then
249
+ # 使用缓存
250
+ cp /tmp/gopls-cache/gopls /usr/local/bin/gopls
251
+ chmod +x /usr/local/bin/gopls
252
+ else
253
+ # 下载编译
254
+ go install golang.org/x/tools/gopls@latest
255
+ ln -sf ~/go/bin/gopls /usr/local/bin/gopls
256
+ fi
257
+ rm -rf /tmp/gopls-cache
197
258
 
198
259
  # 清理
199
260
  apt-get clean
package/docs/README_EN.md CHANGED
@@ -1,4 +1,4 @@
1
- [ [English](README_EN.md) ] | [中文](../README.md)
1
+ << [English](README_EN.md) >> | [中文](../README.md)
2
2
 
3
3
  ---
4
4
 
@@ -49,15 +49,23 @@ After installing manyoyo, use the built-in command to build images:
49
49
  # Pull base image
50
50
  podman pull ubuntu:24.04
51
51
 
52
- # Build using manyoyo (Recommended)
53
- manyoyo --ib all # Build all version (includes all tools)
54
- manyoyo --ib common # Build common version (basic version)
55
- manyoyo --ib go,codex,java,gemini # Build go version (includes go,codex,java,gemini tools)
52
+ # Build using manyoyo (Recommended, auto-cache enabled)
53
+ manyoyo --ib all # Build all version (auto-cache, blazing fast after first build within 2 days)
54
+ manyoyo --ib common # Build common version
55
+ manyoyo --ib go,codex,java,gemini # Build custom combination
56
+
57
+ # How it works:
58
+ # - First build: Auto-downloads Node.js, JDT LSP, gopls etc. to docker/cache/
59
+ # - Rebuild within 2 days: Uses local cache, ~5x faster
60
+ # - After cache expires: Auto-downloads latest versions
56
61
 
57
62
  # Custom image name and version
58
63
  manyoyo --ib all --in myimage --iv 2.0.0
59
64
  # Builds: myimage:2.0.0-all
60
65
 
66
+ # Clean images
67
+ manyoyo --ip # Clean dangling images and <none> images
68
+
61
69
  # Or build manually (Not recommended)
62
70
  iv=1.4.0 && podman build -t localhost/xcanwin/manyoyo:$iv-all -f docker/manyoyo.Dockerfile . --build-arg EXT=all --no-cache
63
71
  podman image prune -f
@@ -173,14 +181,18 @@ manyoyo -n docker-dev -m dind -x /bin/bash
173
181
  nohup dockerd &
174
182
 
175
183
  # Now you can use docker commands inside the container
176
- docker run hello-world
184
+ docker ps -a
177
185
  ```
178
186
 
179
187
  #### Mount Docker socket Development
180
188
 
181
189
  ```bash
182
- # Mount Docker socket (dangerous - container can access host)
183
- manyoyo -n socket-dev -m mdsock -x docker ps
190
+ # Mount Docker socket (dangerous!!! containers can access and execute everything on the host)
191
+ # Create a container mounting /var/run/docker.sock
192
+ manyoyo -n socket-dev -m mdsock -x /bin/bash
193
+
194
+ # Now you can use docker commands inside the container
195
+ docker ps -a
184
196
  ```
185
197
 
186
198
  ### Command-Line Options
@@ -203,7 +215,8 @@ manyoyo -n socket-dev -m mdsock -x docker ps
203
215
  | `-x CMD` | `--sf`, `--shell-full` | Full command (replaces --sp, -s, and --) |
204
216
  | `-y CLI` | `--yolo` | Run AI agent without confirmation |
205
217
  | `-m MODE` | `--cm`, `--cont-mode` | Set container mode (common, dind, mdsock) |
206
- | `--ib EXT` | `--image-build` | Build image, EXT is image variant (all, go, common) |
218
+ | `--ib EXT` | `--image-build` | Build image with auto-cache, EXT is image variant |
219
+ | `--ip` | `--image-prune` | Clean dangling images and `<none>` images |
207
220
  | `--install NAME` | | Install manyoyo command |
208
221
  | `-V` | `--version` | Show version |
209
222
  | `-h` | `--help` | Show help |
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@xcanwin/manyoyo",
3
- "version": "3.1.0",
4
- "imageVersion": "1.5.0",
3
+ "version": "3.4.0",
4
+ "imageVersion": "1.6.0",
5
5
  "description": "AI Agent CLI Security Sandbox",
6
6
  "keywords": [
7
7
  "ai", "agent", "sandbox", "docker", "cli", "container", "development"