pi-web-ui

extensionmaintained

Just open your browser to get all your work done — browser cockpit for AI coding agents (chat, code, files, terminal, Git in one tab)

by — · v0.96.0 · published 20h ago

$ pi install npm:pi-web-ui
downloads/mo
0
stars
245
last push
17h ago
open issues
2

Signals

license: MITtestspi manifest: missinginstall size: —deps: 0peer deps: 0

Download trend

46.1K downloads · last 12 weeks (weekly)

README

pi-web-ui

English | 简体中文

npm 版本 Node.js 许可证

你只需要打开浏览器,就能完成所有工作。

聊天、写代码、改文件、用终端、管 Git —— 都在一个浏览器标签页里,不用开 IDE,不用来回切换。

AI 编程智能体(pi / DSH)的浏览器工作台,宗旨只有一句话:打开浏览器,什么都能干。智能体在服务端运行, 事件经 WebSocket 流式推送到浏览器。支持思考块与工具调用、附件与图片问答、内置终端、 模型管理,以及设置面板(自定义系统提示词、技能/插件开关、设置预设一键应用)等功能。 需要 Node.js ≥ 22.19 及配置好的 pi 环境。

作者的其他项目

正在使用 DSH 构建工具?

dsh-ui-tools 是作者的配套项目, 用于在 DSH 生态中构建和扩展 UI 工具。

QQ群 1126050727

功能特性

对话

  • WebSocket 流式聊天 —— pi SDK 在服务端进程内运行,事件以快照(60ms 节流)推送,浏览器按快照渲染。
  • 思考块、工具调用卡片、bash 输出,实时显示状态(执行中 → 已结束 · 等模型 · 耗时)。
  • 补充(steer) —— 回复流式中可排队发送跟进消息,当前回合工具结算后立即注入(对应 pi CLI 的 Enter 打断语义)。
  • 斜杠命令 —— 输入 / 弹出命令选择器(内置 / 扩展 / 模板 / 技能);内置 /new /name /model /compact /cwd /thinking /resume /reload,另有 /help(命令清单)、/copy(复制上一条回复)与 /pi-web-ui:quit(退出服务)。/new 可带首条提示(/new 修一下失败的测试),会作为新对话的第一条消息发出去。
  • 每项目多对话并发 —— 每个对话独立 agent runtime,切走后仍在后台运行;「运行的对话」列表显示流式进度,可随时切回。
  • 编辑重问 —— 把任意历史问题 fork 成新分支重新提问,原对话不受影响。
  • 超过 30 条的消息自动折叠为摘要行(惰性渲染,点击展开)。
  • 问题导航 —— 右侧浮动导航条 + 每个问题顶部的序号标签,一键跳转。
  • 提示词模板 —— 空对话状态展示一键模板库(仓库初始化、代码审查、调研、合并冲突……);点卡片即填入输入框,也可把当前草稿存成自己的模板。
  • 模型报错自动重试 —— 按对话可配置重试次数(默认 6,0 = 失败即停);次数用完则失败轮次标红,红色报错旁有一键「重试」按钮。
  • 排队可控 —— 排队/插队的气泡可以 ✕ 移除,也可以 ↩ 撤回:文字落回输入框(输入框非空时另起一行追加,绝不覆盖正在打的字)。
  • 消息自带信息 —— 每条消息头部显示角色、产出它的模型和本地 HH:MM 时间,每段文本都有复制按钮。附件渲染为独立可折叠卡片(模式徽章 lines/ref/bridged + 复制按钮 + 视觉桥「已转写」说明),技能调用渲染为技能卡(展开可见完整 SKILL.md),你输入的参数单独成气泡。
  • 压缩看得见 —— 上下文压缩显示为一张卡片(「已压缩 N tokens」),到货时自动展开并跳转;压缩进行中横幅实时计数(「正在压缩 · 12s」)并标明触发原因(手动 / 阈值 / 溢出)。

项目与会话

  • 切换项目 —— 工作区根目录(agent 读写的位置、终端启动位置)随时可切,不用重启:
    • 右下角状态栏的路径 —— 点 📁 <路径> 打开目录选择器:Tab 补全、↑ 回上级、💻 跳到「电脑」根以便换盘符、点文件夹进入后按「选择」,或直接「选择当前目录」;「+ 新建文件夹」可当场建目录,Esc 或点击别处关闭。
    • 右侧文件树 —— 在任意文件夹上点右键 →「以项目打开」(同一菜单里还有「上传文件到此文件夹」)。
    • 左栏「最近项目」,或输入框里 /cwd <路径>(只输 /cwd 显示当前目录)。
    • 启动默认工作目录来自 --cwd <dir> / PI_WEB_CWD。
  • 对话并行 —— 每个对话独立 agent runtime,切走后仍在后台流式;每项目最多同时 8 个(子代理不计入)。
  • 「运行的对话」列表 —— 按项目分组(当前项目置顶),子代理缩进挂在父对话下,带子代理 / 报错(悬停看原因)/ 流式徽标;✎ 行内改名;✕ 可选「仅关已结束的子代理」或「强行全关」(运行中会二次确认);右键某行只作用于该对话的子代理子树。
  • 历史会话 —— 读的是 <agentDir>/sessions/--<cwd>--/,也就是 pi CLI/TUI 写的同一份转录:浏览器和终端里的 pi 共用每个项目的一份列表。支持 ✎ 行内重命名(写入的 session_info 与 pi 的 /name 同机制)与两步确认删除。
  • 最近项目 —— 本浏览器的记录 ∪ 所有有转录的目录,去掉你删过的(墓碑)和不存在的路径,按最近使用排序(显示 20 条,最多存 30)。
  • 回到现场 —— 重连会恢复上次用的工作目录(并提示落在哪),标签标题可显示当前项目名,每个项目记住自己的「模型 + 该服务商当前密钥」用于新建对话(已有内容的对话不被覆盖)。
  • 上次关服时仍在回答的对话,会在下次连接时一次性提示「上次运行被打断」,而不是历史里凭空少一段。

搜索与导航

  • 全局搜索(Ctrl/Cmd+K) —— 一个输入框搜三处:对话转录全文(含助手输出,最多 50 条、每条带跳转锚点)、最近项目、工作区文件名(受限遍历:50 条结果 / 2 万条目 / 4 秒 / 深度 24,触顶时会明确提示而不是卡住)。↑/↓ + Enter 打开、Esc 关闭;点对话=恢复并跳到命中消息,点项目=切工作区并重搜,点文件=打开预览。
  • 会话内搜索(Ctrl/Cmd+F) —— 搜当前对话实际渲染出来的文本(大小写不敏感,走 CSS Custom Highlight API 高亮),Enter 下一个、Shift+Enter 上一个、Esc 关闭。被折叠的旧消息用消息数据建索引,所以长会话仍可搜——只有你跳到的那一条才会展开。
  • 长会话体验 —— 超过 30 条的消息折叠成摘要行(含思考/工具/bash/图片计数与 90 字预览);问题导航条列出问过的每个问题;上滚后浮出「回到底部」;只有贴底时才自动跟随输出(你主动上滚就不会被拽回);远离视口的消息替换为等高占位。

子代理与模板

  • 第一方子代理 —— 后台派发独立对话并行做调研 / 实现 / 审查(subagent_spawn);与普通对话一样在左栏管理:实时查看输出、补充(steer)、中止、移出。内存会话——不进历史 / resume 列表,可嵌套派发。
  • 子代理模板 —— 设置面板「子代理模板」里配置可复用预设:角色系统提示词(追加或整体替换)+ 技能/扩展白名单 + 可选模型 + 可选思考强度。AI 用 subagent_templates 工具查询清单、subagent_spawn(template="…") 选用,也可以不传模板按主会话默认配置运行。模型与思考强度都留空 = 跟随主对话当前设置(与「跟随主对话」的模型回落同语义);模板指定了就固定用那个组合(模型不支持的思考档位会自动收敛)。停用的模板保留在面板可随时重新启用,但对 AI 工具不可见(查不到、不能选)。模板全局共享(<dataDir>/subagent-templates.json,所有浏览器客户端一致)。首次运行自带 13 个内置模板 —— 前 6 个(review / implement / research / scout / audit / delegate)改编自 pi-subagents 社区项目,另 7 个(oracle / librarian / explore / metis / momus / multimodal-looker / sisyphus-junior)移植自 oh-my-pi 内置 agent —— 面板标「默认」徽标,可像普通模板一样修改或删除。

