OpenMausBot Local VM 停止与恢复生命周期验证指南:从镜像锁清理到 UI 一次性启动

发布时间:2026/10/31 6:53:33

OpenMausBot Local VM 停止与恢复生命周期验证指南:从镜像锁清理到 UI 一次性启动 人工智能AI AgentAI 应用大模型交互助手工具调用Agent 编排桌面应用【免费下载链接】OpenMausBotOpen-source Grok Bot alternative with a virtual machine that bots can use项目地址https://gitcode.com/GitHub_Trending/op/OpenMausBot点击查看免费下载本文聚焦 OpenMausBot 中 Local VM本地虚拟机的“停止—恢复”生命周期说明如何用仓库自带的两条命令完整验证idle 自动停止不会删除容器、停止原因能跨服务重启保留、UI 上的 Start 只发出一次请求并在 Cua 预热期间保持忙碌状态、就绪桌面替换空态而无需 remove/recreate。读完后你将掌握这套验证的分层结构前端面板、服务端路由、镜像启动脚本、真实容器验收以及每个断言背后的源码依据可以独立复现或扩展其中的任一环节。一、核心结论先行停止必须可恢复而不是重造OpenMausBot 的 Local VM 是运行在宿主机容器运行时Docker / Podman / Apple container里的 Cua 桌面。资源节约策略会让闲置的桌面停掉但**“停止”语义必须是可恢复的**否则用户的文件、浏览器登录态与已安装应用都会随一次节能动作消失。文档 docs/verification/local-vm-resume.md 定义了三层可验证承诺服务端idle 停止只下发stop绝不触发remove停止原因写入磁盘服务重启后仍能读到。前端面向已存在但已停止的 VM界面给出“已停止”与原因解释Start 只发一次请求请求返回后容器已 running 但 Cua 尚未就绪时按钮保持 disabled aria-busy就绪后直接用预览替换空态。镜像容器复用 home 目录、甚至被docker kill --signal KILL暴力终止后陈旧的 X / 浏览器锁不会导致恢复被拒。对应的源码事实是localVmResumable()只有在运行时可用、守护进程在线、镜像存在、容器为stopped、网络为 loopback、安全加固通过、workspace 持久化安全时才允许走start分支server/container-computer.ts。任何一项“未知”都会 fail closed而不是乐观放行。二、两条命令即可跑完整个生命周期检查文档给出的入口非常克制一共两行pnpm exec vitest run server/container-computer.test.ts server/local-vm-browser-profiles.test.ts server/local-vm-stop-reason.test.ts server/computer-idle.test.ts server/group-local-vm.e2e.test.ts server/routes/desktop-viewer.test.ts src/components/LocalComputerSection.test.ts src/components/ComputerPanel.test.ts src/components/ComputerPanel.i18n.test.ts node --experimental-strip-types scripts/verify-local-vm-resume.ts第一行是九个文件的单元 / 集成 / e2e 组合覆盖容器动作、镜像启动脚本、停止原因、idle 计时器、真实 HTTP 路由与 UI 组件第二行直接以 Node 的 type stripping 运行 UI 证据脚本scripts/verify-local-vm-resume.ts不需要额外编译步骤。运行前提仓库根目录、已安装依赖、有可用的 Chromium/Chrome脚本会自行解析或下载固定版本且不需要宿主机 Docker 守护进程——浏览器配方全程走合成传输。真实 Docker 只出现在文档记录的那次手工验收中。两条命令的分工可以这样理解vitest负责“逻辑与契约”verify-local-vm-resume.ts负责“真实组件 真实浏览器 可归档证据”。三、测试矩阵每个文件守住一条承诺测试文件守护的核心行为server/container-computer.test.ts容器生命周期动作resumes a compatible stopped desktop without removing it断言只调用docker start且调用序列中不含rm/runserver/local-vm-browser-profiles.test.ts运行镜像真实的启动脚本与真实的 profile 抢救逻辑验证登录态跨镜像替换存活、锁清理时机正确server/local-vm-stop-reason.test.ts停止原因按 target key 隔离、只在stopped_at精确匹配时返回idleserver/computer-idle.test.tsidle 计时器只在完整静默窗口后挂起忙碌时不挂起异常按退避重试server/group-local-vm.e2e.test.ts真实 HTTP 路由 真实 idle 计时器 测试专用 loader 缩短窗口server/routes/desktop-viewer.test.ts桌面查看器/状态路由对非就绪、非受管、网络不安全等状态的拒绝路径src/components/LocalComputerSection.test.ts设置页的 Local VM 生命周期请求构造与破坏性操作确认src/components/ComputerPanel.test.ts控制权租约切换顺序先闸门后服务端、先释放后清理src/components/ComputerPanel.i18n.test.ts面板文案在语言切换后语义稳定这张表值得单独强调恢复正确性不是单点函数而是一条贯穿镜像、服务器、路由、UI 的链路。少任何一层“停止后能否恢复”就退化成人工经验。四、镜像准备脚本为什么“复用 home 目录”曾是不可恢复的根因镜像构建阶段会生成/usr/local/bin/prepare-openmausbot-workspace.sh其脚本正文由 server/container-workspace.ts 中的workspacePreparationDockerfile()以printf形式写入 Dockerfile。理解这个脚本就理解了文档里“browser locks are cleared once per container start”的含义。4.1 三类 profile 与一类应用目录的迁移脚本先建立持久化骨架workspace/home/cua/workspace profiles$workspace/.browser-profiles apps$workspace/.desktop-apps mkdir -p $profiles/google-chrome $profiles/chromium $profiles/mozilla $apps/local $HOME/.config $HOME/.cache随后migrate_profile做“只在目标为空时拷入然后把源目录换成符号链接”migrate_profile() { source$1 target$profiles/$2 if [ -d $source ] [ ! -L $source ] [ -z $(find $target -mindepth 1 -print -quit) ]; then cp -a $source/. $target/ fi rm -rf $source ln -s $target $source } migrate_profile $HOME/.config/google-chrome google-chrome migrate_profile $HOME/.config/chromium chromium migrate_profile $HOME/.mozilla mozilla~/.local走同样思路但方向相反先把旧内容搬进$apps/local再把~/.local变成指向它的链接。效果是home 目录可以被随意丢弃真正的用户数据永远落在挂载的 workspace 上。server/local-vm-browser-profiles.test.ts 用一个临时的 fake home/workspace 验证了这一点跑完后~/.mozilla是指向workspace/.browser-profiles/mozilla的符号链接profiles.ini内容仍在Chrome/Chromium 的旧行为不受影响。4.2 容器身份boot ID PID 1 启动时间锁清理的判据是“这是不是一个新容器”container_start$(cat /proc/sys/kernel/random/boot_id):$(sed s/.*) // /proc/1/stat | cut -d -f20) prepared$HOME/.cache/openmausbot-browser-locks if [ $(cat $prepared 2/dev/null || true) ! $container_start ]; then find $profiles \( -name SingletonLock -o -name SingletonSocket -o -name SingletonCookie -o -name .parentlock -o -name lock -type l \) -delete printf %s\n $container_start $prepared fi注意判据是boot ID 与 PID 1 启动时间的组合而不是容器名或 home 路径。这正好解释了文档中的两条关键描述“Browser locks are cleared once per container start.”——同一容器内多次执行准备脚本$prepared内容不变什么都不删。“A changed PID 1 start time or boot ID clears old locks again, including when the container reuses its home directory.”——容器重建但复用 home 时/proc/1/stat第 20 字段或 boot ID 必然变化陈旧锁被清掉。find的目标列表也很有讲究Chromium 系的SingletonLock/SingletonSocket/SingletonCookieFirefox 系的.parentlock与符号链接型lock。用-type l限定lock是为了只删符号链接形态Firefox 用它指向持锁主机不误删普通文件。4.3 “Cua driver 重启不清理活锁”的测试如何证明server/local-vm-browser-profiles.test.ts 的用例名直接表达契约keeps live browser locks across a Cua driver restart until the %s changes并通过it.each([PID 1 start time, boot ID])参数化两条路径。测试流程是先跑一次准备脚本写入身份文件手工造出三份 Chromium 锁与一份 Firefoxlock符号链接 .parentlock再跑一次准备脚本——身份未变逐个readlinkSync断言目标原封不动改写boot-id或init-stat第 20 字段从123改成456第三次运行脚本——所有锁被删除。这里有个实现细节非常值得借鉴测试并不是直接执行 Dockerfile而是从managedImageDockerfile()里截取真实的RUN printf片段把/home/cua/workspace、/proc/sys/kernel/random/boot_id、/proc/1/stat三个路径替换为临时文件后再执行server/local-vm-browser-profiles.test.ts。这样“测的脚本”和“镜像里的脚本”是同一份文本而不是复制品。五、镜像替换前的抢救rescueFirefoxProfile与rescueInstalledApps恢复能力还有第二条支线当旧桌面所在镜像已经不被当前版本接受时系统不是硬重启而是先把登录态与应用拷进 workspace 再删除容器。实现在 server/local-vm-profiles.ts。rescueFirefoxProfile的返回值是三态契约rescued从containerName:/home/cua/.mozilla拷到随机 staging 目录再 rename 到workspace/.browser-profiles/mozillakeptworkspace 里已有非空 profile绝不覆盖none容器里根本没有~/.mozilla从未用过 Firefox或~/.mozilla已是链接新桌面的正常形态。错误处理只放行一类“预期失败”容器内文件不存在正则匹配 Docker/Podman 的 Could not find the file其余错误一律抛出避免把权限问题伪装成“没有东西可抢救”。测试里的 fake runtime 是一个只实现cp的 shell 脚本正如docker cp对已停止容器的行为server/local-vm-browser-profiles.test.ts。rescueInstalledApps额外加了一道安全闸如果 workspace 里已有的.desktop-apps/local与容器内的内容不一致直接抛could not preserve installed desktop apps because the durable app area differs from the old desktop而不是合并或覆盖。这条对应的测试断言持久区内容仍是durable desktop。六、浏览器端 recipe真实面板 合成桌面传输scripts/verify-local-vm-resume.ts 是整个文档里信息密度最高的部分。它做的不是“截图工具”而是一个受控的真 UI 试验台。6.1 启动与隔离const fixture await launchVerificationServer(); const home mkdtempSync(join(tmpdir(), omb-vmr-)); // Keep macOS browser sockets below their path limit.launchVerificationServer()来自 scripts/control-omb.ts会拉起一个隔离数据目录的服务器并返回{ url, pid, dataDir, logPath }runControlOmb([new-bot, ...])建一个种子 bot。mountPreview()再以 Vite 起一个只服务指定入口的预览站点并把/api反代到 fixturescripts/testing/preview-fixture.ts。页面的入口是/scripts/testing/cloud-preview.tsx其中真正挂载的是生产组件ComputerPanel /与LocalComputerSection /只是window.fetch被替换为合成传输scripts/testing/cloud-preview.tsx。合成传输里的vmResumeStatus()精确模拟了恢复场景需要的字段container: vmRunning ? running : stopped, resumable: !vmRunning, desktopReady: vmDesktopReady, ready: vmDesktopReady, stop_reason: vmRunning ? null : idle, problem: vmDesktopReady ? null : vmRunning ? Desktop is starting : The Local VM is stopped,这几行是整段 UI 验证的地基容器已经 running、但readyfalse的状态只能伪造出来真实 Docker 里很难稳定复现在这个瞬间做断言。6.2 复用本机已安装的浏览器文档明确要求Set OMB_AGENT_BROWSER_PATH and AGENT_BROWSER_EXECUTABLE_PATH to reuse installed tools.优先级在 scripts/testing/control-omb-ui.ts 中实现先看OMB_AGENT_BROWSER_PATHagent-browser 可执行文件再看工具目录最后看 PATH否则按固定版本下载并用大小与 SHA-256 校验。Chrome 遵循同一规则环境变量名是AGENT_BROWSER_EXECUTABLE_PATH且文件不存在时会直接报错提示unset it to use the Chrome agent-browser installs。两者都只会落到UI_TOOLS_DIR下一份。6.3 证据目录、日志与录屏const evidenceDir process.env.OMB_UI_EVIDENCE_DIR ? resolve(process.env.OMB_UI_EVIDENCE_DIR) : dirname(fixture.info.logPath); const record process.env.OMB_UI_RECORD 1;默认证据三张截图与持久日志同目录即logPath所在目录OMB_UI_EVIDENCE_DIR可重定向到任意目录脚本会mkdirSync(..., { recursive: true })OMB_UI_RECORD1且 PATH 上有ffmpeg时额外产出resume.mp4。脚本启动时第一行就console.log(JSON.stringify(fixture.info))把隔离服务器 URL 与日志路径打印出来——这就是文档里说的 receipt。失败时它会在catch中打印一份 agent-browser snapshot 再抛出便于定位是选择器错了还是状态没到。6.4 等待条件没有固定延迟文档特别强调 “The readiness assertion waits for two actual status reads while the desktop is held unready; it uses no fixed delay.” 实现是await wait(window.cloudPreviewFixture.vmStarts 1); await wait(Array.from(document.querySelectorAll(button)).some(b b.textContent.includes(Starting Local VM) b.disabled b.getAttribute(aria-busy) true)); await wait(window.cloudPreviewFixture.vmReadinessReads 2); assert.equal(await evaluate(Array.from(document.querySelectorAll(button)).some(b b.textContent.includes(Starting Local VM) b.disabled)), true);vmReadinessReads只在vmRunning !vmDesktopReady时自增scripts/testing/cloud-preview.tsx所以“≥2”等价于“前端至少又真实轮询了两次状态而桌面仍未就绪”。这是对生产轮询逻辑waitForLocalVmReady的直接观测而不是睡眠若干秒碰运气。生产轮询本身的参数也值得记住默认 2000 ms 间隔、60 s 超时循环条件是!ready container running并且每次都用AbortSignal检查取消。七、UI 断言清单文档那四句话的逐条落地文档描述浏览器检查证明了四件事。对照脚本可以逐条映射文档描述脚本中的断言existing shared VM shows “stopped” and an idle explanation切到vm-stopped场景后wait(The Local VM is stopped)并断言含Stopped after inactivity、不含isnt available for this botStart issues exactly one request点击Start Local VM后wait(vmStarts 1)结尾再assert.equal(vmStarts, 1)button stays disabled and busy after that request returns while Cua is still warming up断言存在文案含Starting Local VM、disabled、aria-busytrue的按钮ready desktop replaces the empty state without a remove or recreate request断言存在img.src vmScreenshot naturalWidth 1且paths中没有以/local-computer/remove或/local-computer/run结尾的请求Settings offers Start for a stopped VM and waits for readiness重置后切到 Settings 面板点 Startwait(Waiting for the desktop)点Finish VM startupwait到某个[aria-live]文本恰为Ready两个文案来源可以追到源码vm.stopped.idle与vm.stopped.detail定义在 src/locales/en.json另有 ja/it/es/tr/pl 等语言版本面板在 src/components/ComputerPanel.tsx 与 src/components/LocalComputerSection.tsx 用status.stop_reason idle二选一。paths这个数组记录所有含/computer或/local-computer的请求路径结尾用some(p p.endsWith(/local-computer/remove) || p.endsWith(/local-computer/run))反向断言。换句话说“恢复”路径上任何一次“重建”都会让测试失败这是本文最值得抄走的一条断言写法。八、服务端 fixture真实路由 真实计时器只换容器边界group-local-vm.e2e.test.ts不是普通 mock 测试。文档描述是“runs the actual HTTP routes and idle timer, replacing only the container boundary and shortening the idle window through a test-only loader.”具体机制在 server/testing/group-local-vm-hooks.mjs通过module.registerHooks拦截container-computer.ts与local-vm-profiles.ts的解析换成 fixture 版本fixture 的containerComputerStatus()从状态文件读containers/stopped/stoppedAt/outdated/failed等字段containerComputerAction()把run/start/stop/remove逐个记入actions。真实的服务启动、路由、租约、idle timer、MCP 配置全部保留。“缩短 idle window”是通过改写源码文本实现的把checkedIdleMs(idleMs)替换成读状态文件里idleMs的表达式server/testing/group-local-vm-hooks.mjs。所以用例里可以写vmState({ containers: [shared], idleMs: 300 })让 300 ms 就触发一次真实空闲回收。8.1 三个断言串成一条因果链server/group-local-vm.e2e.test.ts 的核心用例vmState({ containers: [shared], idleMs: 300 }); await api(PATCH, /api/config, { localVm: { mode: shared, idleTimeoutMinutes: 5 } }); const { bot } await api(POST, /api/bots, { name: Resume fixture, computer: vm }); await until(() api(GET, /api/local-computer), s s.container stopped); expect((await api(GET, /api/local-computer)).stop_reason).toBe(idle); const stopped JSON.parse(readFileSync(stateFile, utf8)); expect(stopped.containers).toEqual([shared]); // 容器还在 expect(stopped.actions).toEqual([{ action: stop, target: shared }]); // 只有 stop然后它把idleMs调大、SIGTERM结束并重启服务再断言stop_reason仍是idle随后POST /api/local-computer/start得到ready true且stop_reason变回null动作序列变成stop → start。没有 remove也没有 run。8.2 停止原因为什么能跨重启存活server/local-vm-stop-reason.ts 的实现只有二十多行但设计很克制function recordPath(key: string, dataDir: string): string { return join(dataDir, local-vm-stops, ${createHash(sha256).update(key).digest(hex)}.json); }文件名是 target key 的 SHA-256避免把bot:digest之类的键直接写进路径目录0700、文件0600写入走writeFileAtomic读取时要求status.container stopped且stopped_at存在然后精确比较stoppedAt status.stopped_at。最后这条比较是关键设计stopped_at来自容器的State.FinishedAtserver/container-computer.ts。如果之后有人手动停了一次、或者时间戳无从确定匹配失败localVmStopReason返回nullUI 就回落到中性的vm.stopped.detail而不会误报“因闲置而停止”。server/local-vm-stop-reason.test.ts 用四行断言把这个矩阵钉死不同 target key 为null、时间戳变化为null、容器 running 为null、缺stopped_at为null。写入时机在 idle 回调里server/index.tsconst status await containerComputerStatus(undefined, undefined, target); if (status.container running status.managed) { const stopped await containerComputerAction(stop, undefined, undefined, target); recordLocalVmIdleStop(target.key, stopped.stopped_at); }注意它先确认running managed再 stop并把 stop 返回的stopped_at落盘——记录的时间戳与运行时FinishedAt天然一致这正是文档里“The reason record matches the runtimes finish timestamp”的来源。对外暴露则通过localVmPayload()server/index.ts把stop_reason: localVmStopReason(target.key, status)与idle_timeout_ms、mode、max_instances一起返回。8.3 idle 计时器本身的行为边界server/computer-idle.test.ts 覆盖的六条行为构成恢复链路的前置条件只在完整静默窗口后才挂起999 ms 不触发、1000 ms 触发touch()续期忙碌时绝不挂起且“第一次发现空闲”要重新等满一个窗口忙碌期间每 1/10 窗口复查一次BUSY_CHECKS_PER_WINDOW让晚结束的工作仍获得完整静默窗口手动 stop 后可cancel()不再触发窗口时长变更时从最后一次活动时间重算剩余时间。失败路径也有明确策略suspend()抛错时按idleMs * 2^(failures-1)退避上限至少一个窗口、最多一小时server/computer-idle.ts。这解释了为什么一次设备忙碌或 Docker 抖动不会让 VM 永久失去回收能力。九、容量上限不会阻塞“恢复已有桌面”文档提到 per-bot 与 Auto 场景shared and per-bot starts work, and an Auto turn resumes an existing desktop even when the per-bot capacity limit is reached.源码里的分叉点很清晰server/index.tsconst action localVmWakeAction(status); if (status.ready || !action || !status.runtime) return status; if (action run !pooled !ownsProvision) return status; if (action run target.key.startsWith(bot:)) { const count await existingPerBotLocalVmCount(status.runtime); if (!isCurrent() || count localVmMaxInstances(cfg)) return status; } ... status await containerComputerAction(action, undefined, undefined, target);容量检查只挂在action run新建分支上action start恢复不经过任何maxInstances判断。语义上这是显然的已经在磁盘上存在的桌面不占用新的配额。对应 e2e 用maxInstances: 1把场景推到极限server/group-local-vm.e2e.test.tsrun → stop → start → stop然后清掉 bot 的computer/browser配置发一条普通消息期望 Auto 又触发一次start。最终动作序列断言为[run, stop, start, stop, start]。这条序列同时证明了两件事恢复走start而非run且 Auto turn 在配额已满时仍能接上既有桌面。配额本身的范围定义在 server/local-vm-settings.ts默认maxInstances 21–8默认idleTimeoutMinutes 4805–1440默认模式shared另有per-bot与pool。localVmPreservesInstalledApps默认关闭是显式 opt-in——这与 rescue 逻辑“只在需要时抢救”的保守取向一致。十、生产就绪探针三道门槛决定desktopReady文档提到真实验收“passed the production readiness probe (driver version, health report, and complete screenshot)”。这三项在 server/container-computer.ts 里是严格的前置组合且只有在container running、镜像匹配、受管、loopback、安全加固、持久化安全全部满足时才会执行版本cua-driver --version必须精确等于cua-driver ${CUA_DRIVER_VERSION}当前为0.37.0随后status --socket /run/user/1000/openmausbot-cua.sock必须成功健康报告call health_report的 JSON 必须schema_version 1、checks是数组、overall为ok或degraded完整截图get_desktop_state ... --screenshot-out-file /tmp/openmausbot-readiness.png再用base64 -w0取回并交给wholeScreenshot()校验不完整即判失败。失败时它会tail -n 4 /var/log/supervisor/cua-driver.error.log并把 320 字符内的错误写进desktop_error最终status.ready status.problem null。这解释了 UI 为什么能在“容器已起、桌面未就绪”区间稳定显示忙碌态ready是一个由真实探针得出的布尔值而不是“容器 running”的同义词。十一、真实 Docker 验收记录2026-10-01 的两次停止/两次强杀文档记录了一次手工验收这是唯一触及真实宿主 Docker 的环节条件与结论都需要准确复述环境Linux 上的 Docker使用单独创建的、一次性的容器镜像为当时固定的driver-0.20.0-v5。常规轮次两轮 stop/start 均通过生产就绪探针driver 版本、health report、完整截图且/home/cua与/opt下的标记文件都保留。强杀轮次两轮docker kill --signal KILL之后再恢复先用docker cp确认/tmp/.X1-lock仍留在已停止的容器里再调用生产 Start。两轮同样通过就绪与标记文件检查。根因与修复固定镜像的/usr/local/bin/start-vnc.sh会在启动 VNC 前删除/tmp/.X1-lock与/tmp/.X11-unix/X1这正面解决了此前“一律拒绝恢复”背后的陈旧锁顾虑。清洁度fixture 使用空的临时 workspace事后全部删除不需要重建镜像。不覆盖范围Podman、Apple container、原生 iOS以及镜像替换后的持久化。关于版本号需要一句提醒文档记录的是当时的driver-0.20.0-v5当前源码中CUA_DRIVER_VERSION 0.37.0、IMAGE_LAYER_VERSION 7镜像引用形如localhost/openmausbot/cua-local-vm:driver-0.37.0-v7server/container-computer.ts。也就是说那次验收证明的是机制而不是某个永久有效的标签重新验收时应以当前IMAGE常量与com.openmausbot.*标签为准因为“镜像与容器标签、而非可变 tag 决定兼容性”。十二、Review evidence证据是怎么被约束的文档的 Review evidence 一节给了四类产物全部位于docs/verification/evidence/local-vm-resume/下证据说明before.png在未改动生产代码的上游提交9f0c33d00fc490491bf794704fd192046d2f31eb上截取使用同一套一次性 fixture 与被检查过的 stopped-VM 响应其状态文案反映基线服务器拒绝恢复stopped.png改动后的面板已停止 idle 解释 Startstarting.png请求已返回、Cua 预热中按钮禁用且带 spinnerready.png就绪桌面替换空态resume.mp4记录 Start、两次禁用态的轮询、以及就绪预览三条约束值得学习before 图必须来自未修改的生产代码只把 fixture 传输层拷进那个 checkout——否则“修复前”就没有说服力截图捕获的是真实 panel 元素screenshot aside不是拼图视频只隐藏 fixture 控件.fixed.left-2.top-2产品 UI 原样保留桌面预览明确标注为合成不宣称真实远程会话或原生移动端验收。十三、复现清单与常见坑按顺序执行可以让这套验证在你的机器上稳定跑通pnpm install确认 Node 版本支持--experimental-strip-types先跑九个 vitest 文件定位是逻辑层还是 UI 层的问题需要离线/复用时导出OMB_AGENT_BROWSER_PATH与AGENT_BROWSER_EXECUTABLE_PATH指向本机已安装的 agent-browser 与 Chrome需要归档证据时导出OMB_UI_EVIDENCE_DIR录屏再叠加OMB_UI_RECORD1并确保ffmpeg在 PATH 上运行node --experimental-strip-types scripts/verify-local-vm-resume.ts从首行打印的 JSON 取隔离 URL 与日志路径想验证真实容器时不要在正在使用的数据目录上试验按文档做法新建一次性容器与空临时 workspace验收后清理。常见坑与对应源码位置以为pnpm dev的实例会被脚本改动不会脚本自带隔离数据目录与随机端口mountPreview只绑定127.0.0.1。在 macOS 上路径过长导致浏览器 socket 失败脚本用mkdtempSync(join(tmpdir(), omb-vmr-))并在注释里写明这一动机不要在深层目录里改TMPDIR。误判“停止原因丢了”localVmStopReason要求stopped_at与记录精确一致容器被外部再停一次就会回落为中性文案这是设计而非缺陷。以为 idle 到点必然停ComputerIdleTimer在isBusy()为真时只复查不挂起localVmIdleFor的忙碌判定包含镜像忙碌、生命周期忙碌与活跃线程server/index.ts。在旧镜像上期待恢复成功localVmResumable会因imageMatches、安全、持久化等任一不满足而拒绝此时应走 rescue recreate而不是手工docker start。结语这套验证的价值不在于九条命令本身而在于它把“停止后可恢复”拆成了四个可独立证伪的层镜像启动脚本的锁语义、服务端的 stop reason 与 idle 计时器、UI 的一次启动与无固定延迟就绪等待、以及一次带明确边界的真实 Docker 验收。任何一层回退都会在对应文件里立刻显形——而 docs/verification/local-vm-resume.md 正是这条链路的索引地图。赞分享人工智能AI AgentAI 应用大模型交互助手工具调用Agent 编排桌面应用【免费下载链接】OpenMausBotOpen-source Grok Bot alternative with a virtual machine that bots can use项目地址https://gitcode.com/GitHub_Trending/op/OpenMausBot点击查看免费下载相关推荐PRAXIST 直接 CLI 运维指南从校验、启动到观察、停止与恢复的完整生命周期PRAXIST 直接 CLI 运维指南从校验、启动到观察、停止与恢复的完整生命周期 本文是面向运维人员operator的 PRAXIST 直接 CLI 操人工智能AI Agent多智能体Agent 工作流深度研究AI 评测OpenSandbox CLI 沙箱生命周期管理实战从配置解析到创建、验证、续期、暂停/恢复与清理OpenSandbox CLI 沙箱生命周期管理实战从配置解析到创建、验证、续期、暂停/恢复与清理 本文围绕 OpenSandbox CLI osb 内置人工智能AI AgentAgent 沙箱云原生容器编排虚拟化后端前端网络安全密钥管理CLI微服务Protoactor-go生命周期管理终极指南从启动到停止的完整流程Protoactor go生命周期管理终极指南从启动到停止的完整流程 Protoactor go是Go语言中一个高性能的分布式Actor框架其生命周期管理机后端上一篇语义去重与智能合并基于sentence-transformersFAISS的ACE BulletpointAnalyzer工作原理下一篇如何用splat-transform对高斯场景做平移、旋转、缩放变换操作完全教程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
延伸阅读

