@xcanwin/manyoyo 4.2.3 → 4.2.5
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 +1 -0
- package/bin/manyoyo.js +39 -2
- package/lib/image-build.js +24 -8
- package/package.json +1 -1
package/README.md
CHANGED
package/bin/manyoyo.js
CHANGED
|
@@ -640,6 +640,35 @@ function installManyoyo(name) {
|
|
|
640
640
|
process.exit(0);
|
|
641
641
|
}
|
|
642
642
|
|
|
643
|
+
function updateManyoyo() {
|
|
644
|
+
let isLocalFileInstall = false;
|
|
645
|
+
try {
|
|
646
|
+
const listOutput = runCmd('npm', ['ls', '-g', '@xcanwin/manyoyo', '--json', '--long'], { stdio: 'pipe' });
|
|
647
|
+
const listJson = JSON.parse(listOutput || '{}');
|
|
648
|
+
const dep = listJson && listJson.dependencies && listJson.dependencies['@xcanwin/manyoyo'];
|
|
649
|
+
const resolved = dep && typeof dep.resolved === 'string' ? dep.resolved : '';
|
|
650
|
+
const depPath = dep && typeof dep.path === 'string' ? dep.path : '';
|
|
651
|
+
|
|
652
|
+
if (resolved.startsWith('file:')) {
|
|
653
|
+
isLocalFileInstall = true;
|
|
654
|
+
} else if (depPath && fs.existsSync(depPath)) {
|
|
655
|
+
isLocalFileInstall = fs.lstatSync(depPath).isSymbolicLink();
|
|
656
|
+
}
|
|
657
|
+
} catch (e) {
|
|
658
|
+
// ignore detect errors and fallback to registry update
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
if (isLocalFileInstall) {
|
|
662
|
+
console.log(`${YELLOW}ℹ️ 检测到 MANYOYO 为本地 file 安装(npm install -g . / npm link),跳过在线更新。${NC}`);
|
|
663
|
+
console.log(`${YELLOW} 如需更新,请在本地仓库拉取最新代码后重新安装。${NC}`);
|
|
664
|
+
return;
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
console.log(`${CYAN}🔄 正在更新 ${MANYOYO_NAME} 到最新版本...${NC}`);
|
|
668
|
+
runCmd('npm', ['update', '-g', '@xcanwin/manyoyo'], { stdio: 'inherit' });
|
|
669
|
+
console.log(`${GREEN}✅ 更新完成,请重新执行 ${MANYOYO_NAME} --version 确认版本。${NC}`);
|
|
670
|
+
}
|
|
671
|
+
|
|
643
672
|
function getContList() {
|
|
644
673
|
try {
|
|
645
674
|
const result = execSync(`${DOCKER_CMD} ps -a --size --filter "ancestor=manyoyo" --filter "ancestor=$(${DOCKER_CMD} images -a --format '{{.Repository}}:{{.Tag}}' | grep manyoyo)" --format "table {{.Names}}\\t{{.Status}}\\t{{.Size}}\\t{{.ID}}\\t{{.Image}}\\t{{.Ports}}\\t{{.Networks}}\\t{{.Mounts}}"`,
|
|
@@ -724,6 +753,7 @@ async function setupCommander() {
|
|
|
724
753
|
-- <args...> → 直接透传命令后缀(优先级最高)
|
|
725
754
|
|
|
726
755
|
示例:
|
|
756
|
+
${MANYOYO_NAME} --update 更新 MANYOYO 到最新版本
|
|
727
757
|
${MANYOYO_NAME} --ib --iv ${IMAGE_VERSION_HELP_EXAMPLE} 构建镜像
|
|
728
758
|
${MANYOYO_NAME} --init-config all 从本机 Agent 配置初始化 ~/.manyoyo
|
|
729
759
|
${MANYOYO_NAME} -r claude 使用 manyoyo.json 的 runs.claude 快速启动
|
|
@@ -751,6 +781,7 @@ async function setupCommander() {
|
|
|
751
781
|
.option('--ib, --image-build', '构建镜像')
|
|
752
782
|
.option('--iba, --image-build-arg <arg>', '构建镜像时传参给dockerfile (可多次使用)', (value, previous) => [...(previous || []), value], [])
|
|
753
783
|
.option('--init-config [agents]', '初始化 Agent 配置到 ~/.manyoyo (all 或逗号分隔: claude,codex,gemini,opencode)')
|
|
784
|
+
.option('--update', '更新 MANYOYO(若检测为本地 file 安装则跳过)')
|
|
754
785
|
.option('--irm, --image-remove', '清理悬空镜像和 <none> 镜像')
|
|
755
786
|
.option('-e, --env <env>', '设置环境变量 XXX=YYY (可多次使用)', (value, previous) => [...(previous || []), value], [])
|
|
756
787
|
.option('--ef, --env-file <file>', '设置环境变量通过文件 (仅支持绝对路径,如 /abs/path.env)', (value, previous) => [...(previous || []), value], [])
|
|
@@ -784,8 +815,9 @@ async function setupCommander() {
|
|
|
784
815
|
}
|
|
785
816
|
|
|
786
817
|
const isInitConfigMode = process.argv.some(arg => arg === '--init-config' || arg.startsWith('--init-config='));
|
|
787
|
-
|
|
788
|
-
|
|
818
|
+
const isUpdateMode = process.argv.includes('--update');
|
|
819
|
+
// init-config/update 只处理本地文件或 npm,不依赖 docker/podman
|
|
820
|
+
if (!isInitConfigMode && !isUpdateMode) {
|
|
789
821
|
// Ensure docker/podman is available
|
|
790
822
|
ensureDocker();
|
|
791
823
|
}
|
|
@@ -803,6 +835,11 @@ async function setupCommander() {
|
|
|
803
835
|
YES_MODE = true;
|
|
804
836
|
}
|
|
805
837
|
|
|
838
|
+
if (options.update) {
|
|
839
|
+
updateManyoyo();
|
|
840
|
+
process.exit(0);
|
|
841
|
+
}
|
|
842
|
+
|
|
806
843
|
if (options.initConfig !== undefined) {
|
|
807
844
|
await initAgentConfigs(options.initConfig, {
|
|
808
845
|
yesMode: YES_MODE,
|
package/lib/image-build.js
CHANGED
|
@@ -43,7 +43,7 @@ function createBuildCacheContext(ctx) {
|
|
|
43
43
|
return {
|
|
44
44
|
cacheDir,
|
|
45
45
|
timestampFile,
|
|
46
|
-
cacheTTLDays: config.cacheTTL
|
|
46
|
+
cacheTTLDays: config.cacheTTL ?? ctx.cacheTtlDays,
|
|
47
47
|
nodeMirrors: [config.nodeMirror, 'https://mirrors.tencent.com/nodejs-release', 'https://nodejs.org/dist'].filter(Boolean),
|
|
48
48
|
timestamps: loadBuildCacheTimestamps(timestampFile),
|
|
49
49
|
now: new Date()
|
|
@@ -152,19 +152,30 @@ function cleanupGoTmpPath(ctx, tmpGoPath, warnOnError) {
|
|
|
152
152
|
const { YELLOW, NC } = ctx.colors;
|
|
153
153
|
if (!fs.existsSync(tmpGoPath)) return;
|
|
154
154
|
|
|
155
|
+
let cleanupFailed = false;
|
|
155
156
|
try {
|
|
156
157
|
ctx.runCmd('go', ['clean', '-modcache'], {
|
|
157
158
|
stdio: 'inherit',
|
|
158
159
|
ignoreError: true,
|
|
159
160
|
env: { ...process.env, GOPATH: tmpGoPath }
|
|
160
161
|
});
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
} catch (e) {
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
162
|
+
} catch (e) { cleanupFailed = true; }
|
|
163
|
+
try { ctx.runCmd('chmod', ['-R', 'u+w', tmpGoPath], { stdio: 'inherit', ignoreError: true }); } catch (e) { cleanupFailed = true; }
|
|
164
|
+
try { ctx.runCmd('rm', ['-rf', tmpGoPath], { stdio: 'inherit', ignoreError: true }); } catch (e) { cleanupFailed = true; }
|
|
165
|
+
if (cleanupFailed && warnOnError) {
|
|
166
|
+
ctx.log(`${YELLOW}提示: 临时目录清理失败,可手动删除 ${tmpGoPath}${NC}`);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function isGoCommandMissing(error) {
|
|
171
|
+
const message = error && error.message ? String(error.message) : '';
|
|
172
|
+
const stderr = error && error.stderr ? String(error.stderr) : '';
|
|
173
|
+
const stdout = error && error.stdout ? String(error.stdout) : '';
|
|
174
|
+
const combined = `${message}\n${stderr}\n${stdout}`.toLowerCase();
|
|
175
|
+
if (error && String(error.code || '').toUpperCase() === 'ENOENT') {
|
|
176
|
+
return /\bgo\b/.test(message.toLowerCase()) || /spawnsync go enoent|spawn go enoent/.test(combined);
|
|
167
177
|
}
|
|
178
|
+
return /spawnsync go enoent|spawn go enoent|go: not found|go: command not found|command not found: go/.test(combined);
|
|
168
179
|
}
|
|
169
180
|
|
|
170
181
|
function resolveGoplsSource(tmpGoPath, arch) {
|
|
@@ -209,6 +220,11 @@ function prepareGoplsBuildCache(ctx, cache, imageTool, arch) {
|
|
|
209
220
|
ctx.log(`${GREEN}✓ gopls 下载完成${NC}`);
|
|
210
221
|
cleanupGoTmpPath(ctx, tmpGoPath, true);
|
|
211
222
|
} catch (e) {
|
|
223
|
+
if (isGoCommandMissing(e)) {
|
|
224
|
+
ctx.log(`${YELLOW}提示: 未检测到本机 go,跳过 gopls 本地缓存预下载,将在镜像构建阶段安装${NC}`);
|
|
225
|
+
cleanupGoTmpPath(ctx, tmpGoPath, false);
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
212
228
|
ctx.error(`${RED}错误: gopls 下载失败${NC}`);
|
|
213
229
|
throw e;
|
|
214
230
|
}
|
|
@@ -293,7 +309,7 @@ function buildBuildkitRunArgs(ctx, dockerfilePath, fullImageTag, imageBuildArgs)
|
|
|
293
309
|
'--local', 'context=/workspace',
|
|
294
310
|
'--local', 'dockerfile=/workspace',
|
|
295
311
|
'--opt', `filename=${dockerfileRelativePath}`,
|
|
296
|
-
'--opt', `build-arg:
|
|
312
|
+
'--opt', `build-arg:HTTP_PROXY=$HTTP_PROXY`,
|
|
297
313
|
'--opt', `build-arg:HTTPS_PROXY=$HTTPS_PROXY`,
|
|
298
314
|
'--opt', `build-arg:ALL_PROXY=$ALL_PROXY`,
|
|
299
315
|
'--opt', `build-arg:NO_PROXY=$NO_PROXY`
|