Metadata-Version: 2.4
Name: webmuxd
Version: 0.4.2
Summary: tmux + ttyd for a browser: a persistent Chromium you can watch and drive
Author-email: Twwy <twwy.zh@gmail.com>
License:                                  Apache License
                                   Version 2.0, January 2004
                                http://www.apache.org/licenses/
        
           TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
        
           1. Definitions.
        
              "License" shall mean the terms and conditions for use, reproduction,
              and distribution as defined by Sections 1 through 9 of this document.
        
              "Licensor" shall mean the copyright owner or entity authorized by
              the copyright owner that is granting the License.
        
              "Legal Entity" shall mean the union of the acting entity and all
              other entities that control, are controlled by, or are under common
              control with that entity. For the purposes of this definition,
              "control" means (i) the power, direct or indirect, to cause the
              direction or management of such entity, whether by contract or
              otherwise, or (ii) ownership of fifty percent (50%) or more of the
              outstanding shares, or (iii) beneficial ownership of such entity.
        
              "You" (or "Your") shall mean an individual or Legal Entity
              exercising permissions granted by this License.
        
              "Source" form shall mean the preferred form for making modifications,
              including but not limited to software source code, documentation
              source, and configuration files.
        
              "Object" form shall mean any form resulting from mechanical
              transformation or translation of a Source form, including but
              not limited to compiled object code, generated documentation,
              and conversions to other media types.
        
              "Work" shall mean the work of authorship, whether in Source or
              Object form, made available under the License, as indicated by a
              copyright notice that is included in or attached to the work
              (an example is provided in the Appendix below).
        
              "Derivative Works" shall mean any work, whether in Source or Object
              form, that is based on (or derived from) the Work and for which the
              editorial revisions, annotations, elaborations, or other modifications
              represent, as a whole, an original work of authorship. For the purposes
              of this License, Derivative Works shall not include works that remain
              separable from, or merely link (or bind by name) to the interfaces of,
              the Work and Derivative Works thereof.
        
              "Contribution" shall mean any work of authorship, including
              the original version of the Work and any modifications or additions
              to that Work or Derivative Works thereof, that is intentionally
              submitted to Licensor for inclusion in the Work by the copyright owner
              or by an individual or Legal Entity authorized to submit on behalf of
              the copyright owner. For the purposes of this definition, "submitted"
              means any form of electronic, verbal, or written communication sent
              to the Licensor or its representatives, including but not limited to
              communication on electronic mailing lists, source code control systems,
              and issue tracking systems that are managed by, or on behalf of, the
              Licensor for the purpose of discussing and improving the Work, but
              excluding communication that is conspicuously marked or otherwise
              designated in writing by the copyright owner as "Not a Contribution."
        
              "Contributor" shall mean Licensor and any individual or Legal Entity
              on behalf of whom a Contribution has been received by Licensor and
              subsequently incorporated within the Work.
        
           2. Grant of Copyright License. Subject to the terms and conditions of
              this License, each Contributor hereby grants to You a perpetual,
              worldwide, non-exclusive, no-charge, royalty-free, irrevocable
              copyright license to reproduce, prepare Derivative Works of,
              publicly display, publicly perform, sublicense, and distribute the
              Work and such Derivative Works in Source or Object form.
        
           3. Grant of Patent License. Subject to the terms and conditions of
              this License, each Contributor hereby grants to You a perpetual,
              worldwide, non-exclusive, no-charge, royalty-free, irrevocable
              (except as stated in this section) patent license to make, have made,
              use, offer to sell, sell, import, and otherwise transfer the Work,
              where such license applies only to those patent claims licensable
              by such Contributor that are necessarily infringed by their
              Contribution(s) alone or by combination of their Contribution(s)
              with the Work to which such Contribution(s) was submitted. If You
              institute patent litigation against any entity (including a
              cross-claim or counterclaim in a lawsuit) alleging that the Work
              or a Contribution incorporated within the Work constitutes direct
              or contributory patent infringement, then any patent licenses
              granted to You under this License for that Work shall terminate
              as of the date such litigation is filed.
        
           4. Redistribution. You may reproduce and distribute copies of the
              Work or Derivative Works thereof in any medium, with or without
              modifications, and in Source or Object form, provided that You
              meet the following conditions:
        
              (a) You must give any other recipients of the Work or
                  Derivative Works a copy of this License; and
        
              (b) You must cause any modified files to carry prominent notices
                  stating that You changed the files; and
        
              (c) You must retain, in the Source form of any Derivative Works
                  that You distribute, all copyright, patent, trademark, and
                  attribution notices from the Source form of the Work,
                  excluding those notices that do not pertain to any part of
                  the Derivative Works; and
        
              (d) If the Work includes a "NOTICE" text file as part of its
                  distribution, then any Derivative Works that You distribute must
                  include a readable copy of the attribution notices contained
                  within such NOTICE file, excluding those notices that do not
                  pertain to any part of the Derivative Works, in at least one
                  of the following places: within a NOTICE text file distributed
                  as part of the Derivative Works; within the Source form or
                  documentation, if provided along with the Derivative Works; or,
                  within a display generated by the Derivative Works, if and
                  wherever such third-party notices normally appear. The contents
                  of the NOTICE file are for informational purposes only and
                  do not modify the License. You may add Your own attribution
                  notices within Derivative Works that You distribute, alongside
                  or as an addendum to the NOTICE text from the Work, provided
                  that such additional attribution notices cannot be construed
                  as modifying the License.
        
              You may add Your own copyright statement to Your modifications and
              may provide additional or different license terms and conditions
              for use, reproduction, or distribution of Your modifications, or
              for any such Derivative Works as a whole, provided Your use,
              reproduction, and distribution of the Work otherwise complies with
              the conditions stated in this License.
        
           5. Submission of Contributions. Unless You explicitly state otherwise,
              any Contribution intentionally submitted for inclusion in the Work
              by You to the Licensor shall be under the terms and conditions of
              this License, without any additional terms or conditions.
              Notwithstanding the above, nothing herein shall supersede or modify
              the terms of any separate license agreement you may have executed
              with Licensor regarding such Contributions.
        
           6. Trademarks. This License does not grant permission to use the trade
              names, trademarks, service marks, or product names of the Licensor,
              except as required for reasonable and customary use in describing the
              origin of the Work and reproducing the content of the NOTICE file.
        
           7. Disclaimer of Warranty. Unless required by applicable law or
              agreed to in writing, Licensor provides the Work (and each
              Contributor provides its Contributions) on an "AS IS" BASIS,
              WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
              implied, including, without limitation, any warranties or conditions
              of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
              PARTICULAR PURPOSE. You are solely responsible for determining the
              appropriateness of using or redistributing the Work and assume any
              risks associated with Your exercise of permissions under this License.
        
           8. Limitation of Liability. In no event and under no legal theory,
              whether in tort (including negligence), contract, or otherwise,
              unless required by applicable law (such as deliberate and grossly
              negligent acts) or agreed to in writing, shall any Contributor be
              liable to You for damages, including any direct, indirect, special,
              incidental, or consequential damages of any character arising as a
              result of this License or out of the use or inability to use the
              Work (including but not limited to damages for loss of goodwill,
              work stoppage, computer failure or malfunction, or any and all
              other commercial damages or losses), even if such Contributor
              has been advised of the possibility of such damages.
        
           9. Accepting Warranty or Additional Liability. While redistributing
              the Work or Derivative Works thereof, You may choose to offer,
              and charge a fee for, acceptance of support, warranty, indemnity,
              or other liability obligations and/or rights consistent with this
              License. However, in accepting such obligations, You may act only
              on Your own behalf and on Your sole responsibility, not on behalf
              of any other Contributor, and only if You agree to indemnify,
              defend, and hold each Contributor harmless for any liability
              incurred by, or claims asserted against, such Contributor by reason
              of your accepting any such warranty or additional liability.
        
           END OF TERMS AND CONDITIONS
        
           APPENDIX: How to apply the Apache License to your work.
        
              To apply the Apache License to your work, attach the following
              boilerplate notice, with the fields enclosed by brackets "[]"
              replaced with your own identifying information. (Don't include
              the brackets!)  The text should be enclosed in the appropriate
              comment syntax for the file format. We also recommend that a
              file or class name and description of purpose be included on the
              same "printed page" as the copyright notice for easier
              identification within third-party archives.
        
           Copyright [yyyy] [name of copyright owner]
        
           Licensed under the Apache License, Version 2.0 (the "License");
           you may not use this file except in compliance with the License.
           You may obtain a copy of the License at
        
               http://www.apache.org/licenses/LICENSE-2.0
        
           Unless required by applicable law or agreed to in writing, software
           distributed under the License is distributed on an "AS IS" BASIS,
           WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
           See the License for the specific language governing permissions and
           limitations under the License.
        