更多相关文章

2026/10/31 11:24:06

基于Transformer的煤矿图文检索系统设计与实现

1. 项目概述:煤矿热点新闻图文检索系统 在煤矿安全生产领域,及时获取行业热点新闻的图文信息对从业人员具有重要价值。本项目基于Transformer架构和Flask框架,开发了一套面向煤矿领域的图文检索系统,实现了新闻文本与相关图片的智…

2026/10/31 11:24:06

深度兴趣网络DIN:注意力机制在CTR预测中的实战应用

1. 深度兴趣网络DIN:注意力机制在CTR预测中的实战解析 推荐系统领域有个经典难题:如何让算法真正理解用户瞬息万变的兴趣?2018年阿里提出的DIN(Deep Interest Network)给出了惊艳答案。这个基于注意力机制的CTR预测模型,在当年双十…

2026/10/31 11:24:06

学生学籍管理系统数据库设计:从E-R图到触发器落地

简介:面向教育信息化课程设计与数据库课程实践的学籍管理系统文档,适合计算机专业学生、课程设计开发者及需要梳理学生信息管理流程的读者参考。内容围绕学生成绩与学籍数据管理展开,覆盖需求分析、开发计划、概念结构设计、逻辑结构设计与物…

2026/10/31 11:24:06

5G网络自动化扩容减容工具设计与实践

