Make web UI the primary interface - #73
Conversation
There was a problem hiding this comment.
Pull request overview
This PR makes a localhost Web UI the primary interface for codex-provider-sync, including a read-only chat history browser backed by new server endpoints, and updates packaging/docs so the built Web UI ships with the CLI.
Changes:
- Adds a React/Vite Web UI (Overview / History / Backups / Activity) and ships the built assets under
web/dist. - Introduces a Node HTTP server (
src/web-server.js) with token + origin checks and API endpoints for status/sync/switch/restore/prune/history. - Updates docs/README set (ZH/JA/KO/EN) to position the Web UI as primary, and updates npm packaging + publish script accordingly.
Reviewed changes
Copilot reviewed 23 out of 28 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| web/vite.config.js | Vite build/dev config for the Web UI. |
| web/src/styles.css | Web UI styling and responsive layout. |
| web/src/main.jsx | React entrypoint mounting <App />. |
| web/src/icons.jsx | Shared SVG icon components for the UI. |
| web/src/hooks.js | Adds usePersistentState for localStorage-backed UI state. |
| web/src/App.jsx | Implements the full Web UI (overview, history browser, backups, activity, modals). |
| web/src/api.js | Browser API client with per-process token header injection. |
| web/index.html | Dev HTML template with bootstrap placeholder. |
| web/dist/index.html | Built Web UI entry HTML (with hashed asset references). |
| web/dist/assets/index-9c6c7b2a.css | Built/minified CSS artifact. |
| test/web-server.test.js | Tests Web UI token injection + API authorization + endpoint delegation. |
| test/history.test.js | Tests safe history parsing/filtering and message limiting. |
| src/web-server.js | New localhost web server: static hosting + API endpoints + serialized operations. |
| src/history.js | New rollout JSONL history scanner + list/detail APIs for the server. |
| src/cli.js | Adds codex-provider web command to start the Web UI server. |
| src/backup.js | Adds listBackups() to support Web UI backup browsing. |
| scripts/publish-npm.js | Adds a publish helper that rebuilds Web UI, runs tests, and publishes. |
| README.md | Reorients top-level docs toward Web UI + adds Web UI usage guidance. |
| package.json | Ships web/dist, adds web build/start scripts and publish script; bumps version. |
| docs/WORKING_PRINCIPLE_ZH.md | Adds detailed working-principle documentation (ZH). |
| docs/README_ZH.md | New canonical Chinese README aligned with Web UI-first approach. |
| docs/README_WEB_UI_ZH.md | Adds a dedicated Web UI usage guide (ZH). |
| docs/README_KO.md | Adds Korean README aligned with Web UI-first approach. |
| docs/README_JA.md | Adds Japanese README aligned with Web UI-first approach. |
| docs/README_EN.md | Marks legacy EN doc as secondary; points to root README Web UI docs. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| const port = flags.port === undefined ? 8791 : parseKeepCount(flags.port, { allowZero: true }); | ||
| const handle = await startWebUi({ port, openBrowser: !flags["no-open"] }); |
| function pathsEqual(left, right) { | ||
| if (!left || !right) return false; | ||
| const normalize = (value) => value.replace(/[\\/]+$/, "").replaceAll("\\", "/").toLowerCase(); | ||
| return normalize(left) === normalize(right); | ||
| } |
| </label> | ||
| <label className="form-field form-field--short"> | ||
| <span>保留备份数</span> | ||
| <input type="number" min="1" max="100000" value={keepCount} onChange={(event) => setKeepCount(Number(event.target.value))} disabled={busy} /> |
| useEffect(() => { | ||
| window.localStorage.setItem(key, JSON.stringify(value)); | ||
| }, [key, value]); |
| if (request.method !== "GET" && request.method !== "HEAD") { | ||
| sendError(response, 405, "Method not allowed."); | ||
| return; | ||
| } |
There was a problem hiding this comment.
感谢提交 PR #73,也感谢你在 Web UI 和聊天记录功能上投入的工作。
本轮 Review 主要涉及 Web UI 的本地访问边界、Node 16 兼容性、History 请求行为和版本一致性。以下事项需要在合并前处理。认证方案需要同时满足两个目标:凭证不通过首页下发,使用者也不需要手工输入 Access Code。
Review 状态:REQUEST_CHANGES
1. Web UI 改为零输入自动配对
当前首页会把 API token 随页面返回给客户端。能访问该端口的本机客户端可以读取这个 token,并调用 sync、switch、restore 等写接口。
期望的使用流程:
- 运行
codex-provider web后,自动打开浏览器并完成配对,全程不需要输入或复制验证码。 - 刷新页面和重启服务后保持授权。
- 换浏览器或清除浏览器数据后,重新运行同一命令即可自动配对。
实现要求:
- 首页和静态资源不再包含 API token。
- 启动时生成高熵、短时、一次性的配对凭证。
codex-provider web自动打开带#pair=...fragment 的页面。- 页面配对成功后立即清除 fragment,并换取长期设备凭证。
- 后续 API 请求通过自定义 Header 携带设备凭证。
- 浏览器凭证保存在
localStorage,服务端只持久化其哈希。 - 提供“忘记此浏览器”和
--reset-access。 - 凭证失效时显示重新配对提示,而不是只显示原始 403。
- 已有本工具实例运行时,打开现有实例。
- 端口被其他程序占用时给出明确提示或使用可用端口,不直接抛出
EADDRINUSE。
2. 回环监听与 Origin 校验
- 服务只监听
127.0.0.1,不增加0.0.0.0监听。 - 浏览器写请求必须携带已配对凭证。
- 拒绝非法跨站 Origin。
- Origin 按实际请求的回环 Host 和端口校验,不硬编码
127.0.0.1:8791。 - 支持
localhost、自定义端口,以及 SSH 隧道两端端口不同的情况。
Origin 只用于浏览器跨站防护,写权限仍由配对凭证决定。
3. 存储配置由服务端管理
浏览器不在每次写操作中直接提交任意 codexHome 和 sqliteHome。
- 服务端自动创建默认存储配置。
- 写接口提交
profileId,由服务端解析实际路径。 - 新增或修改配置时,由服务端规范化并验证路径。
- 保留
--codex-home和--sqlite-home。 - 支持记住命名配置,避免多 Codex Home 用户反复填写。
- 使用默认配置时无需填写路径。
4. 继续支持 Node 16
最低版本调整为:
Node >=16.20.2
不升级到 Node 22。
- 启动阶段检查 Node 版本并给出明确提示。
- CI 覆盖 Node 16.20.2 和当前 LTS。
- 验证
better-sqlite3、Web 构建和完整测试。 - 文档、
package.json和测试中的版本要求保持一致。
5. 修复 History 搜索竞态
当前搜索框每次输入都会立即触发扫描。较早的请求可能在较晚请求之后返回,覆盖当前结果。
- 输入增加约 300ms 防抖。
- 按 Enter 立即搜索。
- 使用请求序号保证只有最新响应可以更新页面。
- 客户端取消旧请求。
- 切换会话时显示详情加载状态,不继续显示上一会话内容。
本 PR 不引入 History SQLite 索引或全文索引。
6. 版本统一为 0.5.0
同步更新:
package.jsonpackage-lock.json- .NET 项目版本
- Changelog
- 发布说明
- 版本一致性测试
这里的 0.5.0 仅指本 PR 中的版本元数据和一致性测试;v0.5.0 Git Tag 与 Release 由维护者在合并后创建,不需要 PR 作者操作。
7. 补充远程使用说明
-
文档补充 SSH 隧道示例:
ssh -L 8791:127.0.0.1:8791 user@server
-
无桌面或纯 SSH 环境中不强行调用
xdg-open。 -
打不开浏览器不能导致服务退出。
-
--no-open输出可点击的一次性配对链接。 -
明确说明服务不直接暴露到公网或局域网。
8. 回归验证
认证:
- 匿名访问首页不能取得写凭证。
- 无设备凭证不能调用写接口。
- 一次性配对凭证不可复用。
- fragment 不进入查询参数、HTML 或服务日志。
- 刷新页面和重启服务后保持授权。
- 执行 reset 后旧设备凭证失效。
网络边界:
- 非法 Origin 被拒绝。
- 回环别名、自定义端口和 SSH 隧道可以正常使用。
- 服务只监听回环地址。
兼容与行为:
- Node 16.20.2 下 Web 构建和完整测试通过。
- 快速连续搜索不会被旧响应覆盖。
- 版本一致性测试通过。
范围说明
本 PR 不增加账号系统、Cookie Session、角色权限、审计日志、公网监听或 History 索引。
以上改动更新到当前 PR 时,也请一并附上自动化测试结果和手工验证范围。实现方式上如有不同考虑,欢迎在对应事项下继续讨论;更新完成后再进行下一轮 Review。
辛苦了,感谢。
目的 / Why
在远程服务器/集群上使用,添加web ui支持
关联 Issue / Related issue
改动 / Changes
影响范围 / Impact
数据写入 / Data writes
验证 / Validation
Automated
Manual
代码主要是AI写的,AI跑了测试脚本,人工测试了web ui
Not run
检查清单 / Checklist