文件、图片与附件

  • 一律只给路径引用:reference(仅路径)/ lines(选中行范围,引用上带行号),文件内容永不注入 prompt——模型用自己的 read 工具按需读(旧版 inline 全文注入已移除,旧客户端/旧草稿发来的 inline 按 reference 处理)。
  • 粘贴 / 拖拽 / 上传图片 —— 浏览器端自动缩放,模型支持识图时作为图片内容发送(不支持时提示警告)。
  • 视觉桥 —— 当前模型不支持识图时,把图片交给自动发现的视觉模型转写成文字证据(按批次缓存,可在设置里指定模型/开关)。
  • 免工作区路径附加任意文件 —— 存入全局上传目录,以绝对路径引用(内容不注入)。
  • 文件预览 —— 行号、点选/拖拽/Shift 选区(可添加到对话为 lines 附件)、GBK 回退解码、二进制十六进制视图、媒体 HTTP 预览(支持 Range)、下载按钮。
  • 实时文件树 —— 服务端对当前列出目录 fs.watch,改动即静默重列;超大目录显示截断提示。
  • 能浏览到工作区之外 —— 文件树可以越过工作区根到 💻「此电脑」层,列出所有盘符(POSIX 下是 /);面包屑可直接跳到任意层级,.. 回上级;目录被删/改名/无权限时降级为空列表 + 提示,而不是报错页。
  • 行内操作 —— 悬停文件:下载 / 引用附件(🔗)/ 复制名称 / 复制路径;悬停文件夹:引用附件、复制名称、复制路径(纯 HTTP 环境下剪贴板不可用时自动走兜底实现)。
  • 从文件树上传 —— 右键文件夹行 →「上传文件到此文件夹」(同一菜单里还有「以项目打开」);右键文件行或面板空白 →「上传文件到当前目录」(你正在浏览的那一层)。把系统文件拖到文件夹行上就上传到那一个文件夹(该行高亮),拖到面板则上传到当前目录;拖入的是文件夹会明确提示不支持,而不是静默没反应。单文件上限 100MB,空文件会被拒绝,文件名只取 basename 并替换 Windows 非法字符(限 200 字),目标目录不存在会自动创建,上传完成后列表会刷新——哪怕你当时正浏览别的地方。
  • 列表状态的边界 —— Windows/macOS 用工作区根的递归监听,任何子目录的改动都会刷新(400ms 防抖);不支持监听的网络盘回退为 10 秒轮询(每个工作区只提示一次);POSIX 隐藏构建噪声(node_modules、.git、dist、.venv ……)且最多 500 条,Windows 只隐藏依赖/VCS/数据目录且最多 2000 条,两者被截断时都会明说。
  • 预览也是编辑器 —— 文本文件可直接改并用 Ctrl/Cmd+S 保存(限 2MB、未改动时保存置灰、带未保存改动关闭会先确认);Markdown 可切渲染/原文;HTML 在沙箱 iframe 里渲染,走目录映射 URL 让相对 CSS/图片正常加载(「启用脚本」是逐文件开关,且永不开同源);图片/视频走 HTTP Range 流式;二进制给十六进制视图;文本支持行号、点选/拖拽/Shift 选区(作为 lines 附件添加)、50–200% 缩放、自动换行开关与全屏。
  • 下载不跟安全浏览打架 —— 先取字节再用浏览器的保存框存档(不支持时回退 blob 链接,超 200MB 走原生下载),Windows 非法文件名自动改写,取消保存框不算错误。

终端与 Git

  • 内置终端(xterm.js + node-pty),每客户端独立 PTY 管理;Windows 优先 Git Bash,回退到随包下载的 busybox,再回退 cmd。同时最多 16 个在线终端(agent 自己开的不计入),每个标签切换时保留自己的 8000 行回滚;标签可行内重命名、可关闭(真杀进程),退出码会写进回滚。
  • 常用命令列表 —— 终端侧栏上半是当前项目的 .pi/commands.json 列表(name + command + cwd,${pwd} 展开为工作区):点一行即运行(同名标签复用并重启,类 VSCode task),可增删改,也能从磁盘重读文件。
  • AI bash 分组 —— agent 通过终端接管开的终端收进可折叠的「AI bash」分组,不会淹没你自己的标签。
  • 终端接管 bash(设置 → 工具,默认关)—— 开启后 agent 的 bash 工具在可见的常驻终端里跑,而不是隐藏进程,因此 cd/venv/ssh 等 shell 状态能跨调用保留;静默阈值(默认 15 秒,0 = 一直等)决定何时把安静的命令转后台,head/tail 控制模型要读的行数。
  • 活力检测 —— agent 用过的终端在对话仍流式时长时间没输出,服务端会把尾部输出作为 steer 推给 AI(「去读/回答/关掉它」),而不是干等。
  • 源代码管理(Git)面板 —— 经隐藏查询终端展示 status / branch / diff / 历史 / 未跟踪文件,另有逐文件暂存(+)与取消暂存(-)、提交框(Enter 提交、兼容输入法)与「全部提交」(git add -A && git commit)、本地/远程跟踪分支分组的切换器(选远程分支会在本地建跟踪分支)、分离 HEAD 与 ↑领先 ↓落后 徽标。「提交树」页加载 git log --graph 并可看每个提交的完整 diff。写操作(提交 / 切分支 / 推送 / 拉取)都在可见终端里跑并自动切到终端视图;仓库真实 git 目录变动时(含 worktree)以及 30 秒轮询兜底都会自动刷新,因此在浏览器之外提交也能自己出现在面板里。

模型与设置

  • 模型管理 —— UI 里编辑 models.json、按 provider 设置 API key(密钥/headers 永不下发浏览器)。
    • 模型选择器 —— 可按名称/provider/id 搜索,多个服务商时左侧有服务商栏;你常用的模型自动置顶并标「用过 N 次」,另带推理/视觉徽标;打开时滚到当前模型,底栏固定「刷新模型 / 管理模型」。
    • 一个服务商多把密钥 —— 内置服务商可存多个命名密钥(<agentDir>/provider-keys.json):加第二把不会丢掉第一把,可按名激活/删除(删掉当前活跃的会自动提升下一把)。选择器按密钥分组列出,点某把密钥下的模型即切过去;浏览器只拿到密钥昵称。
    • 自定义服务商 —— 可增删改(API 类型、baseUrl、密钥、可选鉴权头)并逐模型配置上下文窗口/最大输出/文本或图片/推理;抓取模型在服务端探测 /models(所以局域网/回环地址不受 CORS 限制)并合并结果,已保存的服务商也能重新探测。手改过的 models.json 用「重新加载 models.json」拉进来(允许注释,与 SDK 一致)。
  • 思考强度(thinking level)按模型切换 —— 共七档,模型不支持的档位置灰,而不是静默换到别的档。
  • 首次配置引导 —— 没装 pi CLI 时可直接一键安装(失败有详情、可重试/跳过),然后选服务商 + 填密钥就能开用。
  • 设置面板:
    • 系统提示词 —— 11 个来源(soul / tools / guidelines / pi 文档 / append / persona / terminal / markers / context / skills / cwd)拼成的 {{token}} 组合模板,点 token 芯片即可追加;每个来源可单独覆盖(auto 徽标、「以默认为底改写」、单独恢复默认,环境类来源保持只读);另有两个查看器分别展示实际生效的完整提示词与真正发给模型的工具 schema。
    • 输入历史与快捷短语 —— 历史有上限(1–500 条,可选单条字数上限,两步确认清空),用 ↑/↓ 在光标位于草稿首/末视觉行时翻(自动折行的行也算);输入框上方的快捷短语可逐条编辑/上下移/删除/恢复默认。
    • 技能 —— 逐个启停,另有「全文」芯片把整个 SKILL.md 注入提示词(单文件 8KB、总量 32KB)。
    • 扩展 —— 逐个启停,npm: 装的可在可见终端里一键卸载(pi remove npm:<包名>)。
    • 界面插件 / 目标审查 / 视觉桥 / 子代理模板 各有自己的页,见 界面插件。
    • 预设 —— 把当前组合(提示词模板/模式/覆盖、技能与扩展开关、工具开关、终端接管、重试次数、审查提示词、技能全文名单)存成命名预设,随时应用或删除;有意不包含(问卷、目标模式、显示偏好、视觉桥、默认子代理模型、快捷短语),应用预设后它们保持原值。
    • 生效时机 —— 工具开关、重试次数、显示偏好、标记与技能全文名单即时生效;提示词模板/覆盖与技能扩展开关需重载会话,回答中改的会延后到「本回复结束后生效」(有提示)。
    • 显示偏好 —— 思考块默认展开或折叠、工具卡默认展开、宽屏聊天列(宽屏下取消 860px 上限)、标签标题显示项目名、聊天壁纸(地址或上传,带压暗/模糊滑杆)。
  • 主题切换 —— 顶栏选择主题;主题是纯 :root 调色板覆盖(布局唯一在 styles.css)。如何添加自定义主题或向仓库贡献主题,见 主题。