1. 项目背景与痛点分析 在5G网络优化工作中,扩容/减容操作是日常运维中最频繁也最耗时的任务之一。传统的人工操作方式需要经历以下典型流程: 登录网管系统查看当前小区负载 导出KPI指标进行Excel分析 编写变更申请单走审批流程 登录设备执行命令行操…

2026/10/31 11:24:06

Linux进程控制:fork、wait与waitpid详解

1. Linux进程控制基础概念 在Linux系统中,进程控制是系统编程的核心技能之一。作为一位长期使用Linux进行开发的工程师,我经常需要处理进程创建、管理和通信等问题。今天我们就来深入探讨Linux进程控制中最基础也最重要的几个系统调用:fork()…

2026/10/31 11:19:06

数据库系统课程设计资源包:建库脚本、源码与文档完整交付

简介:这份资源是山东科技大学数据库系统概论课程设计的完整实践包,面向正在学习数据库基础、需要完成课程设计或上机实验的高校学生。内容围绕数据表的创建与修改展开,涵盖字段定义、类型与长度设置、空值约束,以及通过 ALTER TAB…

2026/10/30 20:55:10

全国计算机二级C语言真题PDF高效刷题指南

简介:这份PDF是全国计算机二级C语言考试的试题与答案解析,专为备考二级C语言的考生准备。内容涵盖C语言特点与设计理念、程序基本组成单位、main函数执行流程、函数嵌套调用规则、标识符命名规范、整型实型字符型数据类型、八进制十六进制数合法形式、运…

