Skip to content
45 changes: 42 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,50 @@ see the [mygo README](mygo/README.md); with nothing but Docker,
without changing anything on your machine.

On Windows 11, download the `vfox-plus-windows` artifact instead, extract it
and run the one-command script in PowerShell (it self-signs with a local
certificate and installs; see [Windows packaging](shared/packaging/windows/README.md)):
and install the unsigned `.msixbundle` in an elevated PowerShell
(see [Windows packaging](shared/packaging/windows/README.md)):

```powershell
powershell -ExecutionPolicy Bypass -File Sign-Msix.ps1
Add-AppxPackage -Path .\vfox-plus_<version>.msixbundle -AllowUnsigned
```

The bundle is not signed yet; an officially signed bundle will be provided
later.

### Use it in a browser

`vfox-plus pair` connects a browser to the vfox-plus on this machine, in the
style of `opencode pair`. It works the same in bash on Ubuntu and in
PowerShell on Windows:

```sh
vfox-plus pair
```

Open the link it prints. Links work once and expire after a few minutes. The
paired browser gets the full web interface at `/app`: installed SDKs with
install/use/uninstall, the plugin registry with add/update/remove, tasks
with live progress and logs, and the settings.

To connect a browser on another machine, or to run vfox-plus in a container,
keep the pairing server up instead:

```sh
vfox-plus serve --port 8080
```

