拆解dots源码一个入口如何精确pin住invisible-playwright-mcp命令组与.env的工程细节【免费下载链接】dotsOpen-source dots for the web: an AI agent with its own browser, one that does not get blocked.项目地址: https://gitcode.com/gh_mirrors/dots140/dotsdots 是一个自带浏览器的开源 AI agent浏览器Agent浏览器引擎在 C 层打过补丁页面上找不到任何自动化痕迹因此很难被网站拦截。更特别的是它的全部产品逻辑只有 20 行不到的入口代码核心工作是把invisible-playwright-mcp精确 pin 在0.70.2。本文拆解 src/dots/cli.py 的每一行回答两个问题为什么是精确版本锁定exact pin而不是以及为什么必须走命令组而不能直接调ui命令。项目全貌一个20行入口的浏览器Agent 整个仓库只有一个极小的包每个文件各司其职文件作用src/dots/init.py一句话定位dots 是 invisible-playwright-mcp 的界面只是用了人们会搜的那个名字src/dots/main.py支持python -m dots启动仅 2 行src/dots/cli.py唯一的真入口main()函数体只有 4 行tests/test_entry.py4 个测试是pin 升级的验收关卡pyproject.toml版本 pin、命令注册、pre-push 检查配置安装后dots是一条指向main()的可执行命令注册在 pyproject.toml[project.scripts] dots dots.cli:main精确pin依赖为什么写0.70.2而不是0.70.2pyproject.toml 的依赖行上有一段毫不留情的注释⛔ THE WHOLE PRODUCT IS THIS LINE.dots是 invisible-playwright-mcp 换了名字的界面。关键在于cli.py用的不是invisible-playwright-mcp的公开 API而是直接调用了它的命令组command group——那并不是一个发布出来的稳定接口。由此推出两条工程结论若写0.70.2上游某天发布 0.70.3 并改了命令组形态所有新装环境会静默拉到新版dots直接崩写0.70.2精确 pin 后解析器永远不会替你捡新版本。升级 pin 是一次有意识的人工动作改版本号 → 跑 tests/test_entry.py → 全绿再合入。一句话总结精确 pin 买的是升级时机由我决定的契约权。命令组 vs ui命令.env 到底在哪里被读取 cli.py 的main()函数体只有 4 行SUBCOMMAND ui def main(argvNone): from invisible_playwright_mcp.cli import main as group args list(sys.argv[1:] if argv is None else argv) group(args[SUBCOMMAND, *args], prog_namedots)里面藏着两个容易踩坑的细节参数头部强制插一个ui。dots 本质上就是invisible-playwright-mcp ui别无其他后面的所有选项都属于界面本身所以dots --help列出的选项与ui --help完全一致。调的是命令组不是命令。模块 docstring 说得很直白.env文件的读取、以及旧 session 目录的迁移都发生在命令组这一层。如果绕过组直接调ui这两步全被跳过——写在.env里的 OpenRouter key 会悄悄找不到程序看起来没配置。prog_namedots同样讲究帮助信息的用法行显示Usage: dots而不是内部包名对外品牌与内部实现解耦。四道测试关卡升级pin时的验收清单 ✅tests/test_entry.py 的 4 个测试就是命令组哪天变了形状必有一个变红的判据测试级别守护什么group 被带着 ui 调用unitmock 掉命令组断言参数恰为[ui, --port, 9000, --headed]且prog_name是dots。若有人把 dots 改成直调ui其余测试仍会全绿唯独这个能抓住.env永远读不到的隐患help 就是界面的 helpintegration真实子进程跑python -m dots --help断言Usage: dots与--openrouter-key、--model、--proxy、--seed、--profile-dir五个核心选项都在没有 key 就拒跑integration环境中抹掉 API key 后启动断言非零退出且提示 OpenRouter——在启动任何浏览器、子进程之前就失败安装的包就是被 pin 的那个unit从pyproject.toml读出 pin 版本号与已安装包版本逐一比对防止隔壁仓库的 editable 安装让前面所有测试在考错的代码最后一个测试最值得细看它规定了测试判卷的依据是pyproject.toml里的版本号而不是你手头任何 checkout——这正是pin 升级流程里改 pin 前先确认装的确实是被 pin 版本的自动化保证。快速上手一行命令启动 dots git clone https://gitcode.com/gh_mirrors/dots140/dots cd dots pip install . dots --openrouter-key sk-or-...随后打开http://127.0.0.1:8765左边是对话右边是浏览器实时联动。模型用--model一个开关即可切换OpenRouter 上任意模型全部选项以dots --help为准。小结小项目的三个工程姿势精确 pin 胜过地板版本调用的是别人未承诺稳定的接口版本就是契约契约必须写死走命令组、别走命令配置.env读取逻辑住在组里绕过组等于绕过配置测试考的是 pin不只是代码四个测试构成依赖升级的验收线其中已装版本 被 pin 版本一道堵死了环境漂移的后门。更多浏览器指纹细节--seed复现同一身份、--profile-dir跨次保留登录态、--proxy让时区与语言跟随出口以及把同一个浏览器作为 MCP server 接入 Claude Code、Codex、Gemini CLI 的用法见 README.md。【免费下载链接】dotsOpen-source dots for the web: an AI agent with its own browser, one that does not get blocked.项目地址: https://gitcode.com/gh_mirrors/dots140/dots创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考