2026/10/30 20:55:10

requests+BeautifulSoup:爬虫抓取h1标题的入门实战指南

简介:一份以实战为导向的Python爬虫入门资源,面向具备基本编程基础、希望快速掌握网络数据抓取的初学者,可解决从零编写简单爬虫的常见困惑。实例以requests库发送HTTP请求、BeautifulSoup解析HTML文档,完整演示从网页中提取 标题…

2026/10/30 20:55:09

递推最小二乘参数辨识MATLAB编程:二阶系统与渐消记忆实现

简介:这是一篇面向控制系统、信号处理与机器学习等领域学习者的最小二乘参数辨识程序说明文档。资源共包含一个docx格式文档,压缩包大小七十八KB,内容围绕递推最小二乘算法和渐消记忆最小二乘算法展开:先构造一个极点位于单位圆内…

2026/10/31 0:02:41

猫狗目标检测数据集:VOC/COCO/YOLO三格式一体化实战包

简介:本资源是一套面向计算机视觉初学者与YOLO目标检测实践者的猫狗图像数据集及配套开发工具包,专为快速上手目标检测模型训练而设计。资源包含1000张真实场景高清猫狗图片,标注质量高,同时提供VOC(XML)、…

2026/10/31 0:02:41

HDU2017多校标程复现:算法竞赛工程化真题沙盒

简介:本资源为2017年HDU多校联合训练第一场官方配套资料,面向ACM程序设计竞赛备赛学生、算法爱好者及高校编程集训队成员,旨在提供权威解题参考与完整测试验证环境。压缩包共40个文件,含15份C标程(覆盖全部赛题&#x…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