fix: 修复国内网络下镜像配置缺失与 npm install 卡死问题#72
Open
hmhmdcy wants to merge 11 commits into
Open
Conversation
问题: 1. generateNpmrc() 仅写入 registry,漏配 electron/puppeteer/sharp/better-sqlite3 的二进制镜像,导致这些包的 postinstall 走默认源(GitHub/Google),国内网络 下极易卡死或失败 2. 过滤逻辑无法正确识别自动生成的键值行,每次 preinstall 执行都会将已存在的 配置误判为「用户自定义」并重复追加,导致 .npmrc 不断膨胀(实测累积 100+ 行 重复注释段) 3. 缺少 fetch-timeout,npm 包下载遇到不稳定网络时无限等待 修复: - generateNpmrc() 补齐 electron_mirror/electron_builder_binaries_mirror/ puppeteer_download_base_url/sharp_binary_host/better_sqlite3_binary_host 及 fetch-timeout=60000/fetch-retries=3 - 用 begin/end 标记包裹自动生成段,过滤时整体移除,保证幂等 - 新增 .puppeteerrc.cjs(puppeteer 24.x 读取的镜像配置文件)
- deploy.mjs: npm install 超时从 5 分钟提到 30 分钟,失败时打印常见原因与解决方案 - deploy.sh: 修正文件可执行权限 (644 -> 755) - web/pnpm-workspace.yaml: pnpm 11 要求显式许可 esbuild/vue-demi 的 build scripts
问题:
1. resolveOpenCodeExecutable() Linux 硬编码 {type:'shell',cmd:'opencode'},
不做路径查找,不读 OPENCODE_AUTO_START_CMD,systemd 环境找不到 opencode
2. buildServiceContent() 不设 Environment=PATH,systemd 默认 PATH 不含
~/.opencode/bin 和 ~/.local/bin
3. installSystemdService() 的 sudo -u 子进程被 secure_path 覆盖,
丢失用户 PATH 导致用错 Node 版本(v18 而非 v22)且找不到 npm
4. ExecStart 用 dist/index.js 而非 dist/admin/index.js,
导致 Web 面板重启 API 返回 Bridge 管理器未初始化
修复:
- resolveOpenCodeExecutable() Linux 分支补齐常见路径查找
(~/.opencode/bin, ~/.local/bin, /usr/local/bin, /usr/bin)
+ 读取 OPENCODE_AUTO_START_CMD 环境变量
- buildServiceContent() 加 Environment=PATH 和 HOME
- installSystemdService() 用 env 命令显式注入 PATH 绕过 secure_path
- ExecStart 改用 dist/admin/index.js(正确初始化 bridgeManager)
问题: startEmbedded() 动态 import index.js 触发 main(), 但未设置 BRIDGE_SPAWNED_BY_ADMIN,导致 main() 重复创建 不含 bridgeManager 的 admin server,HTTP 请求命中错误实例, restart API 返回 Bridge 管理器未初始化 修复: startEmbedded() 启动前设置 process.env.BRIDGE_SPAWNED_BY_ADMIN='1', 与子进程模式(startChildProcess 的 env)保持一致
问题: findOpenCodeProcesses() 用 isOpenCodeCommand() 匹配所有 opencode 命令 (含交互式 opencode、opencode debug 等),导致 startOpenCodeServe 的幂等检查 误判交互式 opencode 进程为 serve 已运行,跳过启动,实际 4096 端口未监听。 修复: - 新增 isOpencodeServeCommand() 精确匹配 opencode serve 进程 - findOpenCodeProcesses() 新增 serveOnly 参数 - startOpenCodeServe 的进程扫描幂等检查改用 serveOnly=true
与 startOpenCodeServe 的修复保持一致: status-opencode 的进程扫描也应只匹配 opencode serve 进程, 否则会把交互式 opencode 误报为 serve 运行中。 所有调用点安全性分析: - kill-opencode: serveOnly=false (杀所有opencode,设计如此) - list-opencode: serveOnly=false (列所有opencode,设计如此) - status-opencode: serveOnly=true (只检查serve,已修复) - startOpenCodeServe: serveOnly=true (幂等检查,已修复)
问题: process-guard.ts 的 matchesProcessKeywords 用 command.includes('opencode')
匹配所有含 opencode 的进程,不区分 serve 和交互式。当用户开着交互式
opencode 时,runningPids.length > 1 → single-instance-violation →
rescue 失败 → bridge 自动退出。
修复: 新增 matchesServeProcess(),只匹配命令行含 'serve' 的进程。
命令行信息不足时(Windows tasklist 只有进程名)保守匹配(保持原行为)。
回归测试:
- list-opencode: 列出所有(含交互式) ✅
- status-opencode: 只报告 serve ✅
- start-opencode 幂等: 跳过(serve 已运行) ✅
- Web 面板重启: ok ✅
- 飞书+opencode 重启后正常 ✅
- bridge 存活 90s 无 violation ✅
P0 修复:
1. opencode-restart.ts: spawn('opencode') 改用 resolveOpencodeExecutable()
- reliability 自动重启 opencode serve 时不再硬编码命令
2. rescue-orchestrator.ts: spawn('opencode', []) 改用 resolveOpencodeExecutable()
+ 补 'serve' 参数(原来无参数启动的是交互式 opencode)
3. 新增 src/utils/resolve-opencode.ts 共享路径解析工具
- 优先读 OPENCODE_AUTO_START_CMD
- 检查 ~/.opencode/bin, ~/.local/bin, /usr/local/bin, /usr/bin
- 与 process-manager.mjs 逻辑一致
P1 修复:
4. environment-doctor.ts: which opencode 失败时检查常见安装路径
- systemd 环境 PATH 不全时不再误报'未安装'
5. main.ts: 移除重复的 SIGTERM/SIGINT 注册
- 原来注册了两套: 一套直接 process.exit(0) 跳过异步清理,
一套走 gracefulShutdown。移除前者,避免飞书未断开/PID 未清理
回归测试:
- 编译通过, vitest 全部通过
- bridge 存活 90s 无 violation
- Web 面板重启正常
- 飞书+opencode 连接正常
发现新 bug: checkOpenCodeSingleInstance() 的 processListProvider 路径 对返回结果用 matchesProcessKeywords(匹配所有含 opencode 的进程)做二次 过滤,而不是 matchesServeProcess(只匹配 serve)。导致即使 listOpenCodeProcesses 已改用 matchesServeProcess,通过 processListProvider mock 注入的进程列表仍被旧逻辑误判。 修复: 二次过滤也改用 matchesServeProcess。 补充回归测试: - serve + 交互式 opencode 共存 → 不报 violation - 仅交互式 opencode 无 serve → 返回 not-running - 两个 serve 进程 → 报 violation (原有测试保持)
1. feishu/client.ts: handleMessage 加 message_id 去重 - 飞书 SDK 长连接模式可能对同一条消息发送两次事件 - 用 Set 缓存已处理的 message_id,避免重复处理 - 缓存上限 500 条,自动淘汰最早条目 2. feishu/client.ts: start() 前重建 eventDispatcher - 避免多次 start() 导致事件处理器重复注册 3. lifecycle/main.ts: createAdminServer 传 bridgeManager - dist/index.js 入口下 Web 面板重启功能恢复
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
问题背景
在国内网络环境下执行
./scripts/deploy.sh deploy会长时间卡死,最终失败。根因有三:setup-mirror.mjs 镜像配置缺失:
generateNpmrc()只写了registry,漏配electron_mirror/puppeteer_download_base_url/sharp_binary_host/better_sqlite3_binary_host等二进制镜像。electron (~200MB) 和 puppeteer chrome 的 postinstall 只能走 GitHub / Google 默认源,国内极易超时卡死。.npmrc 累积膨胀:
preinstall钩子每次执行setup-mirror.mjs,但旧的过滤逻辑漏过滤electron_mirror、puppeteer_download_base_url等键,导致每次部署都把这些行当“用户自定义配置”重复追加。实测一个反复部署过的仓库.npmrc膨胀到 101 行垃圾注释。npm install 无超时保护:
deploy.mjs的run('npm', ['install', ...])默认 5 分钟超时,而装 800+ 包 + 下载二进制远超此时长;且 GitHub IP 不稳定时 TCP 握手卡在SYN-SENT,npm 默认fetch-timeout=300000(5 分钟)+ 指数退避重试,体感就是“永远卡住”。修复内容
1. scripts/setup-mirror.mjs — 补齐镜像配置 + 幂等性修复
generateNpmrc()新增 electron / puppeteer / sharp / better-sqlite3 的二进制镜像配置fetch-timeout=60000/fetch-retries=3,让 npm 包下载 60 秒超时后快速重试# --- begin/end auto-generated ---标记包裹自动生成段,过滤逻辑改为按标记整段移除,彻底解决重复累积问题2. .npmrc — 清理累积垃圾,补齐镜像
3. .puppeteerrc.cjs — puppeteer 24.x 镜像配置
puppeteer v24+ 已废弃
PUPPETEER_DOWNLOAD_HOST,改读chromeDownloadBaseUrl,新增配置文件适配。4. scripts/deploy.mjs — npm install 超时保护
timeout: 1800000)--ignore-scripts)5. web/pnpm-workspace.yaml — pnpm 11 构建脚本许可
pnpm 11 不再读
package.json的pnpm字段,改用pnpm-workspace.yaml。新增allowBuilds允许 esbuild / vue-demi 运行 postinstall,否则build:web会失败。6. scripts/deploy.sh — 权限修正
644 → 755,确保
./scripts/deploy.sh可直接执行。验证
node --check语法校验通过vitest run全部通过