and open the link it prints, with its address replaced by the reachable one.
A paired browser mints links for more browsers with `GET /api/token`.
Non-loopback servers speak HTTPS: without `--tls-cert/--tls-key` a
self-signed certificate is generated next to the settings on first start,
and its fingerprint is printed for comparison in the browser. Bring your
own certificate to avoid the warning. The
published Docker image runs this server with no display needed; see
[Packaging](mygo/README.md#docker-image):

```sh
docker build -f mygo/Dockerfile -t vfox-plus .
docker run --rm -p 8080:8080 vfox-plus
```

## Repository layout
Expand Down
38 changes: 35 additions & 3 deletions README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,44 @@ vfox-plus
`vfxtool sandbox package` 会把两个文件构建到 `dist/sandbox/`,
不改变本机任何东西。

Windows 11 用户请下载 `vfox-plus-windows` 构件,解压后在 PowerShell 跑一键脚本
(本地自签名证书并安装,见
Windows 11 用户请下载 `vfox-plus-windows` 构件,解压后在管理员 PowerShell
安装未签名 `.msixbundle`(见
[Windows 打包](shared/packaging/windows/README.zh-CN.md)):

```powershell
powershell -ExecutionPolicy Bypass -File Sign-Msix.ps1
Add-AppxPackage -Path .\vfox-plus_<版本>.msixbundle -AllowUnsigned
```

安装包目前尚未签名,日后会提供官方签名的安装包。

### 在浏览器中使用

`vfox-plus pair` 把浏览器与本机的 vfox-plus 配对,对标 `opencode pair`。
Ubuntu 的 bash 与 Windows 的 PowerShell 用法相同:

```sh
vfox-plus pair
```

在浏览器打开它输出的链接即可。链接一次性有效,几分钟后过期;配对后的浏览器
在 `/app` 得到完整 Web 界面:已安装 SDK 的安装/使用/卸载、插件仓库的添
加/更新/删除、带实时进度与日志的任务、以及设置。

另一台机器的浏览器,或容器中运行的 vfox-plus,用常驻服务代替:

```sh
vfox-plus serve --port 8080
```

打开它输出的链接,把地址换成可达地址即可。已配对的浏览器用 `GET /api/token`
为更多浏览器增发链接。非回环服务走 HTTPS:不传 `--tls-cert/--tls-key` 时首次
启动在设置目录旁生成自签名证书并打印指纹,请在浏览器核对;自备证书可消除
警告。发布 Docker 镜像直接跑该服务,无需显示;见
[打包](mygo/README.zh-CN.md#docker-镜像):

```sh
docker build -f mygo/Dockerfile -t vfox-plus .
docker run --rm -p 8080:8080 vfox-plus
```

## 仓库布局
Expand Down
13 changes: 13 additions & 0 deletions docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -194,3 +194,16 @@ possible. The process runner and the vfox client are the seams for that: a
remote implementation of the process runner (or of the client) can forward the
same commands to an agent on the machine, and the state and UI layers stay
unchanged. The CLI contract then becomes the protocol.

`vfox-plus pair` (package `mygo/pair`) is the first step: a pairing server
with one-time links, in the style of `opencode pair`. `vfox-plus serve` keeps
that server up for containers and remote instances, with expiring sessions
and mintable links, and the published Docker image ([`mygo/Dockerfile`](../mygo/Dockerfile))
runs it with no display needed. Non-loopback servers speak HTTPS: without
`--tls-cert/--tls-key` a self-signed certificate is generated next to the
settings on first start, its fingerprint is printed for comparison in the
browser, and the session cookie is Secure. A paired browser gets the full web interface
at `/app`: installed SDKs with install/use/uninstall, the plugin registry
with add/update/remove, tasks with live progress and logs over server-sent
events, and the settings. An Android client on the same protocol is still to
come.
8 changes: 8 additions & 0 deletions docs/zh-CN/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,3 +160,11 @@ Windows `.msix` 与 `.msixbundle` 无额外运行时依赖:Go 可执行文件

连接跑 vfox 机器的 Web UI 与 Android 客户端仍可能。进程运行器与 vfox 客户端是接缝:
远端实现转发同样命令到机器上的 agent,状态与 UI 层不变。CLI 契约届时成为协议。

`vfox-plus pair`(`mygo/pair` 包)是第一步:配对服务,一次性链接,对标
`opencode pair`。`vfox-plus serve` 为容器与远端实例常驻该服务,会话可过期、
链接可增发;发布 Docker 镜像([`mygo/Dockerfile`](../mygo/Dockerfile))无需显示
直接跑它。非回环服务走 HTTPS:不传 `--tls-cert/--tls-key` 时首次启动在设置目录
旁生成自签名证书,在浏览器核对打印的指纹,会话 cookie 为 Secure。配对后的浏览器在 `/app` 得到完整 Web 界面:已安装 SDK 的安
装/使用/卸载、插件仓库的添加/更新/删除、带实时进度与日志的任务、以及设置。
同协议的 Android 客户端仍待后续。
109 changes: 109 additions & 0 deletions mygo/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
# syntax=docker/dockerfile:1
# Copyright 2026 Han Li and contributors
#
# 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.

# The published vfox-plus image: a minimal Ubuntu runtime with vfox and a
# `vfox-plus serve` that browsers pair with. It needs no display server: the
# pairing server is plain Go without a UI toolkit.
#
# Build from the repository root (the build reads mygo/ and shared/):
#
# docker build -f mygo/Dockerfile -t vfox-plus .
#
# Run it with the port mapped, then open the pairing link it prints, with
# 0.0.0.0 replaced by the reachable address. The link is https: a
# self-signed certificate is generated in the container on first start,
# and its fingerprint is printed for comparison in the browser.
#
# docker run --rm -p 8080:8080 vfox-plus
#
# A browser on another machine pairs the same way, over the network the
# container is reachable on. Prefer an encrypted tunnel outside trusted
# networks. A data volume keeps the installed SDKs between runs:
#
# docker run --rm -p 8080:8080 -v vfox-plus-data:/home/vfoxplus vfox-plus
#
# The toolchain versions default to mygo/versions.env; keep them in sync.
# Only linux/amd64 is built here: vfox publishes per-architecture archives,
# and the URL below names the x86_64 one.

ARG GO_VERSION=1.27.3
ARG GO_SHA256=65efbc80fdc1fa2cd2631cad5b481777a68e8725f34e89f50fc6ac714e379b40
ARG VFOX_VERSION=1.0.13
ARG VFOX_SHA256=7ad0a4c82c8173f09393e09abecc3e27468253bab5fe53ffbf58f2b12b3fc768

FROM ubuntu:26.04 AS build
ARG GO_VERSION
ARG GO_SHA256
ARG VFOX_VERSION
ARG VFOX_SHA256

# Go, verified against the published checksum.
RUN <<EOF
set -eu
apt-get update
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends ca-certificates curl
rm -rf /var/lib/apt/lists/*
curl -fsSL --retry 5 -o /tmp/go.tar.gz "https://go.dev/dl/go$GO_VERSION.linux-amd64.tar.gz"
echo "$GO_SHA256 /tmp/go.tar.gz" | sha256sum --check --strict -
tar -xzf /tmp/go.tar.gz -C /opt
rm /tmp/go.tar.gz
EOF
ENV PATH=/opt/go/bin:$PATH \
GOTOOLCHAIN=local \
CGO_ENABLED=0

# vfox, verified against the checksum published with the release.
RUN <<EOF
set -eu
mkdir -p /out
curl -fsSL --retry 5 -o /tmp/vfox.tar.gz \
"https://github.com/version-fox/vfox/releases/download/v$VFOX_VERSION/vfox_${VFOX_VERSION}_linux_x86_64.tar.gz"
echo "$VFOX_SHA256 /tmp/vfox.tar.gz" | sha256sum --check --strict -
tar -xzf /tmp/vfox.tar.gz -C /tmp
install -m 755 "/tmp/vfox_${VFOX_VERSION}_linux_x86_64/vfox" /out/vfox
rm -rf /tmp/vfox*
EOF

WORKDIR /src
COPY mygo/go.mod mygo/go.sum /src/mygo/
COPY shared/tooling/go.mod shared/tooling/go.sum /src/shared/tooling/
RUN cd /src/mygo && go mod download
RUN cd /src/shared/tooling && go mod download
COPY mygo /src/mygo
COPY shared /src/shared
RUN go -C /src/shared/tooling build -o /tmp/vfxtool ./cmd/vfxtool \
&& /tmp/vfxtool prepare --root /src/mygo \
&& /tmp/vfxtool build --root /src/mygo /out/vfox-plus \
&& /out/vfox-plus serve --help

FROM ubuntu:26.04
RUN <<EOF
set -eu
apt-get update
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends ca-certificates
rm -rf /var/lib/apt/lists/*
useradd --create-home --shell /bin/bash vfoxplus
EOF
COPY --from=build /out/vfox /usr/local/bin/vfox
COPY --from=build /out/vfox-plus /usr/local/bin/vfox-plus

USER vfoxplus
WORKDIR /home/vfoxplus
ENV HOME=/home/vfoxplus
VOLUME /home/vfoxplus/.vfox
VOLUME /home/vfoxplus/.version-fox
EXPOSE 8080
ENTRYPOINT ["/usr/local/bin/vfox-plus"]
CMD ["serve", "--bind", "0.0.0.0", "--port", "8080"]
30 changes: 25 additions & 5 deletions mygo/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ project, in Go:
| [`ui/mcu/`](ui/mcu) | The colour scheme: a Go port of the Material colour utilities (HCT, CAM16, tonal spot) |
| [`ui/shapes/`](ui/shapes) | The shapes: a Go port of the rounded polygons and their morphs of `androidx.graphics.shapes` |
| [`assets/`](assets) | What the binary embeds: the icon fonts, the translations and the licenses (all generated at build time) |
| [`main.go`](main.go) | Assembles the model and the window |
| [`pair/`](pair) | `vfox-plus pair` / `vfox-plus serve`: pair a browser with this machine (one-time links) or keep the server up for containers and remote instances; the paired browser gets the full web interface (`/app`: SDKs, registry, tasks with live logs, settings) |
| [`main.go`](main.go) | Assembles the model and the window; dispatches the `pair` subcommand |

The layers follow [the architecture](../docs/architecture.md): `core` knows
nothing of the others, `state` only knows `core`, and `ui` sits on top. `core`,
Expand Down Expand Up @@ -230,13 +231,32 @@ On Windows 11, `vfxtool build-msix` packages cross-compiled executables
(`vfxtool build --goos windows --goarch amd64|arm64`) as unsigned
`vfox-plus_<version>_<arch>.msix` and a `vfox-plus_<version>.msixbundle`,
with the manifest, logos and bundle layout of
[`shared/packaging/windows`](../shared/packaging/windows). Users install with the
one-command [`Sign-Msix.ps1`](../shared/packaging/windows/Sign-Msix.ps1) script
(self-signed certificate, no third party needed); to distribute widely, sign it
with a trusted certificate. CI cross-compiles and packages on Linux, validates with
[`shared/packaging/windows`](../shared/packaging/windows). Users install the
unsigned bundle in an elevated PowerShell with
`Add-AppxPackage -AllowUnsigned`; the bundle is not signed yet and an
officially signed bundle will be provided later. CI cross-compiles and
packages on Linux, validates with
`vfxtool validate-msix`, and installs/uninstalls the bundle on Windows
Server 2025 (x64) and Windows 11 on ARM (arm64).

### Docker image

[`Dockerfile`](Dockerfile) builds the published image from the repository
root: a minimal Ubuntu runtime with vfox and `vfox-plus serve`, needing no
display server. The toolchain versions default to [`versions.env`](versions.env).

```sh
docker build -f mygo/Dockerfile -t vfox-plus .
docker run --rm -p 8080:8080 vfox-plus
```

Open the pairing link it prints, with `0.0.0.0` replaced by the reachable
address. The link is `https`: the container generates a self-signed
certificate on first start and prints its fingerprint for comparison in
the browser. A `-v vfox-plus-data:/home/vfoxplus` volume keeps the installed
SDKs between runs. A browser on another machine pairs the same way, over
the network the container is reachable on.

## Memory

Measured with `vfxtool sandbox measure`: Ubuntu 26.04 in Docker, Xvfb, a
Expand Down
22 changes: 19 additions & 3 deletions mygo/README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ Material 3 Expressive 观感的部件;其元素与无样式部件之上全部
| [`ui/mcu/`](ui/mcu) | 配色:Material 颜色工具的 Go 移植(HCT、CAM16、tonal spot) |
| [`ui/shapes/`](ui/shapes) | 形状:`androidx.graphics.shapes` 圆角多边形及其形变的 Go 移植 |
| [`assets/`](assets) | 二进制嵌入物:图标字体、翻译与许可证(构建时生成) |
| [`main.go`](main.go) | 组装模型与窗口 |
| [`pair/`](pair) | `vfox-plus pair` / `vfox-plus serve`:浏览器配对到本机(一次性链接),或为容器与远端实例常驻服务;配对后的浏览器得到完整 Web 界面(`/app`:SDK、仓库、带实时日志的任务、设置) |
| [`main.go`](main.go) | 组装模型与窗口;分发 `pair` 子命令 |

分层见[架构](../docs/zh-CN/architecture.md):`core` 不知道其它层,`state` 只知道
`core`,`ui` 在上。`core`、`state`、`ui/mcu` 与 `ui/shapes` 是无 UI 工具包的纯 Go,
Expand Down Expand Up @@ -176,10 +177,25 @@ Windows 11 上,`vfxtool build-msix` 把交叉编译的可执行文件
`vfox-plus_<版本>_<架构>.msix` 与
`vfox-plus_<版本>.msixbundle`,含
[`shared/packaging/windows`](../shared/packaging/windows) 的清单、徽标与 bundle 布局。
用户用一键 [`Sign-Msix.ps1`](../shared/packaging/windows/Sign-Msix.ps1) 脚本安装
(自签名证书,无需第三方);广泛分发请用受信证书签名。
用户在管理员 PowerShell 用 `Add-AppxPackage -AllowUnsigned` 安装未签名 bundle;
安装包目前尚未签名,日后会提供官方签名的安装包。
CI 在 Linux 交叉编译打包并用 `vfxtool validate-msix` 校验,在 Windows Server 2025(x64)与 ARM 版 Windows 11(arm64)上校验并安装/卸载 bundle。

### Docker 镜像

[`Dockerfile`](Dockerfile) 从仓库根构建发布镜像:最小 Ubuntu 运行时,含 vfox 与
`vfox-plus serve`,无需显示服务。工具链版本默认取
[`versions.env`](versions.env)。

```sh
docker build -f mygo/Dockerfile -t vfox-plus .
docker run --rm -p 8080:8080 vfox-plus
```

打开它输出的配对链接,把 `0.0.0.0` 换成可达地址。链接是 `https`:容器首次启动
生成自签名证书并打印指纹,请在浏览器核对。`-v vfox-plus-data:/home/vfoxplus`
卷在多次运行之间保留已安装的 SDK。另一台机器的浏览器在容器可达的网络上同样配对。

## 内存

`vfxtool sandbox measure` 测量:Docker 内 Ubuntu 26.04,Xvfb,1280×800 窗口,单进程,
Expand Down
20 changes: 20 additions & 0 deletions mygo/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,37 @@
package main

import (
"fmt"
"log"
"os"
"strings"

"github.com/version-fox/vfox-plus/mygo/core"
"github.com/version-fox/vfox-plus/mygo/core/settings"
"github.com/version-fox/vfox-plus/mygo/pair"
"github.com/version-fox/vfox-plus/mygo/state"
"github.com/version-fox/vfox-plus/mygo/ui"
)

func main() {
// `vfox-plus pair` pairs a browser with this machine, `vfox-plus serve`
// keeps the pairing server up for containers and remote instances;
// anything else starts the desktop application.
if len(os.Args) > 1 {
switch os.Args[1] {
case "pair":
os.Exit(pair.Main(os.Args[2:]))
case "serve":
os.Exit(pair.ServeMain(os.Args[2:]))
case "help", "--help", "-h":
fmt.Println("Usage: vfox-plus [pair|serve]")
fmt.Println()
fmt.Println(" (no arguments) Start the desktop application.")
fmt.Println(" pair Pair a browser with this machine over loopback.")
fmt.Println(" serve Keep the pairing server up for containers and remote instances.")
return
}
}
environment := make(map[string]string)
for _, entry := range os.Environ() {
if key, value, ok := strings.Cut(entry, "="); ok {
Expand Down
Loading
Loading