代理工具与内联标记

  • 工具开关 —— 设置 →「工具」把所有可选工具逐个列出:7 个终端工具(默认关)、7 个 subagent_* 工具(默认开),其余 11 个 —— edit_soft 与 browser_page 默认关,delegate_task/ask_user_question/todo_list/conversation_read/present_files/skill/schedule_task/schedule_list/schedule_cancel 默认开。开关即时生效、不重启,工具只是被禁用仍保留注册以便随时开回;bash 与 SDK 自带的 edit/read 有意不可关。
  • 内联标记 —— 状态改变不需要工具往返,AI 直接把标记写进回复:任务列表用 [[todo:new:<主题>]] / [[todo:set:<id>,in_progress]] / [[todo:remove:<id>]] / [[todo:dep:<id>,blocks=<id>]],不打断的提醒用 [[notify:<级别>:<内容>]],改对话标题用 [[conv:rename:<标题>]]。气泡定稿即执行,标记写错会以浏览器提示回显;任务列表同时以常驻 widget 显示在右栏文件树下方(N/M done + ✓/◐/○),跟随当前对话,且因为存在该对话自己的会话分支里,刷新后仍在。设置 →「工具」另有总开关与逐标记开关(这两项全局共享)。
  • edit_soft —— 更宽松的 edit(默认关):缩进/空白导致内置工具失败时用它,先精确子串、再按去空白逐行核心匹配,newText 原样写入并保留文件换行符/BOM,结果带 diff 与 unified patch。
  • delegate_task —— 强制六段派单(TASK / EXPECTED OUTCOME / REQUIRED TOOLS / MUST DO / MUST NOT DO / CONTEXT)并在服务端校验:模板不可用、任务少于 20 字或任一段为空都会被打回,并把可用模板清单回给模型。卡片按六段结构化展示,跑完后可一键跳到对应子代理对话。
  • ask_user_question —— pi 引擎本身没有问卷工具,这是 pi-web-ui 加的:模型可以问结构化问题(单选/多选 + 富文本选项预览 + 自由文本),以对话框弹出;回答作为工具结果回给模型,取消则以工具错误返回,等你回答的时间不受工具看门狗限制,未答的问卷刷新/重连后会恢复。
  • MCP 服务器 —— 放一份 <dataDir>/mcp.json({"servers":{"github":{"command":"node","args":["mcp.js"],"cwd":"/x"}}}),该 stdio MCP 服务器声明的工具就会作为普通工具交给 AI(服务端执行);某一个起不来只记一行日志,不影响其他。文件热加载:保存后一两秒内自动生效,无需重启——且只有配置真正变了的服务器才会重启(文件写坏会报错并保留正在运行的服务器)。
  • 扩展 UI 桥 —— pi 扩展可以驱动浏览器:setWidget 在文件树下方渲染实时面板(点标题居中放大),setStatus 在底栏显示状态文本,notify 弹通知,select/confirm/input 在输入框上方弹出非模态请求面板(选项走 Markdown 渲染,Esc 当作取消);widget 文本里的 ANSI 色码会被剥掉,不会把扩展底栏变成转义序列噪声。
  • 插件能力 —— 插件可注册 /命令(选择器标 plugin 来源、服务端执行不耗 token)、注册带停止按钮的后台任务、声明设置表单、订阅运行/工具/对话事件,并在前端经 window.__piWebUiHost 切视图、新建对话。详见 界面插件。

声音与通知

  • 声音提醒 —— 总开关 + 四个事件各自开关(提问 / 完成 / 开始 / 报错),每个都带试听按钮,另有音量滑杆(0–100%)。
  • 桌面 / 系统通知 —— 默认关;开启时在点击处申请浏览器权限,被拒则自动关回(并记住)。通知经 Service Worker 发出,所以装成 PWA 后后台也能收到,覆盖「完成 / 提问 / 报错」,点通知会把应用窗口拉到前台。你明显正在看页面时不会打扰——包括 Windows 上浏览器仍声称有焦点/可见但窗口已最小化的情况(改用原生窗口矩形判定)。

PWA 与离线

  • 可安装 —— 带 web app manifest(独立窗口、192/512/1024 + maskable 图标、./ 相对路径所以子路径部署也能装),Chrome/Edge 的「安装应用」或手机「添加到主屏幕」即可得到独立窗口与图标。
  • 离线应用壳 —— Service Worker 对导航请求走网络优先 + 缓存外壳兜底(后端宕机/重启时页面仍能打开),哈希静态资源缓存优先,而 /ws、/api、/themes、/plugins 永不缓存;新 worker 会立即接管已打开的页面。
  • 该提醒时才提醒 —— 页面加载的构建与服务端 wire 协议不一致时(比如刚更新完)会固定显示刷新提示条;标签标题可显示当前项目文件夹。

语言与语言包

  • 顶栏语言菜单按母语名列出所有语言,「获取更多语言」打开的管理器列出 8 个可下载语言包的版本与下载/移除按钮(另有刷新);语言包落在 <dataDir>/locales/,所以也能手工放进去做完全离线的安装。
  • 首次访问没有存过选择时,按浏览器语言 → 实例默认(PI_WEB_LOCALE)→ 英文的顺序决定;一旦你选过就一直跟着。
  • 服务端面向模型/工具的文案也跟随同一语言(工具返回值、提示词段落、提醒),所以中文界面下 subagent_list 这类工具也返回中文。

目标(Goal)模式

  • GoalBar 目标栏 —— 设置目标 + 审查模型 + 最大轮数 + 锁定开关。
  • 目标调研向导(「AI 提炼」)—— 通过引导式问卷把原始需求收敛成明确目标。
  • 自动审查循环 —— 每轮结束后用独立审查会话核对「目标 + 最终文本 + git diff HEAD」;不达标就把审查意见作为 steer 注入重改,直到通过或达到轮数上限。