Project-URL: Homepage, https://github.com/memory-co/webmuxd
Project-URL: Source, https://github.com/memory-co/webmuxd
Keywords: browser,automation,chromium,cdp,vnc,agent,kasm
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Software Development :: Testing
Classifier: Topic :: Internet :: WWW/HTTP :: Browsers
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: websockets>=12.0
Requires-Dist: aiohttp>=3.9
Provides-Extra: dev
Requires-Dist: pytest>=8.0; extra == "dev"
Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
Dynamic: license-file

# webmuxd

[![PyPI](https://img.shields.io/pypi/v/webmuxd)](https://pypi.org/project/webmuxd/)
[![Python](https://img.shields.io/pypi/pyversions/webmuxd)](https://pypi.org/project/webmuxd/)
[![License](https://img.shields.io/badge/license-Apache--2.0-blue)](LICENSE)

**Chromium 做成一个 Python 库:活得比连接久、程序能驱动、人能用浏览器打开的浏览器。**

**简体中文** · [更新日志](CHANGELOG.md) · [GitHub](https://github.com/memory-co/webmuxd) · [CNB](https://cnb.cool/agentuse/webmuxd)(国内)

**webmuxd 是一个 `*muxd` 组件** —— 一扇 HTTP 上的窗给人,一个 Python 把手给程序。
这一族的规范定在 [shellbase](https://github.com/memory-co/shellbase):
[new-interface](https://github.com/memory-co/shellbase/blob/main/docs/v1/new-interface.md)(为什么是这个形状) ·
[muxd-spec](https://github.com/memory-co/shellbase/blob/main/docs/v1/muxd-spec.md)(算不算一个组件) ·
姊妹项目 [tmuxd](https://github.com/memory-co/tmuxd)(终端那一块)

---

无头浏览器能被程序驱动,但**人看不见**;远程桌面里的浏览器人能看见,
但**程序碰不到**。于是排查一次登录失败要来回切:脚本跑一遍、截图存下来、
自己打开看、改一行再跑一遍。

webmuxd 让这两件事落在**同一个浏览器**上:

```python
from webmuxd import Webmuxd

web  = Webmuxd(user="claudecode")                            # 空壳,不起任何东西
sess = web.session(id="work", port=7900, view_port=8090)      # 这行才起一个浏览器
tab  = sess.open("https://example.com")

tab.type("手机号", "13800000000")
tab.click("提交订单")                                         # 按人看得见的字,不写选择器

print(sess.view_url, sess.view_login, sess.view_password)        # 人从这儿进去看
```

那个地址发给谁,谁的浏览器里就是**这个浏览器** —— 看得见,也能直接伸手接管。
程序点了什么人立刻看见,人改了什么程序下一次读到的就是改完的。
**不是两份状态,是一份。**

## 快速开始

要 `docker`,别的都不用 —— Chromium 在镜像里。

```bash
pip install webmuxd
webmuxd install          # 只做两件事:确认 docker 能用、镜像拉不拉得到
```

`install` 把探到的镜像记进 `~/.webmuxd.json` 的 `default_container`,
**所以下面的例子都不用写镜像**。要用别的镜像就显式指定 —— 见[镜像](#镜像)。

### 当库用

```python
from webmuxd import Webmuxd

web = Webmuxd()
sess = web.session(id="work", port=7900, view_port=8090)   # 镜像用记录里的默认
tab = sess.open("https://news.ycombinator.com")

print(tab.observe().as_prompt())      # 元素表,直接喂多模态模型
tab.click("new")
```

`session(id=...)` 是幂等的 —— 同一个 id 再调一次拿到同一个,不会起第二个浏览器。
**端口必须你给**:端口是部署决定的,替你猜一个只会让配置和实际对不上。

### 用命令行

```bash
webmuxd new --id work --api-port 7900 --view-port 8090     # 镜像用记录里的默认
webmuxd new-tab  -t work -u https://example.com
webmuxd click    -t work "Learn more"
webmuxd observe  -t work                  # 喂给模型的元素表
webmuxd log      -t work                  # 它都干了什么
webmuxd kill     -t work
```

**跑起来之后,用浏览器打开 `webmuxd new` 打印的那个画面地址** —— 然后在另一边敲
`webmuxd click`,页面会在你眼前跳过去。整条链路通没通,这一眼就看出来了。

完整走一遍见 [QUICKSTART.md](QUICKSTART.md)。

## 它和别的东西不一样在哪

- **按人看得见的字操作。** `click("提交订单")`,不写选择器。分档匹配(精确 → 子串 →
  忽略大小写),**有歧义就给候选,绝不替你挑一个** —— 挑错了你永远不会知道。
- **"看见"= 元素表 + 标注截图。** `observe()` 一次给全,直接喂多模态模型;
  拿不到的东西写进 `notes`,而不是假装看全了。
- **tab 表就是浏览器那张表。** 不是黑盒:`reason` 分得清是人点开的还是代码开的
  (靠 CDP 的 `openerId`);逃生舱是**你自己拿 DevTools 连上去**,看到的和它一样。
- **日志是 scrollback,不是事件流。** 每一步看到什么、做了什么、页面变成什么样,
  一个 JSONL 按条数切 —— 给人和模型回看的。
- **`act()` 不抛异常。** 写 agent 循环时要把候选喂回模型自我纠正,而不是被异常打断;
  快捷方法(`click` / `type`)则照抛。
- **关掉网页,浏览器照常在跑。** 门面短命,屋子长命。

## 两个端点,别的都不算

```
一个画面端口   ← 给人:浏览器打开就能看,能上手
一个 CDP 端点  ← 给代码:webmuxd 订阅它
```

产出这两样的东西就是一个 runtime,**是不是容器不在契约里**:

| | 起什么 | 用在哪 |
| --- | --- | --- |
| `container`(默认) | 一个现成的浏览器镜像 | 生产。有隔离,画面是完整桌面 |
| `process` | 本机 chromium + Xvnc | 开发、CI。秒起,但没有隔离 |
| `remote` | 什么都不起,两个端点你给 | 云浏览器、别人机器上那个 |

这条线以上的代码**没有任何一处 `if runtime ==`** —— 为什么能做到,见
[works/08](docs/v1/works/08-browser-runtime.md)。

## 镜像

两个现成的,`webmuxd install` 会把默认那个准备好:

| | 挑它的理由 | 代价 |
| --- | --- | --- |
| `kasmweb-chromium`(默认) | **画面最好** | `--network host` 下一台机器只能跑一个 |
| `jlesage-chromium` | **能一机多开** | 画面差一点 |

```bash
docker pull ghcr.io/memory-co/webmuxd/kasmweb-chromium:1.18.0         # 海外
docker pull docker.cnb.cool/agentuse/webmuxd/kasmweb-chromium:1.18.0  # 国内
```

它们是在 kasm / jlesage 原厂镜像上**加一层**:补上 CDP 端点(Chromium 把调试口
绑死在容器内的 loopback,`docker -p` 够不着),并把端口变量名统一成
`WEBMUXD_VIEW_PORT` / `WEBMUXD_CDP_PORT`。

### 镜像填在哪

**默认那个不用填** —— `webmuxd install` 已经把它记进 `~/.webmuxd.json` 了。
要换成别的,两条路都接同一个参数:

```python
sess = web.session(id="work", port=7900, view_port=8090,
                   image="docker.cnb.cool/agentuse/webmuxd/jlesage-chromium:v26.08.1")
```

```bash
webmuxd new --id work --api-port 7900 --view-port 8090 \
  --image docker.cnb.cool/agentuse/webmuxd/jlesage-chromium:v26.08.1
```

**换镜像不用改 webmuxd 的代码** —— 它读镜像的 `webmuxd.*` 标签认它,不认名字。
所以你自己 build 的镜像只要打上标签,`--image` 指过去就能用;
没有标签就直接报错,不猜。怎么加一个新镜像,见 [docker/](docker/README.md)。

## 依赖

| | | |
| --- | --- | --- |
| **Docker** | 任意近版 | `container` runtime 要它 |
| **Python** | ≥ 3.10 | |
| **系统** | Linux | 容器共享 network namespace,这是 Linux 的东西 |

`process` runtime 另外要本机有 `chromium`(以及 `Xvnc` —— 没有就只有 API 没有画面,
**这件事它会明说**,而不是给你一个连不上的地址)。

镜像里是 **Chromium 不是 Chrome**:Chrome 是专有软件、再分发受限。代价是不带
H.264 / AAC,少数只有这两种编码的视频放不了。

## 开发

```bash
docker build -t webmuxd-dev docker/dev/
docker run --rm -v "$PWD":/src webmuxd-dev pytest -q
```

测试跑的是**真的 Chromium**,不 mock —— 这个项目的全部价值就在它和浏览器的交界处,
换成假的等于什么都没测。用例[按场景组织](tests/README.md),不按代码模块:
`pointing_at_things/` 是"按字找东西",`chrome_facts/` 是"我们对 CDP 的假设逐条量过"
(换 Chromium 大版本先跑它)。

两个镜像各有一个场景,真的 `docker run`,要在宿主机上跑:

```bash
pytest tests/image_kasmweb tests/image_jlesage
```

## 文档

| | |
| --- | --- |
| [QUICKSTART.md](QUICKSTART.md) | 完整跑一遍 |
| [`docs/v1/sdk`](docs/v1/sdk/) | Python 包 —— **主体**,行为定义在这儿 |
| [`docs/v1/api`](docs/v1/api/) | HTTP + WS 的线上格式 —— sdk 的导出面 |
| [`docs/v1/cli`](docs/v1/cli/) | `webmuxd` 命令,照着 tmux 设计 |
| [`docs/v1/works`](docs/v1/works/) | **为什么这么做** —— 设计稿和实测记录 |
| [docker/](docker/README.md) | 镜像怎么用、怎么加一个新的 |

## 许可

Apache-2.0,见 [LICENSE](LICENSE)。

webmuxd 把 [Chromium](https://www.chromium.org/)(BSD)当外部程序驱动,
画面那一半用 [kasmweb](https://hub.docker.com/r/kasmweb/chromium) 和
[jlesage](https://hub.docker.com/r/jlesage/chromium) 的镜像 ——
**不改动、不重新发行它们的源码**,只在上面加一薄层。