DeepSeek Harness(DSH)引擎

  • 引擎可切换 —— PI_WEB_ENGINE=pi|dsh(默认 pi)。pi 引擎在进程内跑 pi SDK;DSH 引擎把官方 @deepseek-ai/dsh(DeepSeek Harness)运行时作为子进程拉起。/api/health 返回 engine;底栏显示 DSH 徽标。
  • 同一套 wire 协议 —— DSH 引擎实现与 pi 相同的 WebSocket 协议,目标/审查、SCM、后台任务、设置、插件、终端、message_delta 与快照全部一致。
  • 原生目标机制 —— DSH 自己的目标状态机 + round-driver 自动续轮;完成/受阻由模型自判定(无独立审查会话)。目标向导经模型 ask_user_question 驱动。
  • 真图片块 —— 图片作为真正的 image 内容发给支持视觉的 DeepSeek 模型(如 deepseek-v4-flash-vision-exp);纯文本模型走文字转写桥。
  • 提问对话框 —— 模型 ask_user_question 弹出浏览器对话框(单选/多选 + 自由文本),支持排队与倒计时。
  • 工具 & MCP 桥 —— 插件 AI 工具与外部 MCP 服务器(mcp.json)都桥进 DSH 运行时,DSH 模型可直接调用(服务端执行)。
  • 技能启停 —— 设置面板暴露 DSH 技能目录;禁用即运行时过滤该技能,模型不可见。
  • DSH 用户补丁 —— 在 <dataDir>/dsh-patches/ 放 .yml Cordis 补丁扩展运行时,设置面板一键重扫生效;设置 →「插件」会列出补丁文件(大小/时间)与解析后的目录路径,坏文件跳过并把错误打到运行时的 stderr。

DSH 与 pi 引擎的差异(切换前值得知道):

  • 思考强度固定 high,改档会回答「DeepSeek V4 只支持高思考强度」。
  • 底栏的 token/成本/上下文按 DeepSeek 官方每百万定价与 100 万窗口计算。
  • 打开历史会话是只读回放:一发消息就会开新分支并把旧对话作为上下文注入(运行时不允许原地续聊);编辑重问同理。
  • 停止会杀掉运行时进程树,所以所有进行中的 DSH 对话都会停(有提示),半成品目标会先清除;不支持只中止 bash 工具。
  • 会话存在 <dataDir>/dsh-sessions/(与 pi 引擎的转录隔离),超过 PI_WEB_DSH_SESSION_RETENTION_DAYS(90)天自动清理;每项目最多同时 8 个对话;运行时崩溃按 1s/3s/9s 退避重启,60 秒内最多 2 次,超限就停下并提示你去查 API key 与 DSH 依赖。
  • 工具跑在 workspace-write 沙箱里、审批为 never——你的「停止」按钮就是控制阀。问卷是逐题向导(带选项预览与倒计时)。
  • pi 专属能力(会话重命名、/compact、/reload、扩展热重载、子代理模板、自定义服务商/多密钥、服务商模型探测、装 pi CLI、视觉桥、逐工具开关)都会给明确提示并被隐藏入口,而不是静默失败。

后台任务

  • 后台任务面板 —— 在 bash 前后对比监听端口,检测 agent 启动的服务并列出端口 / pid / 名称 / 命令行(点命令行可展开全文);可单独停止或全部关闭,顶栏按钮带实时数量徽标。
  • 列表属于浏览器客户端而非对话:切项目、切对话、重连都不丢,服务端每 30 秒刷新一次并剔除已退出的进程。检测会排除已知桌面软件,以及父链回溯到 explorer 而不是服务进程的进程(所以你自己开的浏览器不会被当成「AI 启动的服务」)。
  • 插件注册的任务带 🧩 标记与实时状态文本,走插件自己的停止回调(比如邮件轮询任务)。
  • 工具看门狗 —— 单个工具调用超过 20 分钟自动中断会话(超时在设置「工具」页可改,0 = 禁用;PI_WEB_TOOL_TIMEOUT_MS 只提供默认值;工具自己声明更长超时,如 bash timeout,则自动顺延)。问卷豁免。
  • 只停止 bash 命令 —— 中止运行中的 bash 工具而不打断对话。
  • 失联警告 —— 流式运行完全没事件超过 3 分钟(PI_WEB_STALL_NOTIFY_MS,0 = 关)会指名对话地提醒一句,但不自动中止。

安全与运维

  • 默认只绑 loopback;局域网 / 容器需显式 PI_WEB_HOST=0.0.0.0。
  • 口令鉴权 —— PI_WEB_TOKEN 可经 Authorization: Bearer …、X-PI-Token: …、?token=… 或 pi_web_token cookie 任一通过;?token= 链接一次登录、从地址栏抹除并把口令写入 cookie,每次授权请求都会刷新它,失效 cookie 在 401 时立即过期——所以改完口令后一次正确的 ?token= 进入就永久恢复。/api/health 保持开放给探针。
  • WebSocket Origin/Host 同权威校验 —— 跨源页面直接拒绝(403),Origin: null(file:// 页面)一律拒绝,设了口令时凭据不对会在升级前就被 401;反代场景用 PI_WEB_ALLOW_ORIGINS 白名单。
  • Host 白名单 —— PI_WEB_ALLOW_HOSTS=host1,host2 在始终生效的同权威校验之上再加一层严格主机名白名单。
  • 实例收窄 —— PI_WEB_TABS=chat,terminal,git 只开放这些标签页,未列出的标签页在服务端也会被拒绝(对应消息返回说明),chat 永不可关。PI_WEB_MANAGED=1 声明实例由外部部署管理:自更新、装 pi CLI、插件市场安装都会被服务端拒绝并给出原因,前端也隐藏这些入口(版本按钮变成纯标签)。
  • 文件边界 —— 工作区相对路径的读写一律做 .. 逃逸校验(工作区外的路径只能经显式绝对路径/机器浏览到达);/api/file 内联只放行图片/视频/HTML,二进制不可能被 <img> 带走——其他类型必须走 ?download=1(附件下载)。HTML 预览路由一律以 sandbox 下发。
  • 本地控制 socket 提供 server status|quiesce|unquiesce(排空模式:拒绝新 prompt/编辑重问/会话恢复,DSH 下还会拒绝新客户端连接,存量跑完)。
  • 凭据不下发浏览器 —— provider headers(可能含 Authorization)永不发送到前端,服务商 API key 只以昵称形式到达浏览器。
  • 10 种界面语言(中英内置 + 8 个可下载语言包:德/西/法/意/日/韩/葡/俄),语言包可在顶栏菜单里装/卸(见上方「语言与语言包」)。
  • 保留期 —— uploads/ 里超过 PI_WEB_UPLOAD_RETENTION_DAYS(14 天,0 = 不清理)的文件会在启动时与之后每 6 小时清理一次;DSH 会话有自己 90 天的清理。
  • 运维看门狗(工具超时、模型失联、终端活力)都可调,见 环境变量调优。

部署与更新

  • 前台运行 / 全局 npm 安装 / Docker(见 Docker)/ macOS launchd / Linux systemd / Windows 登录自启(HKCU Run 键 + 无控制台启动器 + 崩溃看门狗)/ 桌面快捷方式(server shortcut)。
  • server install --print 只打印将要写入的 launchd plist / systemd unit / Windows 启动器就退出,可在真正安装前先审阅。
  • 更新面板 —— 版本按钮在有新版本时显示黄点,另有「N 个更新」徽标;「检查全部更新」会比对本体、全局安装的 pi 核心与 <agentDir>/npm/package.json 里声明的直接依赖,每行都能单独更新,另有「全部更新」与「重新检查」;命令在可见终端里跑(pi 扩展走 pi update npm:<名字>,这是唯一能更新 pi 真正加载的那份的命令;其余走 npm i -g <名字>@latest)。刚发布不足 30 分钟会提醒 npm 缓存元数据可能还没同步。被 launchd/systemd/Windows 看门狗托管的实例多一个「重启服务」按钮;前台运行的实例没有,因为没有东西会把它拉回来。
  • 命令行更新插件 —— pi-web-ui plugins --check-updates 逐个对比插件记录的提交与远端 HEAD 并给出确切更新命令;每次 install --force 都会把旧版本快照到 <dataDir>/plugin-backups/(只留最近 3 份,拷贝失败自动回滚),所以 pi-web-ui plugins --rollback <id> 可以退回上一版。
  • pi CLI 里还有 /webui(来自随包的 extensions/webui.ts):/webui 从 8787 起挑第一个空闲端口拉起服务,--port 9000、--cwd <路径>、--no-browser、status、stop 分别控制它;每个 pi 会话一个子进程,会话关闭时回收,不留孤儿进程。

快捷键

按键作用
Enter发送。触屏设备上 Enter 改为换行,Ctrl/Cmd+Enter 才发送(Windows 触屏笔记本当作桌面)。
Shift+Enter输入框内换行。
↑ / ↓光标在首/末视觉行时翻全局输入历史(跨对话持久化;自动折行的行也算,一段长草稿按 ↑ 是逐行上移光标而不是切历史);Esc 回到草稿。
Ctrl/Cmd+K全局搜索(对话 / 项目 / 工作区文件名)。
Ctrl/Cmd+F搜当前对话 —— Enter 下一个命中,Shift+Enter 上一个,Esc 关闭。
/打开斜杠命令选择器(↑/↓ 选择、Tab 或 Enter 补全、Esc 关闭;输入空格则自动关闭)。
Ctrl/Cmd+S预览里编辑文件时保存。
Ctrl/Cmd+A预览里全选行(光标不在文本框时)。
Ctrl/Cmd+Enter提交「编辑重问」编辑器。
Ctrl/Cmd+C / Ctrl/Cmd+V终端里:有选中则复制(无选中时 ^C 仍发给 shell)/ 原生粘贴。
Esc关闭预览、对话框、命令选择器、问卷或扩展请求面板(预览有未保存改动时会先问)。
拖放窗口任意位置拖入文件 = 附件到对话;拖到文件树 = 上传到那一个目录;不支持拖文件夹(展开后选文件)。

界面截图

对话 + 提示词模板

对话 + 提示词模板

运行轨迹时间线

运行轨迹时间线(run-trace 插件)

设置面板

设置面板

内置终端

内置终端

Git 源代码管理面板

Git 源代码管理面板

安装

npm i -g pi-web-ui            # 全局安装(推荐)
npx pi-web-ui                 # 或免安装直接跑(拉取最新版,启动在 :8787)
npm i -g .                    # 或安装本地 checkout

npm ≥ 12? npm 12+ 默认阻止依赖安装脚本(会看到 npm warn install-scripts … blocked 警告)。 node-pty 是原生模块,需要放行其脚本(其余两个包只是 no-op/纯提示,一并放行可消除警告):

npm i -g --allow-scripts=node-pty,@google/genai,protobufjs pi-web-ui@latest

Termux(Android)

pi-web-ui 可以通过 Termux 在 Android 上运行,但原生依赖 node-pty 需要编译工具链,而且 Android 有几个值得注意的坑:

  1. 先安装编译工具链 —— node-pty 需要 Python 和 C 工具链:

    pkg install python clang make binutils
    
  2. 给 node-pty 构建指定一个占位 NDK 路径。在 Android 上,gyp 会报 Undefined variable android_ndk_path,除非该变量有定义:

    GYP_DEFINES="android_ndk_path=' '" npm i -g --allow-scripts=node-pty,@google/genai,protobufjs pi-web-ui@latest
    
  3. 如果安装后 pi-web-ui 无法执行(Android 上 exec 位和/或 shebang 可能 被破坏):恢复它:

    chmod +x "$(command -v pi-web-ui)"
    sed -i 's/\r$//' "$(command -v pi-web-ui)"
    
  4. 后台运行时加上 --no-browser(没有桌面浏览器可以自动打开):

    setsid nohup pi-web-ui --no-browser --cwd /path/to/workspace >~/pi-web.log 2>&1 &
    

    setsid 把服务器从启动它的 shell 的进程组中脱离,关闭 Termux 会话也不会 带走服务器 —— 单靠 nohup 在父进程组被杀时是不够的。

启动时的 [control] socket error: EACCES …/.pi-web/pi-web-ui.sock 警告在 Android 上无害:pi-web-ui server stop/restart 无法通过 control socket 工作, 但 Web UI 本身不受影响。

启动

前台启动

pi-web-ui                                           # 前台,http://localhost:8787

启动参数 & 环境变量 —— 每个设置既能用命令行的 --flag 传,也能用环境变量设(flag 优先)。 二者任选一种即可:

参数环境变量默认作用
--port <n>PI_WEB_PORT8787HTTP 端口
--cwd <dir>PI_WEB_CWD当前目录工作区根(读/写/终端)
--data-dir <dir>PI_WEB_DATA_DIR~/.pi-web数据目录(界面状态/插件/上传/主题/语言包)
--engine <pi|dsh>PI_WEB_ENGINEpi智能体引擎;--engine dsh = DeepSeek Harness
--host <addr>PI_WEB_HOST127.0.0.1监听地址(0.0.0.0 供局域网/Docker)
--agent-dir <dir>PI_CODING_AGENT_DIR~/.pi/agentpi 配置目录(auth.json、models.json、会话、技能)
--no-browser—关启动但不自动打开浏览器
仅环境变量PI_WEB_TOKEN空可选共享鉴权口令
仅环境变量PI_WEB_DSH_*—dsh 运行时、补丁与调试设置

两者等价 —— 任选其一:

pi-web-ui --engine dsh --port 9000 --cwd /path/to/project
PI_WEB_ENGINE=dsh PI_WEB_PORT=9000 PI_WEB_CWD=/path/to/project pi-web-ui

若用 dsh 引擎,需先安装运行时(npm i -g @deepseek-ai/dsh@0.1.1-rc.2)并准备 DeepSeek API key (读 ~/.pi/agent/auth.json,在服务商/API key 面板设置)。

停止

  • 前台:在运行它的终端里按 Ctrl+C。
  • 作为服务:pi-web-ui server stop。Linux 和 Windows 上会保留开机自启(下次登录/开机会回来,直到 server uninstall);macOS 上 stop 会卸载 launchd 代理,因此不再登录自启——用 pi-web-ui server start 恢复。

更新

npm i -g pi-web-ui@latest     # 升级到最新发布版本
pi-web-ui server restart      # 重启服务使新版本生效(前台运行则手动重启)

卸载

npm uninstall -g pi-web-ui

卸载不会删除你的聊天记录:历史面板里的转录存在 <agentDir>/sessions/(默认 ~/.pi/agent/sessions/,按项目分子目录),其余状态(界面设置、最近项目、插件、上传、主题、语言包)存在 <dataDir>(默认 ~/.pi-web/)。两者都能跨卸载/升级/重装保留,之后重跑 pi-web-ui server install 会重新读到(若要删除它们,先备份 sessions/ 与 plugins/ —— 卸载本身永不动这两处)。

作为系统服务(开机自启)

pi-web-ui server install --port 9000 --cwd /path/to/project   # 安装 + 启动
pi-web-ui server status                     # 运行中?开机自启?
pi-web-ui server restart                    # 重启(应用配置/版本变更)
pi-web-ui server stop                       # 停止(开机自启保留)
pi-web-ui server start                      # 再次启动
pi-web-ui server uninstall                  # 彻底移除服务
pi-web-ui server shortcut                   # 桌面一键启动图标
pi-web-ui server quiesce                    # 排空:拒绝新的对话/消息,存量运行继续跑完
pi-web-ui server unquiesce                  # 解除排空,恢复接收新工作

server status 还会经本地控制 socket 显示实时状态(版本、PID、排空状态、 浏览器连接数、运行中对话数)——quiesce/unquiesce 也走同一个 socket。

  • macOS → launchd 代理(无需 sudo),日志 /tmp/pi-web-ui.log / .err
  • Linux → systemd unit(systemctl enable --now),日志 journalctl -u pi-web-ui -f
  • Windows → 登录自启 Run 键(HKCU,无需管理员)+ wscript 无窗口启动器 + 10 秒崩溃看门狗(PID 写在 %APPDATA%\pi-web-ui\)

选项:--port(默认 8787)、--cwd(工作目录)、--data-dir(数据目录)、 --engine <pi|dsh>、--host、--agent-dir、--name(自定义服务名)、 --print(只打印将生成的配置,不安装)。重复执行 server install 并传入新选项即可重新生成配置并重启服务 —— 这就是修改已装服务端口/工作目录/引擎的方式。 --engine / --host / --agent-dir 会自动烘焙进服务;仅环境变量的(PI_WEB_TOKEN、 PI_WEB_DSH_*)需手动写进服务配置。见上方「启动参数 & 环境变量」表。

pi-web-ui server install --engine dsh --port 9000 --cwd /path/to/project

Docker

镜像会构建前后端、保留 node-pty 需要的编译工具链、预装 DSH 运行时(所以 PI_WEB_ENGINE=dsh 无需额外步骤)、以非 root 的 node 用户运行,并声明 /app/.pi-web 为数据卷:

docker compose up -d          # 然后打开 http://localhost:8787

docker-compose.yml 已设好容器必需的 PI_WEB_HOST=0.0.0.0(端口映射的前提),并用命名卷 pi-web-data 持久化数据目录。文件里注释掉的块覆盖常见容器调整 —— 切 DSH 引擎、挂 dsh-patches 目录、把项目挂为 PI_WEB_CWD、把 ~/.pi/agent 只读挂为 PI_CODING_AGENT_DIR(让容器能看到你的 API key 与模型配置):

services:
  pi-web-ui:
    build: .
    ports: ["8787:8787"]
    environment:
      PI_WEB_HOST: 0.0.0.0
      # PI_WEB_ENGINE: dsh
    volumes:
      - pi-web-data:/app/.pi-web
      # - ./my-project:/workspace:ro
      # - ~/.pi/agent:/root/.pi/agent:ro
volumes:
  pi-web-data:

界面插件

插件是可选的界面组件(顶栏多出一个 tab,背后是插件自己的视图,可带服务端入口和 AI 工具)。 它们安装在数据目录的 plugins 文件夹(<dataDir>/plugins/<id>/,默认 ~/.pi-web/plugins/)—— 一个插件就是一个目录:manifest.json + 可选服务端入口 (index.mjs)+ 可选视图入口(client/entry.mjs)。目录不存在 = 没有插件,界面上不会有任何痕迹。

插件目录

以下插件随本仓库发布(plugins/<id>/),可直接从 GitHub 安装:

插件功能
📬 网页邮箱 webmailIMAP 收件箱浏览/搜索/阅读/标记/删除 + SMTP 发信、新邮件通知,可选「允许 AI 管理邮箱」(六个 mail_* AI 工具)。首次激活自动补装 npm 依赖。
🗄️ 数据库 db-client数据库工作台:MySQL / PostgreSQL / SQLite / SQL Server / MongoDB / Redis 连接管理 + 库表树 —— 表结构、分页排序、SQL 编辑器、行编辑。驱动首次使用自动安装。
📝 编辑器 + SSH vscode-editor类 VSCode 工作台:多根文件树(本地 + SSH 主机)、CodeMirror 多标签编辑器、Remote-SSH 远程文件浏览/编辑、可拖拽多终端面板(xterm.js)、SFTP 同步与下载到电脑。自动安装 ssh2。
📊 图表 mermaid把对话里的 ```mermaid 围栏渲染成 SVG 图表(fenced-code 渲染插件,本地引擎离线优先)。
🧭 运行轨迹 run-trace运行轨迹:任务 → 思考 → 工具 → 文件改动 → 结果的时间线聚合视图,支持回放与节点详情。
📖 阅读 legado-webLegado 阅读(文本源):基于兼容安卓书源的搜书 / 发现 / 详情 / 目录 / 正文阅读,支持书源导入、检测与删废源,并提供四个修源 AI 工具(legado_rules、legado_book_sources、legado_source_probe、legado_run_rule)与「🤖 AI 修复源」按钮(带失败现场直接开新对话)。书源/书架/进度存在 <dataDir>/legado-web/。
💬 微信通道 wechat-ilink微信扫码登录(与腾讯 openclaw-weixin 同源的 ilink 协议):出站长轮询收消息,在微信里直接指挥 agent,无需公网 IP。
🎤 语音输入 voice-input输入框旁的麦克风按钮:浏览器语音识别直接听写进输入框;不支持/识别失败时自动降级为服务端转写(远端接口,或一键安装的本地 Whisper,免费不出网)。
🌐 实时预览 live-previewLive Server 式预览:/liveserver 看 HTML(含相对资源与自动刷新)、/md 看 Markdown 渲染;真服务只绑回环地址,经宿主通用代理对外只露同源前缀。
🖼 图片处理 image-toolkit图片处理工作台:压缩(按目标体积二分逼近)、裁剪、缩放、旋转/翻转、格式转换(PNG/JPEG/WebP/AVIF)、批量导出 ZIP、水印、滤镜调色、图片信息与 EXIF,可直接读写工作区图片;另给 AI 配了 4 个工具。
📓 笔记 notes随手记:笔记 + 待办 + 日程提醒三合一。顶栏按钮打开可自由拖拽的全局浮窗(位置/尺寸记忆,设置也在浮窗里,无独立视图页);提醒走服务端定时(重启不丢、错过补送),另有 5 个 AI 工具与 /note /todo /remind 快速捕获。

plugins/demo-mailbox 作为最小插件模板保留在仓库里(服务端入口 + 客户端视图 + 双向消息协议),兼作测试夹具——想自己写插件从这里入手。

也可以直接在界面里装:设置 → 界面插件 → 插件市场列出可维护插件(同一套,随包在 plugins/catalog.json)并提供安装 / 更新 / 卸载(更新保留 config.json),还能用「添加插件」把任何第三方插件(填 owner/repo 或 owner/repo/子目录)加进列表——你加的条目存在 <dataDir>/plugin-catalog.json。插件作者想让插件进内置列表,往 plugins/catalog.json 提一行 PR 即可。

安装示例(网页邮箱):

pi-web-ui install https://github.com/xing-shuyin/pi-web-ui/tree/main/plugins/webmail

每个插件在仓库里的目录都带独立 README.md,含完整功能清单、配置说明与注意事项。

社区插件

插件目录并不限于本仓库:条目的 source 可以指向任意 GitHub 仓库(owner/repo、monorepo 里的 owner/repo/子目录, 两者都可带 #ref),所以在别处开发、发布、维护的插件同样能进市场列表,安装 / 更新 / 回滚与上面的插件完全一致—— 同样落在 <dataDir>/plugins/<id>/,更新时保留 config.json。

装的时候代码是从那个仓库拉的,本仓库不做内置拷贝:社区条目只是一条指针,许可证、issue 与发布节奏都归插件作者。 想要固定版本,在 source 里带上 #ref。

插件功能
🌿 多仓库 Git multi-git多仓库 Git 总览:项目目录下每个仓库的变更、差异、历史、分支、贮藏、跨仓搜索、时间线与单文件回滚,另有工作区分支聚合、Fetch/Pull(仅快进)与可选的内置终端;其余只读。

想被收录,和任何条目一样只差一行:往 plugins/catalog.json 加一条并发 PR。不提 PR 也可以在市场里自行登记(存在 <dataDir>/plugin-catalog.json),或用 pi-web-ui install --catalog <url> 把市场指向你自托管的目录文档。

安装

从 GitHub 安装(支持以下任意源写法):

pi-web-ui install owner/repo                                  # 简写
pi-web-ui install https://github.com/owner/repo               # 完整 URL(.git 可省)
pi-web-ui install https://github.com/o/r/tree/dev/sub/dir     # 指定分支 + 仓库内子目录
pi-web-ui install owner/repo#v1.2                             # 指定分支/tag(#后缀对以上任意写法都适用)
pi-web-ui install /path/to/plugin-dir                         # 本地目录直接安装(开发调试用)

常用选项:

  • --name <id> —— 自定义插件 id / 目录名(默认取仓库名或子目录名;仅限字母数字--/_)。
  • --force —— 目标目录已存在时覆盖安装。插件本地的 config.json(凭据等)在升级时会原样保留。
  • --data-dir <dir> —— 覆盖数据目录(默认 ~/.pi-web)。

CLI 会浅克隆仓库(无 git 时回退 tarball 下载),定位其中的 manifest.json (包括仓库内子目录里的),然后把插件拷贝到 <dataDir>/plugins/<id>/。

没装 git?没有网络? 直接把插件目录手工拷进 ~/.pi-web/plugins/ 也行——效果完全一样。

更新

对同一来源重新执行 install 并加 --force 即覆盖更新:

# 例:把网页邮箱插件更新到仓库里的最新版
pi-web-ui install https://github.com/xing-shuyin/pi-web-ui/tree/main/plugins/webmail --force
  • 升级时会自动保留插件目录里的 config.json(账号凭据等)。
  • 存放在插件目录其他位置的本地数据不在保留范围内(如 db-client 的 db-connections.json、vscode-editor 的 ssh-hosts.json)——强制重装前请先备份。
  • 更新后刷新浏览器即可生效,无需重启服务。
  • 想知道哪些插件过时了:pi-web-ui plugins --check-updates 逐个对比记录的提交与远端 HEAD;退回上一版用 pi-web-ui plugins --rollback <id>(每次 --force 升级前都会自动备份旧目录,只留最近 3 份)。

生效方式

服务运行中只需刷新浏览器——新插件在 attach 时即被加载,无需重启;服务未运行则下次启动生效。 每个插件会在顶栏出现一个 tab(🧩 或插件自带图标)。

列出 / 停用 / 卸载

pi-web-ui plugins             # 列出已装插件(id / 名称 / 版本 / 描述)
pi-web-ui uninstall <id>      # 卸载插件
  • 想临时隐藏某个插件而不卸载:设置面板(⚙)→「界面插件」开关即可——按客户端持久化、纯 UI 隐藏,无需重启,随时可重新打开。
  • uninstall 会删除插件目录;刷新浏览器后 tab 即消失。写在插件目录内的配置文件也会一并删除—— 如需保留请先备份 <dataDir>/plugins/<id>/config.json。

浏览器扩展

🎯 网页元素拾取(page-picker)

在开发中的网页上点选元素,把它整理成 AI 能直接动手的上下文,一键注入 pi-web-ui 的对话输入框 (Alt+Shift+P 或点扩展图标 → hover 高亮 → 点击拾取 → Shift+点击多选 → 写备注 → 「添加到对话」)。

它不是 pi-web-ui 的服务端插件,而是一个浏览器扩展(所以不走 pi-web-ui install):

下载装(不需要 Node):page-picker-extension.zip → 解压 → chrome://extensions 打开「开发者模式」→「加载已解压的扩展程序」→ 选解压出的目录 → 点扩展的「扩展程序选项」填 pi-web-ui 地址(远程地址先点「授权该地址」)。

详细说明(交互、采集了什么、远程部署、已知限制)见 plugins/page-picker/README.md。

采集的不是截图,而是能让 AI 一次改对的东西:React fiber 里的组件源码位置(Card.tsx:18:5 + 调用链)、Vue SFC 文件、命中的 CSS 规则源文件与行号(Vite dev 下精确反推)、 只保留「与默认值不同」的计算样式子集、短且唯一的定位串、HTML 骨架与折叠文本; 可选元素截图会走对话附件。

主题

每个主题是一份纯 :root 调色板覆盖 —— 只写 CSS 变量的声明文件(变量全集见 web/src/styles.css 的 :root:--bg/--accent/--term-* 基础色,加 --tooltip-bg/--code-bg/--notice-* 等派生色)。布局只存在于打包的 web/src/styles.css 里,选主题只是覆盖变量,因此任何主题都能在所有版本上工作,改布局也不需要碰主题文件。内置主题由 node make-light-theme.mjs 生成。

内置主题随 npm 包分发(themes/,共 23 套)。选择器把命名调色板(nord、tokyo-night、catppuccin、one-dark、solarized-light、geist、ayu-light 等)归在「现代经典」下,内置预设归在「原始预设」下:white / mist / paper / sakura(浅色)、cyberpunk / dazzle / dark-teal(深色)、md-preview,以及壁纸友好的 translucent / transparent(可配对话壁纸)。主题选择器在顶栏(🌞 图标),当前选择按浏览器存在 localStorage。

使用主题

在顶栏直接选择即可 —— 内置主题和用户主题合并显示在同一个菜单里;同名 id 时用户主题优先。

本地添加主题(无需 GitHub)

把任意 CSS 文件丢进数据目录的 themes 文件夹就会自动出现在主题菜单里 —— 不用重启、不用重新构建:

  1. 找到数据目录(默认 ~/.pi-web,可用 PI_WEB_DATA_DIR 覆盖)。
  2. 创建 <dataDir>/themes/ 并放入你的样式表,例如 ~/.pi-web/themes/my-theme.css。
  3. 刷新页面,在顶栏选择它。文件名(去掉 .css) 就是菜单里显示的主题 id。
~/.pi-web/
└── themes/
    └── my-theme.css          # 菜单里显示为 "my-theme"

最容易的写法:复制一个内置调色板(如源码仓库里的 themes/white.css),改 :root 颜色即可 —— 想覆盖哪些变量就列哪些,没列的会落到 styles.css 的深色默认值。注意:

  • 终端跟随主题 —— 在你的 :root 里设置 --term-* 变量(终端 ANSI 配色 + --term-bg),xterm 画布和它的内边距容器都会自动适配(默认值见 styles.css)。
  • 代码高亮色(打包自带 highlight.js 的 github-dark.css)在浅色主题下必须覆盖,否则代码会看不清 —— 参照 themes/white.css 末尾的 .hljs 覆盖写法(深色主题可跳过)。
  • 主题 id 必须匹配 ^[A-Za-z0-9_-]+$(不能有点和斜杠 —— 服务端有路径穿越防护)。

向仓库贡献主题(GitHub)

想让你的主题随包分发给所有人?在 github.com/xing-shuyin/pi-web-ui 开一个 Pull Request:

  1. Fork 并 clone 仓库。
  2. 创建 themes/<id>.css —— 一份纯 :root 调色板。以 themes/white.css(浅色)或 themes/cyberpunk.css(深色)为模板。
  3. 本地验证:运行 npm run dev,用顶栏主题选择器确认你的主题能被列出、渲染正确(对话卡片、代码块、工具调用卡片、Git/终端面板)。
  4. 如果你改了 styles.css 的变量清单,用 node make-light-theme.mjs 重新生成全部内置主题。
  5. 提交(git add themes/<id>.css)并开 PR。themes/ 已在 npm 包 files 白名单里,合并发布后 npm i -g pi-web-ui 即可把你的主题带给所有人。

合并主题的规则:必须是单一 CSS 文件、设置 --term-* 变量保证终端可读、浅色主题覆盖 .hljs 语法高亮色以保证代码可读。

环境变量调优

以下全部可选——默认值就是开发时一直在用的配置。完整参考:docs/env-vars.md。

变量默认作用
PI_WEB_TOOL_TIMEOUT_MS1200000(20 分)单工具调用看门狗;超时自动中止(ask_user_question 豁免)。只做默认值,设置面板「工具」页优先。
PI_WEB_STALL_NOTIFY_MS180000(3 分)流式运行完全没事件时给警告(不中止);0 = 关。
PI_WEB_TERMINAL_IDLE_MS15000AI 开过的终端静默这么久就催它去看一眼;0 = 关。
PI_WEB_TERMINAL_IDLE_LINES10该催命消息回送的终端尾部行数(1–500)。
PI_WEB_VISION_TIMEOUT_MS90000视觉桥整批转写的超时。
PI_WEB_UPLOAD_RETENTION_DAYS14<dataDir>/uploads/ 保留天数;0 = 不清理。
PI_WEB_SHELL自动仅 Windows:node-pty 用哪个 shell(自动顺序:PI_WEB_SHELL → $SHELL → Git Bash → 随包 busybox → %COMSPEC% → PowerShell)。
PI_WEB_TABS全部标签页逗号分隔的标签页白名单(chat,terminal,git,search,tasks,settings,plugins);未列入的在服务端也被拒绝,chat 不可关。
PI_WEB_MANAGED关1/true 声明实例由外部部署管理:自更新、装 pi CLI、装插件都被拒绝并说明原因,前端也隐藏入口。
PI_WEB_ALLOW_HOSTS空严格的主机名白名单(叠加在始终生效的同权威校验之上)。
PI_WEB_LOCALE空首访回退语言(显式选择与浏览器语言优先级更高)。
PI_WEB_LOCALE_BASE_URLGitHub raw语言包下载根 —— 指向镜像即可做离线/内网安装。
PI_WEB_PKG_ROOT自动显式指定包根目录(非标准安装位置时用)。
PI_CODING_AGENT_SESSION_DIR空让 pi 把转录扁平写入该目录(而非 <agentDir>/sessions/--<cwd>--/,会改变历史列表读到的内容)。
PI_WEB_SDKbundled用哪一份 pi SDK:bundled(pi-web-ui 自带的副本)或 global(祖先链上更新的那份)。
PI_WEB_ALLOW_ORIGINS空WebSocket Origin 校验的额外白名单(逗号分隔;dev 代理 / 反向代理用)。
PI_WEB_GIT_EXTENSION_CHECK1(默认开)设 0/false/no/off 关闭「全部组件更新」里的 git 行(走 git ls-remote),大型单体仓库场景可用。
PI_WEB_PLUGIN_CATALOG_URL官方清单 URL开机插件市场清单来源:默认指向官方社区清单 https://xing-shuyin.github.io/pi-web-ui-plugins/catalog.json(仅拉取文档写可安装列表,不自动安装插件)。设为空串或 off/0/false/no 可关闭;设 PI_WEB_PLUGIN_CATALOG_INSTALL=1 时顺手自动全部安装。
PI_WEB_LAUNCHED_BY / PI_WEB_SERVICE_NAME空由 pi-web-ui server install 写进服务单元/启动脚本(service / --name):服务端据此知道实例由平台服务托管,更新面板才会出现「重启服务」按钮。
PI_WEB_DSH_*—DSH 运行时旋钮:PI_WEB_DSH_RUNTIME、PI_WEB_DSH_DATA_DIR、PI_WEB_DSH_PATCH_DIR、PI_WEB_DSH_QUESTION_TIMEOUT_MS、PI_WEB_DSH_TOOL_TIMEOUT_MS、PI_WEB_DSH_SESSION_RETENTION_DAYS、PI_WEB_DSH_DEBUG。

安全

  • 默认只绑 loopback —— 服务器只监听 127.0.0.1,不暴露到网络;需要局域网访问或 Docker 端口映射时显式设置 PI_WEB_HOST=0.0.0.0(docker-compose.yml 已内置)。
  • WebSocket Origin 校验 —— 浏览器页面连 /ws 时其 Origin 的 hostname 和端口 必须与请求 Host 一致,跨源页面直接 403;无 Origin 的非浏览器客户端不受影响。 反向代理场景可用 PI_WEB_ALLOW_ORIGINS=http://你的域名:端口 放行。
  • Quiesce 排空 —— server quiesce 后拒绝新的 prompt/编辑重问/会话恢复,存量运行 跑完为止(升级/备份前用);server unquiesce 恢复。
  • 凭据不下发浏览器 —— provider 的 headers(可能含 Authorization / API key) 永不发给浏览器;模型管理 UI 编辑其他字段,服务端自动保留 headers。

反向代理(nginx)

pi-web-ui 默认只绑 loopback,同机 nginx 反代是官方支持的远程访问方式(无需 PI_WEB_HOST=0.0.0.0):

# pi-web-ui 在 127.0.0.1:8787,对外暴露为 https://your-host/pi/
server {
    listen 443 ssl;
    server_name your-host;
    # ssl_certificate ... / ssl_certificate_key ...

    # 应用入口(剥掉 /pi/ 前缀)
    location /pi/ {
        proxy_pass http://127.0.0.1:8787/;
        proxy_http_version 1.1;
        # 必须用 $http_host(保留端口)—— 服务端的 Origin 校验比较完整权威
        # (hostname + 端口),$host 会丢掉端口导致 403
        proxy_set_header Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    # WebSocket —— 必须原样转发 Host,否则升级被 403(页面能开,
    # 但对话/终端一直重连)
    location /ws {
        proxy_pass http://127.0.0.1:8787;
        proxy_http_version 1.1;
        proxy_set_header Host $http_host;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_read_timeout 3600s;
        proxy_send_timeout 3600s;
    }

    # 构建产物的绝对路径资源/API(根路径,不带 /pi/)
    location /assets/  { proxy_pass http://127.0.0.1:8787; }
    location = /favicon.svg           { proxy_pass http://127.0.0.1:8787; }
    location = /api/file   { proxy_pass http://127.0.0.1:8787; }
    location = /api/health { proxy_pass http://127.0.0.1:8787; }
}

要点:

  • Host 必须用 $http_host(保留端口),/pi/ 和 /ws 都要 —— Origin 校验比较 hostname 和端口。proxy_set_header Host $host 或不设置(默认上游地址 127.0.0.1:8787)都会 403。
  • 同源自动通过:只要浏览器 Origin 与转发后的 Host 一致(普通反代天然如此), 就无需 PI_WEB_ALLOW_ORIGINS;仅当浏览器 Origin 与后端看到的 Host 不同 (如 TLS 终止代理改了端口)才需要设置。
  • 不要开 proxy_protocol(除非确实要真实客户端 IP):它会让 nginx 拒绝所有 不带 PROXY 头的连接,局域网直连和 frp 以外的客户端全挂。用 frp 时同样去掉 transport.proxyProtocolVersion(除非 nginx 也 listen proxy_protocol)。
  • 局域网免代理访问:直接设 PI_WEB_HOST=0.0.0.0(加防火墙规则), 或把上面的 server 块放到 80/443 端口。

带 frp 内网穿透的完整可运行示例:deploy/nginx-subpath.conf。

参与贡献

pi-web-ui 是一个小型开源项目 —— 你的贡献就是它成长的力量。代码、插件、主题、文档、翻译、想法,统统欢迎;每一个合并的 PR 都会随下一次 npm publish 送达所有用户。❤️

贡献方式如何开始
🧩 写插件打造你自己的界面 tab + AI 工具。以 plugins/demo-mailbox 为最小模板(它兼作测试夹具),本地开发后既可开 PR 收录进插件目录,也可独立发布并照样收录(见社区插件)。
🎨 贡献主题以 themes/white.css(浅色)或 themes/cyberpunk.css(深色)为纯调色板模板,调整 :root 配色 + --term-* + .hljs,用 npm run dev 验证后开 PR —— 完整步骤见向仓库贡献主题。
💻 修 bug / 加功能在 Issues 里挑一个,或提出新想法。Fork → 分支 → PR。代码约定见 AGENTS.md(Tab 缩进、i18n 双语 key、协议改动只动 server/protocol.ts)。
📖 文档与翻译完善 README、补插件文档、改错别字,或帮忙把界面/文档翻译成更多语言。
💡 想法与反馈在 Issues 或 Discussions 里开帖 —— 功能建议、bug 报告、界面优化点子、部署经验分享都欢迎。

开 PR 前,快速自检能让维护者更省心:

  • npm run check:protocol + npm test —— 协议同步与单元测试。
  • npm run typecheck —— 无类型错误。
  • npm run build —— 前后端都能编译。
  • 涉及协议改动:server/index.ts 与 web/src/use-chat.ts 两端 dispatch 都要加分支(详见 AGENTS.md「协议单源」)。

喜欢 pi-web-ui?给仓库点个 ⭐,帮助更多人发现它。如果你在上面做了很酷的东西(插件、主题、部署方案),记得告诉我们 —— 我们乐于展示社区作品。

License

MIT