pi-web-ui 0.92.0 → 0.94.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/CHANGELOG.md +74 -2
  2. package/README.md +69 -14
  3. package/README.zh-CN.md +36 -10
  4. package/bin/pi-web-ui.mjs +18 -6
  5. package/dist/server/agent-service.js +577 -127
  6. package/dist/server/auth-cookie.js +26 -0
  7. package/dist/server/claim-files-tool.js +6 -7
  8. package/dist/server/client-state.js +125 -8
  9. package/dist/server/conversation-read-tool.js +2 -1
  10. package/dist/server/delegate-task.js +10 -3
  11. package/dist/server/dsh/dsh-agent-service.js +43 -1
  12. package/dist/server/files-service.js +79 -27
  13. package/dist/server/http-proxy.js +72 -0
  14. package/dist/server/index.js +84 -17
  15. package/dist/server/patch-node-pty.js +11 -0
  16. package/dist/server/plugins.js +1 -0
  17. package/dist/server/protocol-version.js +1 -1
  18. package/dist/server/read-tool.js +37 -3
  19. package/dist/server/resolve-global-sdk.js +72 -0
  20. package/dist/server/sdk-origin.js +64 -0
  21. package/dist/server/serialize.js +59 -21
  22. package/dist/server/settings-service.js +12 -1
  23. package/dist/server/skill-tool.js +2 -1
  24. package/dist/server/soft-cap.js +38 -4
  25. package/dist/server/subagents.js +30 -13
  26. package/dist/server/terminals.js +38 -18
  27. package/dist/server/themes.js +15 -0
  28. package/dist/server/tool-info.js +89 -0
  29. package/dist/server/tool-manager.js +107 -14
  30. package/package.json +2 -2
  31. package/plugins/catalog.json +10 -0
  32. package/themes/ayu-light.css +136 -0
  33. package/themes/catppuccin-latte.css +4 -0
  34. package/themes/catppuccin.css +4 -0
  35. package/themes/codex.css +136 -0
  36. package/themes/cyberpunk.css +4 -0
  37. package/themes/dazzle.css +4 -0
  38. package/themes/everforest-light.css +136 -0
  39. package/themes/geist.css +136 -0
  40. package/themes/gruvbox-light.css +136 -0
  41. package/themes/kanagawa-lotus.css +136 -0
  42. package/themes/md-preview.css +4 -0
  43. package/themes/mist.css +4 -0
  44. package/themes/nord.css +4 -0
  45. package/themes/one-dark.css +4 -0
  46. package/themes/paper.css +4 -0
  47. package/themes/rose-pine-dawn.css +136 -0
  48. package/themes/sakura.css +4 -0
  49. package/themes/solarized-light.css +4 -0
  50. package/themes/tokyo-night.css +4 -0
  51. package/themes/white.css +4 -0
  52. package/web/dist/assets/{TerminalPanel-RACpk6AX.js → TerminalPanel-B-CMQuzm.js} +1 -1
  53. package/web/dist/assets/index-18jK6al2.js +364 -0
  54. package/web/dist/assets/index-B3S9MxnN.css +1 -0
  55. package/web/dist/index.html +2 -2
  56. package/web/dist/assets/index-BgrnP9Jz.js +0 -364
  57. package/web/dist/assets/index-Cy8dSTZt.css +0 -1
package/CHANGELOG.md CHANGED
@@ -10,6 +10,74 @@
10
10
 
11
11
  ## [Unreleased]
12
12
 
13
+ ## [0.94.0] — 2026-09-22
14
+
15
+ ### Added
16
+
17
+ - **复制为图片:预览面板 + 标题 / 边框 / 水印 + 多轮勾选拼接(#274)** — 点「复制为图片」打开右侧停靠面板(不挡对话)。可选标题、边框、自定义水印(默认 `pi-web-ui`);对话里勾选多条消息,按时间线从早到晚竖排拼成一张 2x PNG。面板提供「包含工具调用 / 包含思考过程」两个开关(默认关),勾上后把对应块加进图并强制展开,不改对话里原有折叠状态。超长则降到 1x 或拒绝复制,避免黑图。
18
+ - **压缩软上限(Soft Cap)支持人性化 tokens 单位输入与纯数字智能识别** — 设置「消息显示」页与按模型覆盖的压缩阈值输入框全面支持人类习惯的缩写(如 `300k`、`1.5M`、`300,000`、`300_000`);纯数字且 `<= 1000`(如 `300`、`128`、`64`)自动智能识别为 K tokens(`300` → `300,000`),回显自动格式化为整千/整百万可读缩写,避免手滑漏输 0。
19
+ - **全局跨标签页/重启共享的项目模型与 Provider Key 记忆** — 将项目绑定的模型与服务商密钥提升至全局持久化层(`GLOBAL_SETTINGS_KEY`)。新开标签页、切换工作区或重启浏览器时,确定恢复该项目最后使用的模型与密钥;全新空白会话创建时提前解析并注入目标模型,且在 `setModel` 前优先恢复对应的 provider key,彻底解决新对话鉴权失败与回退内置硬编码模型的问题。
20
+
21
+ ### Changed
22
+
23
+ - **官方插件清单内置为默认来源(`PI_WEB_PLUGIN_CATALOG_URL`)** —— 服务端启动时未配置该环境变量时,自动拉取官方社区清单 `https://xing-shuyin.github.io/pi-web-ui-plugins/catalog.json` 并同步进插件市场列表(**仅更新列表供用户按需安装,不自动安装插件**);显式设为空串或 `off`/`0`/`false`/`no` 可关闭;仅当显式设置 `PI_WEB_PLUGIN_CATALOG_INSTALL=1` 时才在开机时顺手自动安装全部插件(headless/容器预置镜像场景)。
24
+ - **界面交互防选区干扰与遮罩层重绘优化** —— 侧边栏(会话列表、项目列表、文件树)、顶栏、右键菜单、消息头部及技能卡片头部等不可交互文本区域增加 `user-select: none`,防止高频双击或拖拽时意外选中文本;弹窗与文件预览遮罩层移除 `backdrop-filter: blur` 改用纯色半透明实底,并添加 `overscroll-behavior: contain` 与硬件加速,消除滚动穿透并显著降低大消息流时的重绘负担。
25
+
26
+ ### Fixed
27
+
28
+ - **复制为图片浅色主题色差(#273)** — html-to-image 把 `color-mix(...)` / 半透明 `rgba` 画到默认黑画布上,浅色气泡变成深紫、深字叠黑底。导出前把计算色拍成不透明 rgb,画布底用主题 `--card-bg`/`--bg` 实底,并去掉 `backdrop-filter`(否则 SVG 里会变成黑罩)。
29
+
30
+ <!-- auto-i18n:start -->
31
+ ### i18n
32
+
33
+ - 前端新增 key(13):`saveAsImage`、`copyImageBtn`、`savingImage`、`imageTitle`、`imageTitlePlaceholder`、`imageBorder`、`imageWatermark`、`imageWatermarkPlaceholder`、`exportSelectHint`、`exportTooLong`、`exportSelectedCount`、`exportIncludeTools`、`exportIncludeThinking`
34
+ - 前端中文变更(2):`softCapHint`、`softCapOff`
35
+ - 前端英文变更(2):`softCapHint`、`softCapOff`
36
+ <!-- auto-i18n:end -->
37
+
38
+ ## [0.93.0] — 2026-09-21
39
+
40
+ ### Added
41
+
42
+ - **支持 HTTP 代理配置传导(`httpProxy`)** —— 服务端启动时自动读取 pi agent 配置(`~/.pi/agent`)中的 `httpProxy` 设置,并与环境变量 `HTTP_PROXY` / `HTTPS_PROXY` 结合,自动设置 Node.js 内置 fetch 及 undici 的全局代理调度器,确保所有出网 HTTP 请求(模型调用、插件下载等)在代理环境下稳定工作。
43
+ - **可配置的单工具看门狗超时(`toolWatchdogTimeoutMs`)** —— 设置「工具」页新增单工具超时配置,支持自定义单次工具调用的看门狗超时毫秒数(0 表示禁用看门狗;`PI_WEB_TOOL_TIMEOUT_MS` 环境变量只作为默认值;工具自身声明的更长超时如 bash `timeout` 仍获尊重)。
44
+ - **子代理会话持久化落盘(`persist_conversation`)** —— 支持将原本仅存在于内存中的临时子代理会话持久化保存为常规历史会话,方便后续长期回顾与复盘。
45
+ - **工具输出图片查看增强与开关** —— 工具结果中的图片支持点击放大查看,设置「消息显示」页新增「工具图片」开关(`toolImagesEnabled`),可按需控制工具结果中图片的内联显示。
46
+ - **社区插件 multi-git 与社区插件收录机制(PR #271)** —— 插件市场首次收录外部独立维护的社区插件 `multi-git`(多仓库 Git 总览,来源 `EinErste/pi-web-multigit`);文档(README / README.zh-CN)同步增加社区插件章节,规范外部来源声明与安装流程。
47
+ - **社区需求与投票墙插件(`feature-board`)** —— 官方插件库新增 `feature-board` 插件及配套 Cloudflare Worker 后端代码,支持社区用户查看热门功能建议、提交新需求以及投票交互。
48
+ - **工具调用卡片的工具名上右键,就能看这个工具的「定义说明」** —— 在工具卡头部(工具名那一行)右键,选「显示工具详细信息」:弹窗里给出它的说明、系统提示词里的摘要与要点、来源(SDK 内置 / 扩展 / 插件)与当前是否启用,以及**参数表**(参数名 / 类型 / 必填 / 说明,嵌套对象按层级缩进)+ 可折叠的原始 JSON Schema。定义是静态大对象(不进快照、不占上下文),点开时按名现取一次;DSH 引擎拿不到工具定义时明确写「当前引擎不支持」,而不是给一个空窗。右键工具卡不抢浏览器菜单(点在代码块/输入框上、或页面里已选中文字时照旧给系统菜单),也不会顶掉整条消息的右键菜单;新槽位 `contextmenu.toolcall` 同样进了设置 → 「界面布局」页(可隐藏 / 调序),插件也能往这个菜单里加自己的条目。
49
+
50
+ - **read 工具可直接读目录 + 接受 `file_path`** —— 模型把目录路径交给 read 时不再报 `EISDIR`,改为列出目录条目(一行一项、目录带 `/` 后缀,`limit` 此时是条目上限),看目录不必再走 bash 的 `ls`;read 同时也接受 `file_path`(`path` 的别名,两者都给时 `path` 为准)。实现是覆盖内置 read(同名 customTool),文件/图片/不存在的路径行为与原来完全一致;设置 → 工具页新增「read 读目录」开关(默认开),关掉即恢复内置行为。仅 pi 引擎生效(DSH 引擎的工具来自预设,无此覆盖面)。
51
+
52
+ ### Fixed
53
+
54
+ - **Windows 下开启 terminalBash 长期运行不再导致 MSYS2 控制台耗尽死锁(issue #269)** —— 在 Windows 下开启「终端接管 bash」(`terminalBash: true`)时,之前每一次一次性命令(`persist=false`)都会自增创建新的 ConPTY 终端;不仅启动极慢(每次约 1.3s),且子进程退出或异常关闭时通过 Win32 `TerminateProcess` 硬杀会跳过 MSYS2 清理钩子,导致内核命名共享内存 `\cygwin.shared` 中的控制台设备 slot(上限 128)永久泄漏,累积约 128 次后报错 `fatal error - console device allocation failure - too many consoles in use, max consoles is 128` 并导致后续所有 bash 工具全面瘫痪。现在做了三重修复:① Windows 平台开启 `terminalBash` 时,一次性命令(`persist !== true`)自动分流走原生 SDK bash(纯进程基于 pipe,极速 20ms、零控制台设备分配),只有明确需要持久交互(`persist === true`)时才进入常驻可见终端 `ai-bash`(始终复用单个终端,只占 1 个 slot);② 改进伪终端退出机制:子进程已退出时绝不再调 `process.kill(pid)`,直接释放 PTY 句柄;运行中被关闭时先写 `\x03exit\r` 尝试优雅退出再兜底强杀;终端自然 exit、history 淘汰和 `killAll` 时一律安全释放底层 ConPTY 句柄;③ 为 node-pty 的 `conpty_console_list_agent` 增加 try-catch 补丁,进程已死时 `AttachConsole` 失败不再抛出未捕获异常。
55
+ - **流式回复期间不再每帧重算整份会话统计(issue #259)** —— SDK 的 `session.getSessionStats()` 要遍历整份转写,而 `message_delta` 之前**每个流式帧**都调它一次(只为填 `usage`)。实测 6000 条转写的会话跑 6002 帧时,这一条链吃掉了流式阶段 **27.6%** 的 CPU(2123ms)。现在按 250ms 做短缓存(并按键到 session 实例,切换对话不会拿到上一份的读数):实测流式 CPU **4.859s → 1.328s(3.7×)**,快照字节数完全不变。长会话(尤其并行子代理 × 长转写)下卡顿的主因之一。
56
+ - **长会话快照与折叠消息列表不再随子代理并发退化(issue #259)** —— 服务端不再让后台对话的 `tool_execution_end` / `agent_end` 给当前激活对话白刷快照;超过 4096 条转写时,序列化缓存改为只回收已不在当前转写里的死条目,保持消息对象引用稳定,让 `snapshot_delta` 继续生效。客户端折叠摘要行启用 `content-visibility: auto` 并固定占位高度,展开箭头改为纯 CSS,避免每行挂一个 SVG + polyline。6000 条历史消息 + 8 个子代理 × 5 次 bash 的实测:全量快照 **3 条 / 14.925MB → 0 条 / 0MB**,增量快照 **0 条 → 3 条 / 4KB**;折叠行内 SVG/polyline **3990/3990 → 0/0**,`.messages` 内元素约减少 22%。
57
+ - **pi SDK 依赖范围不再把 0.86.x 挡在门外,并说清「服务跑的是自带副本」(issue #260)** —— `package.json` 里 SDK 的范围原本是 `^0.85.1`,而 `^` 对 0.x 的语义是 `>=0.85.1 <0.86.0`:上游发到 0.86.1 也永远装不进来,只会一直用自带的 0.85.1 副本;而 npm 全局安装**不 hoist**(实测),Node 又「嵌套优先于祖先」,所以用户 `npm i -g @earendil-works/pi-coding-agent@latest` 改的是全局那份,服务加载的仍是自带那份 —— 表现为「升了 0.86.1,横幅和 `/api/health` 还显示 0.85.1」。现在范围放宽到 `>=0.85.1 <0.87.0`,并新增 `server/sdk-origin.ts`:启动横幅在检测到「有更新的副本被遮蔽」时给出提示,`/api/health` 新增 `piSdkCopies` 列出所有可解析到的副本(第一项 = 实际生效),README 也写明「升级全局 pi CLI 不会改变本服务运行的 SDK」。**另提供显式开关**:`PI_WEB_SDK=global` 时(issue #260 的另一半诉求)改用祖先链上**更新**的那份副本,否则回落自带副本 —— 默认仍是自带副本,因为不同机器跑不同 SDK 会让 bug 无法复现。
58
+ - **设了 `PI_CODING_AGENT_SESSION_DIR` 的用户不再「历史列得出来、却点不开」** —— 历史/最近项目从这个额外会话根扫盘,而打开 / 删除 / 改名的守卫只认 `<agentDir>/sessions/` 一个根:一点就报「路径不在允许范围内」,删不掉也改不了名。现在打开类操作与**列表同口径**(两个根都认),守卫的意图(只许开会话转录、不许开任意文件)没有放宽 —— 仍然必须是某个会话根下的转录。
59
+ - **`voice-input` 插件补上 `tools` 能力声明** —— 它的 manifest `permissions` 里少了 `tools`,而它要注册 `transcribe_audio` 工具;宿主对工具注册点是**硬门控**(未声明 `tools` 即拒绝注册),所以这个 AI 工具实际上**永远不会出现**在工具列表里,只在插件诊断里留一句话。其余所有注册 AI 工具的插件都声明了它;单测也补上了这条断言(以前没断言,所以缺声明时测试照绿)。输入框旁的 🎤 / 📷 不受影响(那两个走的是界面动作,不是 AI 工具)。
60
+
61
+ - **跨会话弹窗污染** —— 修复了当后台运行的子代理或其他会话触发提问(`ask_user_question`)时,问卷弹窗会无视当前正浏览的对话、强行在全局弹出的问题。现在问卷对话框只会在属于它的会话里弹出(其他会话只会正常出现「?」角标),切换到其他会话时会自动收起,切回原会话时也会自动恢复显示弹窗(仅 pi 引擎,DSH 引擎提问无会话归属保持原状)。
62
+ - **Android / Termux 上的文件面板与「选择目录」能用了(issue #262,PR #263)** —— 三处都是同一个原因的不同表现:① **目录符号链接在所有平台都按目标分类**(原来只有 Windows 分支跟随符号链接,posix 下 `~/storage/shared` 这类链接被判成「文件」):文件树里能进去、不再显示成文件,只列目录的选择对话框也不再是一片空白;② **机器根(「此电脑」)在 `readdir("/")` 被拒时回落**到 `$HOME` 与 `/storage/emulated/0`(Android 上 `ls /` 本身就失败,原来点进去是死路);③ **路径栏支持 `~` 展开**(`completePath` / `makeDir` 早就这么做,`listFiles` 漏了,于是 `~/storage/shared` 被当成工作区相对路径、静默变成空列表)。断链仍回落成文件;搜索的深度上限兼作环保护,Linux / macOS / Windows 行为不变。
63
+ - **`PI_WEB_TOKEN` 含 `=` 等特殊字符时不再「进得去、用不了」(issue #261)** —— 口令里带 `=`(base64 尾巴上最常见)、`+`、空格或非 ASCII 时,浏览器经 `?token=…` 进去那一次是 200,之后**每个资源请求都 401**(页面停在背景色):服务端把口令按 `encodeURIComponent` 写进 cookie(RFC 6265 的 cookie-value 只允许 ASCII,`=` 必须转义),读取时却拿转义后的 `%3D` 去和原文的 `=` 比,永远不相等。现在读取 cookie 时先解码再比(新增 `decodeCookieToken`,脏值解不开就原样返回、不会把请求打成 500),手写 / 旧客户端的明文 cookie 仍然接受;`tests/token-auth-test.mjs` 增加整个特殊字符口令的场景(`?token=` → 仅凭 cookie 导航 → WS 凭 cookie 连接 → 明文 cookie),把修复撤掉即变红。
64
+ - **插件 bundle 的加载作用域不再互相覆盖(issue #268 里定位到的一条真实竞态)** —— 加载插件 bundle 时,「设插件作用域 + import」是**并发**跑的,而作用域是模块级变量:两个 bundle 求值交错时,后启动的那个会把全局作用域改成自己的 id,前一个插件在顶层 / 异步回调(如 notes 插件的 `whenBridge`)里注册的动作就落到**别人**名下(键从 `notes:notes:toggle` 变成 `<别的插件>:notes:toggle`)。宿主派发时按自己的 id 与裸名都查不到 → `kind: "action"` 的条目一点就弹「插件没有接管这个动作」(`kind: "view"` 的条目走视图分支、不过这张表,所以只有 action 中招)。现在两者串成一条闸门(`createScopedImporter`,导出以便单测),单个插件加载失败也不会卡住后面的插件。
65
+ - **认领工具(`claim_files`)补进工具目录 + 设置页开关** —— 之前它是常驻注册、不进 `AGENT_TOOL_CATALOG` 的例外,所以设置 → 工具页里根本找不到它(想关都关不掉)。现在按新增可开关工具的三处走:目录项(默认开,纯 advisory,关掉只少一路事前提醒、事后触碰集照常工作)+ 设置页「其他」组开关行(紧跟「读取别的对话」)+ 中英文案与 8 个语言包同步;工具目录 25→26。仅 pi 引擎(DSH 引擎无 customTool 注册面,提醒里照样能看到认领)。
66
+
67
+ ### Changed
68
+
69
+ - **文件行右键也能「上传文件到当前目录」** —— 上传入口原先只对**目录**行显示,右键一个文件时菜单里根本没有这一项(想往当前目录传文件只能去右键空白处)。现在文件行也给,落点是它所在的目录:当前目录里的文件显示「上传文件到当前目录」,子目录里的文件显示「上传文件到文件夹」;只有机器根(不能往盘符根写)仍然隐藏,文件树右键菜单的其余条目不变。
70
+
71
+ <!-- auto-i18n:start -->
72
+ ### i18n
73
+
74
+ - 前端新增 key(34):`themeLight`、`themeDark`、`quickPhrasesSendTip`、`persistSubagent`、`toolImages`、`toolImagesDesc`、`toolImageZoom`、`toolWatchdogTimeout`、`toolWatchdogTimeoutDesc`、`toolWatchdogOff`、`uiLayoutContextToolcall`、`pluginSettingsTitle`、`pluginSettingsShow`、`pluginSettingsHide`、`claimFilesEnabledDesc`、`claimFilesOffHint`、`toolInfoMenuLabel`、`toolInfoTitle`、`toolInfoLoading`、`toolInfoUnsupported`、`toolInfoMissing`、`toolInfoActive`、`toolInfoInactive`、`toolInfoSource`、`toolInfoDescription`、`toolInfoNoDescription`、`toolInfoPromptSnippet`、`toolInfoGuidelines`、`toolInfoParams`、`toolInfoParamsNone`、`toolInfoSchemaDropped`、`toolInfoRawSchema`、`toolInfoRequired`、`toolInfoFootnote`
75
+ - 前端中文变更(1):`elsewhereTip`
76
+ - 前端英文变更(1):`elsewhereTip`
77
+ - 服务端新增 key(1):`agent.conv.limit.reached`
78
+ - 服务端文案变更(2):`subagents.spawn.started`、`subagents.list.empty`
79
+ <!-- auto-i18n:end -->
80
+
13
81
  ## [0.92.0] — 2026-09-20
14
82
 
15
83
  ### Added
@@ -17,7 +85,7 @@
17
85
  - **插件设置的 `select` 候选值可由宿主现算(`optionsFrom`)** —— manifest `settings` 里写 `"type": "select", "optionsFrom": "models" | "thinkingLevels"` 即可让宿主在浏览器侧现算候选值:模型列已配置鉴权的模型(值 `provider/id`,标签同设置面板的模型选择器)、思考强度列 SDK 档位(`off`…`max`,文案走 `thinking.<值>`);两者自动带一个空值选项 = 跟随全局默认,插件不用自己维护会过期的静态表。服务端不校验这类值(清单在浏览器侧、随配置变化),只留 200 字符长度护栏,非法值由用的时候(如 `host.chat` 切模型)报错;当前存值不在清单里(模型被删/手改过 storage.json)时也保留,不被下拉静默吃掉。
18
86
  - **自定义模型提供商「补参数」支持随时中断与实时进度反馈** —— 模型配置面板中点击「补参数」后,新增实时进度显示(下载 OpenRouter / models.dev 目录、抓取依据网页、逐个匹配参数 N/M 与百分比),并提供「✕ 取消」按钮;点击取消后服务端立即截断网络连接与批处理,并自动保留中断前已匹配的模型行,避免弱网时无响应或无法停止。
19
87
  - **微信通道(wechat-ilink)设置里的「模型」「思考强度」改下拉选择** —— 旧版是手打 `provider/id` 文本框,打错要到微信里跑完一轮才发现(切换失败)。现在从清单里选,空 = 跟随全局默认。
20
- - **read 工具可直接读目录** —— 模型把目录路径交给 read 时不再报 `EISDIR`,改为列出目录条目(一行一项、目录带 `/` 后缀,`limit` 此时是条目上限),看目录不必再走 bash 的 `ls`。实现是覆盖内置 read(同名 customTool),文件/图片/不存在的路径行为与原来完全一致;设置 → 工具页新增「read 读目录」开关(默认开),关掉即恢复内置行为。仅 pi 引擎生效(DSH 引擎的工具来自预设,无此覆盖面)。
88
+ - **read 工具可直接读目录** —— 模型把目录路径交给 read 时不再报 `EISDIR`,改为列出目录条目(一行一项、目录带 `/` 后缀,`limit` 此时是条目上限),看目录不必再走 bash 的 `ls`。实现是覆盖内置 read(同名 customTool),文件/图片/不存在的路径行为与原来完全一致;read 也因此接受 `file_path`(`path` 的别名,两者都给时 `path` 为准)。设置 → 工具页新增「read 读目录」开关(默认开),关掉即恢复内置行为。仅 pi 引擎生效(DSH 引擎的工具来自预设,无此覆盖面)。
21
89
  - **浏览器扩展(page-picker):点一次图标就能看见「让 AI 操作本页」** —— AI 授权入口原来只挂在拾取**确认条**里(必须先在页面上点一个元素它才出现,「只想授权」的人白点一下)。现在拾取态底部常驻一条细条:直接显示本页授权状态(未授权 / 已授权 / 「AI 操作页面」总开关关着 / 查不到后台),并给出「让 AI 操作本页…」「与另一页配对…」「退出」;在扩展设置页点完「授权该页面」回到那个页面,细条自己变成「已授权 · 模型可操作本页」(扩展监听授权表变化,不用重新点图标、不用刷新)。细条只有按钮可点,其余区域点击照旧穿透到页面元素 —— 不影响拾取手感。
22
90
  - **AI 可以主动把文件「拿给你看」(`present_files`)** —— 新工具让模型把产物直接推到对话里成卡片:图片、视频、音频**在消息内直接显示/播放**(不折叠、不用点),文本/代码/Markdown/HTML 给开头摘录 + 「预览」按钮开文件预览弹窗(行号、选区、加进对话都在那边),不能内联的(PDF/二进制)只给下载与本地打开;每一行都带「预览 / 本地打开(用默认应用打开文件)/ 在文件夹中显示 / 下载 / 复制路径」,其中「本地打开」「在文件夹中显示」与右栏文件树右键菜单**同一套协议**(服务器跑在别的机器上时由服务端明确提示不支持,不是默默没反应);路径不存在时卡片直接标红说明,不会给你一个点不动的东西。模型还能把某个文件标成「先看这个」,配合设置 → 消息显示新增的「自动打开 AI 展示的预览」开关(默认关)就能自动把预览窗弹出来(只对刚发生的卡片生效,翻旧会话不会突然弹窗)。工具目录 24→25(默认开,**设置 → 工具页有独立开关**,可随时关掉)。仅 pi 引擎(DSH 引擎的工具来自预设,无此覆盖面)。
23
91
 
@@ -35,11 +103,13 @@
35
103
  - **插件声明式设置表单改成单列行式布局** —— 旧版是 `auto-fit` 网格 + `space-between`:窄列时长标签被逐字挤成**竖排**(如「允许的用户默认工作空间」一个字一行),勾选框被甩到行最右端、与标签断开,输入框/下拉/数字框宽度也各自为政。现在统一为「标签固定左列(不压缩、超长省略号 + 悬浮看全名)+ 控件右列(文本/下拉 420px、数字 120px、勾选框贴标签)」,行间细分隔线;`hint` 从只挂 `title` tooltip 改为**常显在标签下的小字**(最多两行);窄窗口(≤720px)标签与控件上下堆叠。纯渲染层改动,manifest `settings` schema、`plugin_settings` 协议与既有 class 名(`.plugin-settings-field/-save/-reset/-form`)均未变。
36
104
 
37
105
  <!-- auto-i18n:start -->
106
+
38
107
  ### i18n
39
108
 
40
109
  - 前端新增 key(45):`setGlobalDefault`、`clearGlobalDefault`、`globalDefaultBadge`、`themeGroupClassics`、`themeGroupBuiltin`、`scmHistoryFilterPlaceholder`、`scmHistoryFilterTip`、`scmHistoryFilterEmpty`、`scmCommitHistoryTip`、`antigravityTemplateTitle`、`antigravityTemplateDesc`、`antigravityFillOpenAI`、`antigravityFillAnthropic`、`enrichModels`、`enrichModelsHint`、`enrichHintPh`、`enrichingModels`、`enrichModelsCancel`、`enrichModelsAbort`、`enrichCancelling`、`enrichModelsCancelled`、`enrichModelsOk`、`enrichModelsErr`、`enrichModelsNeedIds`、`readDirEnabled`、`readDirEnabledDesc`、`pluginMenuTitle`、`pluginMenuPin`、`pluginMenuUnpin`、`pluginMenuReorder`、`pluginMenuReorderHint`、`pluginMenuManage`、`pluginMenuEmpty`、`pluginMenuNoView`、`uiLayoutRequired`、`pluginSettingsInherit`、`presentOpenLocal`、`presentMissing`、`presentEmpty`、`presentAutoOpen`、`presentAutoOpenDesc`、`presentFilesEnabledDesc`、`presentFilesOffHint`、`skillEnabledDesc`、`skillOffHint`
41
110
  - 服务端新增 key(45):`claimfiles.no.store`、`claimfiles.list.empty`、`claimfiles.list.ttl`、`claimfiles.list.head`、`claimfiles.release.all`、`claimfiles.bad.paths`、`claimfiles.bad.outside`、`claimfiles.claim.ok`、`claimfiles.claim.conflict`、`claimfiles.claim.noop`、`claimfiles.release.paths`、`claimfiles.bad.action`、`convread.read.query.head`、`convread.read.chat.note`、`convread.list.bad.kind`、`convread.list.running.more`、`convread.list.history.more`、`convread.list.head.running`、`convread.list.head.history`、`convread.list.head.all`、`convread.read.bad.view`、`convread.read.query.empty`、`convread.files.empty`、`convread.files.more`、`convread.files.head`、`convread.files.claims`、`convread.status.head`、`convread.status.last.tool`、`convread.status.no.tool`、`convread.status.last.say`、`convread.status.no.say`、`convread.status.touched`、`convread.status.touched.none`、`convread.status.waiting`、`convread.status.claims`、`models.enrich.empty`、`models.enrich.cancelled`、`present.files.result.head`、`present.files.result.kindDir`、`present.files.result.missing`、`present.files.result.tail`、`present.files.result.allMissing`、`present.files.result.disabled`、`present.files.result.noItems`、`read.dir.header`
42
111
  - 服务端文案变更(1):`convread.bad.action`
112
+
43
113
  <!-- auto-i18n:end -->
44
114
 
45
115
  ## [0.91.0] — 2026-09-19
@@ -1123,7 +1193,9 @@ when?, children?}`,也收 `topbar` / `settings` 这类简写别名);宿主
1123
1193
  - 0.35.1(2026-08-27):编辑重问保留附件(#18)+ 全窗口拖放(#19)。
1124
1194
  - 0.29.0(2026-08-23):全局搜索弹窗(Ctrl+K)+ 消息列表惰性窗口化。
1125
1195
 
1126
- [Unreleased]: https://github.com/xing-shuyin/pi-web-ui/compare/v0.92.0...main
1196
+ [Unreleased]: https://github.com/xing-shuyin/pi-web-ui/compare/v0.93.0...main
1197
+ [0.94.0]: https://github.com/xing-shuyin/pi-web-ui/releases/tag/v0.94.0
1198
+ [0.93.0]: https://github.com/xing-shuyin/pi-web-ui/releases/tag/v0.93.0
1127
1199
  [0.92.0]: https://github.com/xing-shuyin/pi-web-ui/releases/tag/v0.92.0
1128
1200
  [0.91.0]: https://github.com/xing-shuyin/pi-web-ui/releases/tag/v0.91.0
1129
1201
  [0.90.1]: https://github.com/xing-shuyin/pi-web-ui/releases/tag/v0.90.1
package/README.md CHANGED
@@ -70,7 +70,7 @@ QQ群 1126050727
70
70
  - **Streaming agent chat over WebSocket** — the pi SDK runs in-process; events are pushed as snapshots (60 ms throttled) and the browser renders them.
71
71
  - Thinking blocks, tool-call cards and bash outputs with live status (running → finished · waiting for the model · duration).
72
72
  - **Steer (follow-up queueing)** — send a follow-up while the agent is replying; it is queued and injected as soon as the current turn's tool calls settle (the "Interrupt" equivalent of the pi CLI).
73
- - **Slash commands** — `/` opens a command picker (built-in / extension / template / skill); built-ins include `/new /model /compact /cwd /thinking /resume`, plus `/help` (command list) and `/copy` (copy last reply). `/new` takes an optional first prompt (`/new fix the failing test`) and sends it as the new chat's first message.
73
+ - **Slash commands** — `/` opens a command picker (built-in / extension / template / skill); the built-ins are `/new /name /model /compact /cwd /thinking /resume /reload`, plus `/help` (command list), `/copy` (copy last reply) and `/pi-web-ui:quit` (stop the server). `/new` takes an optional first prompt (`/new fix the failing test`) and sends it as the new chat's first message.
74
74
  - **Multiple conversations per project** — each conversation gets its own agent runtime and keeps running in the background after you switch away; the "Running conversations" list shows stream progress and lets you switch back.
75
75
  - **Edit & re-ask** — fork any past question into a new branch and re-prompt; the original conversation stays untouched.
76
76
  - Long threads auto-collapse messages older than 30 into lazy summary rows (click to expand).
@@ -104,7 +104,7 @@ QQ群 1126050727
104
104
  ### 🤖 Subagents & templates
105
105
 
106
106
  - **First-party subagents** — spawn independent background conversations for parallel exploration / implementation / review (`subagent_spawn`, with optional `model` override or a template's model); collect results without polling via `subagent_wait_all` (blocks until every subagent finishes, then summarizes results/errors). Manage them like a chat right in the left panel: view live output, inject follow-ups (steer), abort, dismiss — failed runs surface a red dot in the running list and an error notice in the main chat. In-memory sessions — they never touch the history / resume list, and can be nested.
107
- - **Subagent templates** — configure reusable presets in Settings → Subagent templates: a role system prompt (append or replace), skills & extensions whitelists, an optional per-template model, and an optional thinking level. The AI picks one via the `subagent_templates` tool and `subagent_spawn(template="…")`, or spawns without one (default = follow the main conversation's current model **and thinking level**, or the global default subagent model set in the same panel). A template that sets them pins that exact combination (unsupported thinking levels are clamped by the SDK to the nearest one the model supports). Disabled templates stay in the panel for re-enabling but become invisible to the AI tools (can't be listed or picked). Templates are shared globally across browser clients (`<dataDir>/subagent-templates.json`). Six built-in templates (review / implement / research / scout / audit / delegate, adapted from the pi-subagents community projects) seed the list on first run — marked 「Built-in」, editable and deletable like any other.
107
+ - **Subagent templates** — configure reusable presets in Settings → Subagent templates: a role system prompt (append or replace), skills & extensions whitelists, an optional per-template model, and an optional thinking level. The AI picks one via the `subagent_templates` tool and `subagent_spawn(template="…")`, or spawns without one (default = follow the main conversation's current model **and thinking level**, or the global default subagent model set in the same panel). A template that sets them pins that exact combination (unsupported thinking levels are clamped by the SDK to the nearest one the model supports). Disabled templates stay in the panel for re-enabling but become invisible to the AI tools (can't be listed or picked). Templates are shared globally across browser clients (`<dataDir>/subagent-templates.json`). Thirteen built-in templates seed the list on first run — marked 「Built-in」, editable and deletable like any other: review / implement / research / scout / audit / delegate (adapted from the pi-subagents community projects) and oracle / librarian / explore / metis / momus / multimodal-looker / sisyphus-junior (ported from oh-my-pi's built-in agents).
108
108
 
109
109
  ### 🖼️ Files, images & attachments
110
110
 
@@ -151,7 +151,7 @@ QQ群 1126050727
151
151
 
152
152
  ### 🧩 Agent tools & inline markers
153
153
 
154
- - **Tool switches** — Settings → Tools lists every optional agent tool as its own switch: the 7 terminal tools (default **off**), the 7 `subagent_*` tools (default on), `edit_soft` (default off), `delegate_task`, `ask_user_question` and `todo_list` (default on). Toggling is live (no reload) and the tools stay registered so they can come back; `bash` and the SDK's own `edit`/`read` are deliberately outside the catalog and cannot be disabled.
154
+ - **Tool switches** — Settings → Tools lists every optional agent tool as its own switch: the 7 terminal tools (default **off**), the 7 `subagent_*` tools (default on), and the other 11 — `edit_soft` and `browser_page` (default off), `delegate_task`, `ask_user_question`, `todo_list`, `conversation_read`, `present_files`, `skill`, `schedule_task`, `schedule_list` and `schedule_cancel` (default on). Toggling is live (no reload) and the tools stay registered so they can come back; `bash` and the SDK's own `edit`/`read` are deliberately outside the catalog and cannot be disabled.
155
155
  - **Inline markers** — instead of a tool round-trip the AI writes state changes straight into its reply: `[[todo:new:<subject>]]` / `[[todo:set:<id>,in_progress]]` / `[[todo:remove:<id>]]` / `[[todo:dep:<id>,blocks=<id>]]` for the task list, `[[notify:<level>:<message>]]` for a non-interruptive notice, and `[[conv:rename:<title>]]` to retitle the chat. Markers are applied as soon as a reply bubble is final, a bad marker comes back as a browser notice, and the task list also renders as a live widget under the file tree (`N/M done` with ✓ / ◐ / ○) that follows the active conversation and survives a reload — it is stored in that conversation's own session branch. Settings → Tools has a master switch plus one switch per marker (these are global, shared by all browsers).
156
156
  - **`edit_soft`** — a looser `edit` (default off) for when indentation or whitespace makes the built-in tool fail: exact substring first, then trimmed line-core matching, `newText` written verbatim with the file's line endings/BOM preserved, and a diff + unified patch in the result. It also tolerates sloppy input (a JSON string, a bare object, legacy top-level `oldText`/`newText`).
157
157
  - **`delegate_task`** — hands a specialist template a six-section brief (TASK / EXPECTED OUTCOME / REQUIRED TOOLS / MUST DO / MUST NOT DO / CONTEXT) validated on the server: a missing template, a task under 20 characters or any empty section is rejected, and the error tells the model which templates it may use. Cards render the brief as labelled sections, and a finished delegation gets a button that jumps to the subagent's conversation.
@@ -209,7 +209,7 @@ QQ群 1126050727
209
209
  - Background-task panel — servers launched by the agent are detected by diffing the listening ports before and after a bash run and listed with port / pid / name / command (click the command to expand it fully); stop one or kill all, and the top-bar chip carries a live count badge.
210
210
  - The list belongs to the browser client, not the conversation: it survives project switches, conversation switches and reconnects, and is refreshed server-side every 30 s with processes that exited pruned. Detection deliberately ignores known desktop apps and processes whose parent chain traces back to `explorer` rather than to the server, so a browser you opened yourself isn't reported as “started by the agent”.
211
211
  - Plugin-registered tasks show a 🧩 marker and their live status text, and stop through the plugin's own callback (a mail-polling task, for instance).
212
- - Tool watchdog — a tool call running over 20 minutes is aborted automatically (`PI_WEB_TOOL_TIMEOUT_MS`; questionnaires are exempt).
212
+ - Tool watchdog — a tool call running over 20 minutes is aborted automatically (adjustable in Settings → Tools, 0 = disable; `PI_WEB_TOOL_TIMEOUT_MS` only sets the default; a tool that declares its own longer timeout, e.g. bash `timeout`, is honoured). Questionnaires are exempt.
213
213
  - **Stop bash command only** — abort a running bash tool without killing the conversation.
214
214
  - **Stall warning** — if a streaming run goes completely silent for 3 minutes (`PI_WEB_STALL_NOTIFY_MS`, `0` = off) you get a warning naming the conversation, without aborting it.
215
215
 
@@ -223,7 +223,7 @@ QQ群 1126050727
223
223
  - **File boundaries** — workspace-relative reads/writes reject `..` escapes (a path outside the workspace is only reachable through explicit absolute / machine browsing); inline `/api/file` streaming is limited to images, video and HTML, so a binary can never be smuggled through an `<img>` tag — anything else needs `?download=1` (attachment disposition). The HTML preview route is always served sandboxed.
224
224
  - Quiesce drain mode via a local control socket (`server status|quiesce|unquiesce`) — refuses new prompts/forks/resumes (and, on the DSH engine, brand-new client connections) while in-flight runs finish.
225
225
  - Credentials stay server-side — provider headers (which may carry `Authorization`) are never sent to the browser, and provider API keys reach it only as nicknames.
226
- - 9 UI languages — Chinese/English built in, plus 8 downloadable packs (German, Spanish, French, Italian, Japanese, Korean, Portuguese, Russian); the top-bar language menu installs or removes packs — see [Languages & language packs](#-languages--language-packs).
226
+ - 10 UI languages — Chinese/English built in, plus 8 downloadable packs (German, Spanish, French, Italian, Japanese, Korean, Portuguese, Russian); the top-bar language menu installs or removes packs — see [Languages & language packs](#-languages--language-packs).
227
227
  - **Retention** — uploaded files older than `PI_WEB_UPLOAD_RETENTION_DAYS` (14; `0` = never) are swept at startup and every 6 h; DSH sessions have their own 90-day sweep.
228
228
  - **Operational watchdogs** — tool timeout, model-stall warning and terminal liveness are all tunable, see [Tuning & advanced environment variables](#tuning--advanced-environment-variables).
229
229
 
@@ -231,7 +231,7 @@ QQ群 1126050727
231
231
 
232
232
  - Foreground, global npm install, Docker (see [Docker](#docker)), macOS launchd, Linux systemd, Windows autostart (a per-user `Run` key with a console-free launcher and a crash watchdog), and a desktop shortcut (`server shortcut`).
233
233
  - `server install --print` prints the launchd plist / systemd unit / Windows launcher it _would_ write and exits, so you can review it before installing.
234
- - **Update panel** — the version chip shows an amber dot when a newer web UI exists and a badge with how many _other_ components have updates. “Check all updates” compares the web UI, the globally installed pi core and the direct packages declared in `<agentDir>/npm/package.json`; each row has its own Update, plus “Update all” and “Re-check all”, and the commands run in a visible terminal (`pi update npm:<name>` for pi extensions — the only command that updates the copy pi actually loads — and `npm i -g <name>@latest` for the rest). A “just published (<30 min)” warning tells you npm's cached metadata may be stale. On an instance owned by launchd/systemd/the Windows watchdog there is also a **Restart service** button; on a foreground instance there isn't, because nothing would bring it back.
234
+ - **Update panel** — the version chip shows an amber dot when a newer web UI exists and a badge with how many _other_ components have updates. “Check all updates” compares the web UI, the globally installed pi core and the direct packages declared in `<agentDir>/npm/package.json`; each row has its own Update, plus “Update all” and “Re-check all”, and the commands run in a visible terminal (`pi update npm:<name>` for pi extensions — the only command that updates the copy pi actually loads — and `npm i -g <name>@latest` for the rest). A “just published (<30 min)” warning tells you npm's cached metadata may be stale. On an instance owned by launchd/systemd/the Windows watchdog there is also a **Restart service** button; on a foreground instance there isn't, because nothing would bring it back. **Note on the pi core row:** pi-web-ui **ships and loads its own copy** of the pi SDK, so updating the globally installed pi CLI does _not_ change the SDK this server runs — upgrade pi-web-ui for that (the startup banner and `/api/health` print every copy they can resolve, and say so when a newer one is shadowed, issue #260).
235
235
  - **Plugin updates from the CLI** — `pi-web-ui plugins --check-updates` compares each installed plugin's recorded commit with the remote HEAD and prints the exact update command; every `install --force` snapshots the outgoing version into `<dataDir>/plugin-backups/` (newest 3 kept, and it auto-rolls back if the copy fails), so `pi-web-ui plugins --rollback <id>` can undo an upgrade.
236
236
  - In the pi CLI there is also `/webui` (from the bundled `extensions/webui.ts`): `/webui` starts a server on the first free port from 8787, and `/webui --port 9000`, `--cwd <path>`, `--no-browser`, `status` and `stop` manage it — one subprocess per pi session, killed when the session shuts down so no orphan servers linger.
237
237
 
@@ -282,6 +282,16 @@ npx pi-web-ui # or run without installing (latest, starts on :87
282
282
  npm i -g . # or install the local checkout
283
283
  ```
284
284
 
285
+ > **Which pi SDK does it run?** pi-web-ui depends on `@earendil-works/pi-coding-agent` and
286
+ > loads **its own** copy (npm nests global-install dependencies, and Node resolves the nested
287
+ > copy first). Upgrading the global pi CLI — or clicking Update in the update panel's pi core
288
+ > row — therefore does **not** change the SDK the server runs; upgrade pi-web-ui instead.
289
+ > Run `pi-web-ui` and read the `pi SDK` line, or `curl /api/health`, to see the copy in use
290
+ > (`piSdkCopies` lists every copy that resolves, first = effective). If you really want the
291
+ > server to follow a newer globally installed SDK, start it with **`PI_WEB_SDK=global`** — it
292
+ > then resolves to the nearest ancestor copy that is newer than the bundled one (and falls
293
+ > back to the bundled copy when there is none, e.g. desktop builds).
294
+
285
295
  **npm ≥ 12?** npm 12+ blocks dependency install scripts by default (you'll see
286
296
  `npm warn install-scripts … blocked`). node-pty is a native module, so allow its
287
297
  script (the other two packages it lists are harmless no-ops — allowing them just
@@ -306,8 +316,22 @@ random free loopback port and opens a window pointed at it (see
306
316
  fight over port `8787`, separate data directory, both can run side by side.
307
317
 
308
318
  **Nothing is code signed yet**: on Windows SmartScreen shows an “unknown
309
- publisher” prompt, and on macOS you have to right-click → **Open** the app the
310
- first time (Gatekeeper is stricter than SmartScreen) — see the
319
+ publisher” prompt. macOS needs its own note: the bundle is only ad-hoc signed
320
+ (no Developer ID, no notarization) _and_ the download carries a
321
+ `com.apple.quarantine` attribute, so Gatekeeper reports it as **“damaged and
322
+ can't be opened”** rather than “unidentified developer” — which means the usual
323
+ right-click → **Open** does **not** get you past it. Clear the attribute once
324
+ instead:
325
+
326
+ ```bash
327
+ xattr -dr com.apple.quarantine /Applications/pi-web-ui-desktop.app
328
+ ```
329
+
330
+ This affects **both** manual install paths — the `.dmg` you drag the app out of,
331
+ and the `.zip` you unpack yourself: the quarantine attribute is inherited by
332
+ the extracted `.app` either way. The in-app updater is unaffected, because it
333
+ runs the `.zip` through `electron-updater`, whose Squirrel helper clears the
334
+ attribute itself (`clearQuarantineForDirectory:`) — see the
311
335
  [code signing policy](#-code-signing-policy). Build it locally with
312
336
  `npm run desktop:dist`.
313
337
 
@@ -427,10 +451,10 @@ socket drives `quiesce`/`unquiesce`.
427
451
 
428
452
  - **macOS** → launchd agent (no sudo), logs to `/tmp/pi-web-ui.log` / `.err`
429
453
  - **Linux** → systemd unit (`systemctl enable --now`), logs via `journalctl -u pi-web-ui -f`
430
- - **Windows** → Task Scheduler logon task (hidden PowerShell window, no black console)
454
+ - **Windows** → per-user logon `Run` key (HKCU, no admin needed) with a wscript launcher that runs hidden (no black console) and a 10 s crash watchdog (PID recorded under `%APPDATA%\pi-web-ui\`)
431
455
 
432
456
  Options: `--port` (default 8787), `--cwd` (workspace), `--data-dir` (sessions),
433
- `--engine <pi|dsh>`, `--host`, `--agent-dir`, `--name` (custom service name). Rerunning
457
+ `--engine <pi|dsh>`, `--host`, `--agent-dir`, `--name` (custom service name), `--print` (print the generated config and exit without installing). Rerunning
434
458
  `server install` with new options regenerates the config and restarts the service — that's how
435
459
  you change its port/cwd/engine. `--engine` / `--host` / `--agent-dir` are baked into the service
436
460
  automatically; env-only vars (`PI_WEB_TOKEN`, `PI_WEB_DSH_*`) must be added to the service config
@@ -489,6 +513,11 @@ straight from GitHub:
489
513
  | 📊 [mermaid](https://github.com/xing-shuyin/pi-web-ui/tree/main/plugins/mermaid) | Renders ` ```mermaid ` fences in chat messages as SVG diagrams (fenced-code renderer plugin, offline-first local engine). |
490
514
  | 🧭 [run-trace](https://github.com/xing-shuyin/pi-web-ui/tree/main/plugins/run-trace) | Run trajectory: task → thinking → tools → file changes → result timeline with replay and node details. |
491
515
  | 📖 [legado-web](https://github.com/xing-shuyin/pi-web-ui/tree/main/plugins/legado-web) | Legado book reader (📖 阅读): search / discovery / book info / TOC / chapter reading on top of Android-compatible **book sources**, with source import, health checking and dead-source cleanup, and four agent tools (`legado_rules`, `legado_book_sources`, `legado_source_probe`, `legado_run_rule`) plus an “🤖 AI fix this source” button that opens a new chat with the failure context. Sources/shelf/progress persist under `<dataDir>/legado-web/`. |
516
+ | 💬 [wechat-ilink](https://github.com/xing-shuyin/pi-web-ui/tree/main/plugins/wechat-ilink) | WeChat channel (ilink protocol, same origin as Tencent's openclaw-weixin): QR-code login plus outbound long-polling, so you can drive the agent straight from WeChat — no public IP needed. |
517
+ | 🎤 [voice-input](https://github.com/xing-shuyin/pi-web-ui/tree/main/plugins/voice-input) | Voice input: a mic button next to the composer dictates through the browser's speech recognition; when that is unsupported or fails it falls back to server-side transcription (a remote API, or a one-click local Whisper that runs offline). |
518
+ | 🌐 [live-preview](https://github.com/xing-shuyin/pi-web-ui/tree/main/plugins/live-preview) | Live-Server-style preview: `/liveserver` serves HTML with relative assets and auto-reload, `/md` renders Markdown; the real server stays loopback-only and is reached through host proxy prefixes. |
519
+ | 🖼 [image-toolkit](https://github.com/xing-shuyin/pi-web-ui/tree/main/plugins/image-toolkit) | Image workbench: compress (binary search toward a target size), crop, resize, rotate/flip, format conversion (PNG/JPEG/WebP/AVIF), batch ZIP export, watermark, filters, image info + EXIF — read/write straight into the workspace, with 4 agent tools. |
520
+ | 📓 [notes](https://github.com/xing-shuyin/pi-web-ui/tree/main/plugins/notes) | Notes, todos and reminders in one draggable floating panel (position/size/settings live in the panel, no separate tab); reminders fire server-side (survive restarts, delivered on next open), with 5 agent tools and `/note` `/todo` `/remind` quick capture. |
492
521
 
493
522
  `plugins/demo-mailbox` stays in the repo as the minimal plugin template (server entry + client view + two-way message protocol) and test fixture — start there if you want to write your own.
494
523
 
@@ -509,6 +538,27 @@ list with a one-line PR to `plugins/catalog.json`.
509
538
  Each plugin's directory in the repo has its own `README.md` with full feature
510
539
  lists, configuration and per-plugin caveats.
511
540
 
541
+ ### Community plugins
542
+
543
+ The catalog is not limited to this repository: an entry's `source` may point at any GitHub
544
+ repository (`owner/repo`, an `owner/repo/subdir` inside a monorepo, either with an optional
545
+ `#ref`), so a plugin that is developed, released and supported elsewhere can still be listed in
546
+ the market and installed exactly like the ones above — same install / update / rollback
547
+ lifecycle, same `<dataDir>/plugins/<id>/` layout, `config.json` preserved across updates.
548
+
549
+ The code is fetched from that repository at install time, not vendored here: a community entry
550
+ is a pointer, and its license, issues and release cadence belong to its author. Put a `#ref` in
551
+ the `source` if you want a pinned revision.
552
+
553
+ | Plugin | What it does |
554
+ | ------ | ------------ |
555
+ | 🌿 [multi-git](https://github.com/EinErste/pi-web-multigit) | Multi-repository Git overview: changes, diffs, history, branches, stashes, cross-repo search, a timeline and per-file rollback for every repository below the project directory, plus a workspace-wide branch view, Fetch/Pull (fast-forward only) and an optional PTY terminal. Read-only otherwise. |
556
+
557
+ Getting listed is the same one line as any other entry — an entry in `plugins/catalog.json` plus a
558
+ PR. Without a PR you can register the plugin locally in the market (stored in
559
+ `<dataDir>/plugin-catalog.json`), or point the market at a catalog document you host yourself
560
+ with `pi-web-ui install --catalog <url>`.
561
+
512
562
  ### Installing
513
563
 
514
564
  From GitHub (any of these source forms):
@@ -600,7 +650,7 @@ truncated text. An optional element screenshot rides along as a chat attachment.
600
650
 
601
651
  Each theme is a **pure `:root` palette override** — a small CSS file that only sets CSS variables (see the `:root` block in `web/src/styles.css` for the full variable list: base colors `--bg/--accent/--term-*` plus derived colors like `--tooltip-bg/--code-bg/--notice-*`). The layout lives ONLY in the bundled `web/src/styles.css`; picking a theme overrides the variables, so every theme works with every build and layout changes never touch themes. Built-in themes are generated by `node make-light-theme.mjs`.
602
652
 
603
- Built-in themes ship in the npm package (`themes/`): `white` (light), `cyberpunk` / `dazzle` (dark), and `translucent` / `transparent` (wallpaper-friendly, pair with a chat wallpaper). The theme picker lives in the top bar (🌞 icon); the current choice is stored per browser in `localStorage`.
653
+ Built-in themes ship in the npm package (`themes/`, 23 palettes). The picker shows the named palettes (`nord`, `tokyo-night`, `catppuccin`, `one-dark`, `solarized-light`, `geist`, `ayu-light`, …) under a **Classics** heading, then the built-in presets under **Original**: `white` / `mist` / `paper` / `sakura` (light), `cyberpunk` / `dazzle` / `dark-teal` (dark), `md-preview`, and the wallpaper-friendly `translucent` / `transparent` (pair with a chat wallpaper). The theme picker lives in the top bar (🌞 icon); the current choice is stored per browser in `localStorage`.
604
654
 
605
655
  ### Using a theme
606
656
 
@@ -644,7 +694,7 @@ All optional — the defaults are what the app is developed against. Full refere
644
694
 
645
695
  | Variable | Default | What it changes |
646
696
  | ------------------------------ | ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
647
- | `PI_WEB_TOOL_TIMEOUT_MS` | `1200000` (20 min) | Per-tool-call watchdog; a tool still running is aborted (`ask_user_question` is exempt). |
697
+ | `PI_WEB_TOOL_TIMEOUT_MS` | `1200000` (20 min) | Per-tool-call watchdog; a tool still running is aborted (`ask_user_question` is exempt). Default only — the Settings → Tools field wins. |
648
698
  | `PI_WEB_STALL_NOTIFY_MS` | `180000` (3 min) | Warn — without aborting — when a streaming run produces no event at all; `0` disables. |
649
699
  | `PI_WEB_TERMINAL_IDLE_MS` | `15000` | Nudge the AI when a terminal it opened goes silent for this long; `0` disables. |
650
700
  | `PI_WEB_TERMINAL_IDLE_LINES` | `10` | How many trailing terminal lines that nudge quotes back (1–500). |
@@ -659,7 +709,12 @@ All optional — the defaults are what the app is developed against. Full refere
659
709
  | `PI_WEB_LOCALE_BASE_URL` | GitHub raw | Where language packs are downloaded from — point it at a mirror for offline/intranet installs. |
660
710
  | `PI_WEB_PKG_ROOT` | auto | Overrides where the server looks for `package.json`, `themes/`, `plugins/catalog.json` and `web/dist` (non-standard install layouts). |
661
711
  | `PI_CODING_AGENT_SESSION_DIR` | empty | Flat session layout for pi instead of `<agentDir>/sessions/--<cwd>--/` (changes what the history list reads). |
662
- | `DSH_*` | — | DSH runtime knobs: `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`. |
712
+ | `PI_WEB_SDK` | `bundled` | Which pi SDK copy to run: `bundled` (the copy shipped with pi-web-ui) or `global` (the nearest ancestor copy when it is newer). |
713
+ | `PI_WEB_ALLOW_ORIGINS` | empty | Extra comma-separated `Origin` allow-list for the WebSocket check (dev proxy / reverse proxy). |
714
+ | `PI_WEB_GIT_EXTENSION_CHECK` | `1` (on) | `0` / `false` / `no` / `off` drops the git-source row from “Check all updates” (it runs `git ls-remote`), for very large repos. |
715
+ | `PI_WEB_PLUGIN_CATALOG_URL` | official catalog URL | Boot-time catalog source: defaults to the official community registry `https://xing-shuyin.github.io/pi-web-ui-plugins/catalog.json` (writes installable list only, **does not install plugins**). Set to empty or `off`/`0`/`false`/`no` to disable; combine with `PI_WEB_PLUGIN_CATALOG_INSTALL=1` to auto-install entries at boot (headless/container provisioning). |
716
+ | `PI_WEB_LAUNCHED_BY` / `PI_WEB_SERVICE_NAME` | empty | Written by `pi-web-ui server install` into the service unit/launcher (`service` / the `--name`): tells the server a supervisor owns it, which is what enables the update panel's “Restart service” button. |
717
+ | `PI_WEB_DSH_*` | — | DSH runtime knobs: `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`. |
663
718
 
664
719
  ## Security
665
720
 
@@ -799,7 +854,7 @@ pi-web-ui is a small open-source project — **your contributions are what make
799
854
 
800
855
  | Way to contribute | How to get started |
801
856
  | -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
802
- | 🧩 **Write a plugin** | Build your own UI tab + agent tools. Copy `plugins/demo-mailbox` as the minimal template (it doubles as the test fixture), develop locally, then either open a PR to ship it in the [catalog](#plugin-catalog) or [publish it standalone](https://github.com/xing-shuyin/pi-web-ui/tree/main/plugins). |
857
+ | 🧩 **Write a plugin** | Build your own UI tab + agent tools. Copy `plugins/demo-mailbox` as the minimal template (it doubles as the test fixture), develop locally, then either open a PR to ship it in the [catalog](#plugin-catalog) or [publish it standalone](https://github.com/xing-shuyin/pi-web-ui/tree/main/plugins) and list it there anyway — see [Community plugins](#community-plugins). |
803
858
  | 🎨 **Contribute a theme** | Copy `themes/white.css` (light) or `themes/cyberpunk.css` (dark) as a pure-palette template, tweak the `:root` palette + `--term-*` + `.hljs`, verify with `npm run dev`, then open a PR — full walkthrough in [Contributing a theme](#contributing-a-theme-to-the-repository-github). |
804
859
  | 💻 **Fix a bug / add a feature** | Look for [open issues](https://github.com/xing-shuyin/pi-web-ui/issues) or propose something new. Fork → branch → PR. Keep the code conventions in `AGENTS.md` (tabs, i18n keys in both languages, protocol changes in `server/protocol.ts`). |
805
860
  | 📖 **Docs & translations** | Improve the READMEs, write plugin docs, fix typos, or help translate the UI / docs into more languages. |
package/README.zh-CN.md CHANGED
@@ -31,7 +31,7 @@ QQ群 1126050727
31
31
  - WebSocket 流式聊天 —— pi SDK 在服务端进程内运行,事件以快照(60ms 节流)推送,浏览器按快照渲染。
32
32
  - 思考块、工具调用卡片、bash 输出,实时显示状态(执行中 → 已结束 · 等模型 · 耗时)。
33
33
  - **补充(steer)** —— 回复流式中可排队发送跟进消息,当前回合工具结算后立即注入(对应 pi CLI 的 Enter 打断语义)。
34
- - **斜杠命令** —— 输入 `/` 弹出命令选择器(内置 / 扩展 / 模板 / 技能);内置 `/new /model /compact /cwd /thinking /resume`,另有 `/help`(命令清单)与 `/copy`(复制上一条回复)。`/new` 可带首条提示(`/new 修一下失败的测试`),会作为新对话的第一条消息发出去。
34
+ - **斜杠命令** —— 输入 `/` 弹出命令选择器(内置 / 扩展 / 模板 / 技能);内置 `/new /name /model /compact /cwd /thinking /resume /reload`,另有 `/help`(命令清单)、`/copy`(复制上一条回复)与 `/pi-web-ui:quit`(退出服务)。`/new` 可带首条提示(`/new 修一下失败的测试`),会作为新对话的第一条消息发出去。
35
35
  - **每项目多对话并发** —— 每个对话独立 agent runtime,切走后仍在后台运行;「运行的对话」列表显示流式进度,可随时切回。
36
36
  - **编辑重问** —— 把任意历史问题 fork 成新分支重新提问,原对话不受影响。
37
37
  - 超过 30 条的消息自动折叠为摘要行(惰性渲染,点击展开)。
@@ -65,7 +65,7 @@ QQ群 1126050727
65
65
  **子代理与模板**
66
66
 
67
67
  - **第一方子代理** —— 后台派发独立对话并行做调研 / 实现 / 审查(`subagent_spawn`);与普通对话一样在左栏管理:实时查看输出、补充(steer)、中止、移出。内存会话——不进历史 / resume 列表,可嵌套派发。
68
- - **子代理模板** —— 设置面板「子代理模板」里配置可复用预设:角色系统提示词(追加或整体替换)+ 技能/扩展白名单 + 可选模型 + 可选思考强度。AI 用 `subagent_templates` 工具查询清单、`subagent_spawn(template="…")` 选用,也可以不传模板按主会话默认配置运行。模型与思考强度都留空 = 跟随主对话当前设置(与「跟随主对话」的模型回落同语义);模板指定了就固定用那个组合(模型不支持的思考档位会自动收敛)。停用的模板保留在面板可随时重新启用,但对 AI 工具不可见(查不到、不能选)。模板全局共享(`<dataDir>/subagent-templates.json`,所有浏览器客户端一致)。首次运行自带 6 个内置模板(review / implement / research / scout / audit / delegate,改编自 pi-subagents 社区项目),面板标「默认」徽标,可像普通模板一样修改或删除。
68
+ - **子代理模板** —— 设置面板「子代理模板」里配置可复用预设:角色系统提示词(追加或整体替换)+ 技能/扩展白名单 + 可选模型 + 可选思考强度。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 —— 面板标「默认」徽标,可像普通模板一样修改或删除。
69
69
 
70
70
  **文件、图片与附件**
71
71
 
@@ -112,12 +112,12 @@ QQ群 1126050727
112
112
 
113
113
  **代理工具与内联标记**
114
114
 
115
- - **工具开关** —— 设置 →「工具」把所有可选工具逐个列出:7 个终端工具(默认**关**)、7 个 `subagent_*` 工具(默认开)、`edit_soft`(默认关)、`delegate_task`/`ask_user_question`/`todo_list`(默认开)。开关即时生效、不重启,工具只是被禁用仍保留注册以便随时开回;`bash` 与 SDK 自带的 `edit`/`read` 有意不可关。
115
+ - **工具开关** —— 设置 →「工具」把所有可选工具逐个列出: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` 有意不可关。
116
116
  - **内联标记** —— 状态改变不需要工具往返,AI 直接把标记写进回复:任务列表用 `[[todo:new:<主题>]]` / `[[todo:set:<id>,in_progress]]` / `[[todo:remove:<id>]]` / `[[todo:dep:<id>,blocks=<id>]]`,不打断的提醒用 `[[notify:<级别>:<内容>]]`,改对话标题用 `[[conv:rename:<标题>]]`。气泡定稿即执行,标记写错会以浏览器提示回显;任务列表同时以常驻 widget 显示在右栏文件树下方(`N/M done` + ✓/◐/○),跟随当前对话,且因为存在该对话自己的会话分支里,刷新后仍在。设置 →「工具」另有总开关与逐标记开关(这两项全局共享)。
117
117
  - **`edit_soft`** —— 更宽松的 `edit`(默认关):缩进/空白导致内置工具失败时用它,先精确子串、再按去空白逐行核心匹配,`newText` 原样写入并保留文件换行符/BOM,结果带 diff 与 unified patch。
118
118
  - **`delegate_task`** —— 强制六段派单(TASK / EXPECTED OUTCOME / REQUIRED TOOLS / MUST DO / MUST NOT DO / CONTEXT)并在服务端校验:模板不可用、任务少于 20 字或任一段为空都会被打回,并把可用模板清单回给模型。卡片按六段结构化展示,跑完后可一键跳到对应子代理对话。
119
119
  - **`ask_user_question`** —— pi 引擎本身没有问卷工具,这是 pi-web-ui 加的:模型可以问结构化问题(单选/多选 + 富文本选项预览 + 自由文本),以对话框弹出;回答作为工具结果回给模型,取消则以工具错误返回,等你回答的时间不受工具看门狗限制,未答的问卷刷新/重连后会恢复。
120
- - **MCP 服务器** —— 放一份 `<dataDir>/mcp.json`(`{"servers":{"github":{"command":"node","args":["mcp.js"],"cwd":"/x"}}}`),该 stdio MCP 服务器声明的工具就会作为普通工具交给 AI(服务端执行);某一个起不来只记一行日志,不影响其他。文件在启动时读取,改完需重启 pi-web-ui。
120
+ - **MCP 服务器** —— 放一份 `<dataDir>/mcp.json`(`{"servers":{"github":{"command":"node","args":["mcp.js"],"cwd":"/x"}}}`),该 stdio MCP 服务器声明的工具就会作为普通工具交给 AI(服务端执行);某一个起不来只记一行日志,不影响其他。文件**热加载**:保存后一两秒内自动生效,无需重启——且只有配置真正变了的服务器才会重启(文件写坏会报错并保留正在运行的服务器)。
121
121
  - **扩展 UI 桥** —— pi 扩展可以驱动浏览器:`setWidget` 在文件树下方渲染实时面板(点标题居中放大),`setStatus` 在底栏显示状态文本,`notify` 弹通知,`select`/`confirm`/`input` 在输入框上方弹出非模态请求面板(选项走 Markdown 渲染,`Esc` 当作取消);widget 文本里的 ANSI 色码会被剥掉,不会把扩展底栏变成转义序列噪声。
122
122
  - **插件能力** —— 插件可注册 `/命令`(选择器标 plugin 来源、服务端执行不耗 token)、注册带停止按钮的后台任务、声明设置表单、订阅运行/工具/对话事件,并在前端经 `window.__piWebUiHost` 切视图、新建对话。详见 [界面插件](#界面插件)。
123
123
 
@@ -170,7 +170,7 @@ QQ群 1126050727
170
170
  - 后台任务面板 —— 在 bash 前后对比监听端口,检测 agent 启动的服务并列出端口 / pid / 名称 / 命令行(点命令行可展开全文);可单独停止或全部关闭,顶栏按钮带实时数量徽标。
171
171
  - 列表属于**浏览器客户端**而非对话:切项目、切对话、重连都不丢,服务端每 30 秒刷新一次并剔除已退出的进程。检测会排除已知桌面软件,以及父链回溯到 `explorer` 而不是服务进程的进程(所以你自己开的浏览器不会被当成「AI 启动的服务」)。
172
172
  - 插件注册的任务带 🧩 标记与实时状态文本,走插件自己的停止回调(比如邮件轮询任务)。
173
- - 工具看门狗 —— 单个工具调用超过 20 分钟自动中断会话(`PI_WEB_TOOL_TIMEOUT_MS`,问卷豁免)。
173
+ - 工具看门狗 —— 单个工具调用超过 20 分钟自动中断会话(超时在设置「工具」页可改,0 = 禁用;`PI_WEB_TOOL_TIMEOUT_MS` 只提供默认值;工具自己声明更长超时,如 bash `timeout`,则自动顺延)。问卷豁免。
174
174
  - **只停止 bash 命令** —— 中止运行中的 bash 工具而不打断对话。
175
175
  - **失联警告** —— 流式运行完全没事件超过 3 分钟(`PI_WEB_STALL_NOTIFY_MS`,`0` = 关)会指名对话地提醒一句,但不自动中止。
176
176
 
@@ -184,7 +184,7 @@ QQ群 1126050727
184
184
  - **文件边界** —— 工作区相对路径的读写一律做 `..` 逃逸校验(工作区外的路径只能经显式绝对路径/机器浏览到达);`/api/file` 内联只放行图片/视频/HTML,二进制不可能被 `<img>` 带走——其他类型必须走 `?download=1`(附件下载)。HTML 预览路由一律以 sandbox 下发。
185
185
  - 本地控制 socket 提供 `server status|quiesce|unquiesce`(排空模式:拒绝新 prompt/编辑重问/会话恢复,DSH 下还会拒绝新客户端连接,存量跑完)。
186
186
  - 凭据不下发浏览器 —— provider headers(可能含 Authorization)永不发送到前端,服务商 API key 只以昵称形式到达浏览器。
187
- - 9 种界面语言(中英内置 + 8 个可下载语言包:德/西/法/意/日/韩/葡/俄),语言包可在顶栏菜单里装/卸(见上方「语言与语言包」)。
187
+ - 10 种界面语言(中英内置 + 8 个可下载语言包:德/西/法/意/日/韩/葡/俄),语言包可在顶栏菜单里装/卸(见上方「语言与语言包」)。
188
188
  - **保留期** —— `uploads/` 里超过 `PI_WEB_UPLOAD_RETENTION_DAYS`(14 天,`0` = 不清理)的文件会在启动时与之后每 6 小时清理一次;DSH 会话有自己 90 天的清理。
189
189
  - **运维看门狗**(工具超时、模型失联、终端活力)都可调,见 [环境变量调优](#环境变量调优)。
190
190
 
@@ -419,6 +419,11 @@ volumes:
419
419
  | 📊 [图表 mermaid](https://github.com/xing-shuyin/pi-web-ui/tree/main/plugins/mermaid) | 把对话里的 ` ```mermaid ` 围栏渲染成 SVG 图表(fenced-code 渲染插件,本地引擎离线优先)。 |
420
420
  | 🧭 [运行轨迹 run-trace](https://github.com/xing-shuyin/pi-web-ui/tree/main/plugins/run-trace) | 运行轨迹:任务 → 思考 → 工具 → 文件改动 → 结果的时间线聚合视图,支持回放与节点详情。 |
421
421
  | 📖 [阅读 legado-web](https://github.com/xing-shuyin/pi-web-ui/tree/main/plugins/legado-web) | Legado 阅读(文本源):基于兼容安卓书源的搜书 / 发现 / 详情 / 目录 / 正文阅读,支持书源导入、检测与删废源,并提供四个修源 AI 工具(`legado_rules`、`legado_book_sources`、`legado_source_probe`、`legado_run_rule`)与「🤖 AI 修复源」按钮(带失败现场直接开新对话)。书源/书架/进度存在 `<dataDir>/legado-web/`。 |
422
+ | 💬 [微信通道 wechat-ilink](https://github.com/xing-shuyin/pi-web-ui/tree/main/plugins/wechat-ilink) | 微信扫码登录(与腾讯 openclaw-weixin 同源的 ilink 协议):出站长轮询收消息,在微信里直接指挥 agent,无需公网 IP。 |
423
+ | 🎤 [语音输入 voice-input](https://github.com/xing-shuyin/pi-web-ui/tree/main/plugins/voice-input) | 输入框旁的麦克风按钮:浏览器语音识别直接听写进输入框;不支持/识别失败时自动降级为服务端转写(远端接口,或一键安装的本地 Whisper,免费不出网)。 |
424
+ | 🌐 [实时预览 live-preview](https://github.com/xing-shuyin/pi-web-ui/tree/main/plugins/live-preview) | Live Server 式预览:`/liveserver` 看 HTML(含相对资源与自动刷新)、`/md` 看 Markdown 渲染;真服务只绑回环地址,经宿主通用代理对外只露同源前缀。 |
425
+ | 🖼 [图片处理 image-toolkit](https://github.com/xing-shuyin/pi-web-ui/tree/main/plugins/image-toolkit) | 图片处理工作台:压缩(按目标体积二分逼近)、裁剪、缩放、旋转/翻转、格式转换(PNG/JPEG/WebP/AVIF)、批量导出 ZIP、水印、滤镜调色、图片信息与 EXIF,可直接读写工作区图片;另给 AI 配了 4 个工具。 |
426
+ | 📓 [笔记 notes](https://github.com/xing-shuyin/pi-web-ui/tree/main/plugins/notes) | 随手记:笔记 + 待办 + 日程提醒三合一。顶栏按钮打开可自由拖拽的全局浮窗(位置/尺寸记忆,设置也在浮窗里,无独立视图页);提醒走服务端定时(重启不丢、错过补送),另有 5 个 AI 工具与 `/note` `/todo` `/remind` 快速捕获。 |
422
427
 
423
428
  `plugins/demo-mailbox` 作为最小插件模板保留在仓库里(服务端入口 + 客户端视图 + 双向消息协议),兼作测试夹具——想自己写插件从这里入手。
424
429
 
@@ -432,6 +437,22 @@ pi-web-ui install https://github.com/xing-shuyin/pi-web-ui/tree/main/plugins/web
432
437
 
433
438
  每个插件在仓库里的目录都带独立 `README.md`,含完整功能清单、配置说明与注意事项。
434
439
 
440
+ ### 社区插件
441
+
442
+ 插件目录并不限于本仓库:条目的 `source` 可以指向任意 GitHub 仓库(`owner/repo`、monorepo 里的 `owner/repo/子目录`,
443
+ 两者都可带 `#ref`),所以在别处开发、发布、维护的插件同样能进市场列表,安装 / 更新 / 回滚与上面的插件完全一致——
444
+ 同样落在 `<dataDir>/plugins/<id>/`,更新时保留 `config.json`。
445
+
446
+ 装的时候代码是从那个仓库拉的,本仓库不做内置拷贝:社区条目只是一条指针,许可证、issue 与发布节奏都归插件作者。
447
+ 想要固定版本,在 `source` 里带上 `#ref`。
448
+
449
+ | 插件 | 功能 |
450
+ | ---- | ---- |
451
+ | 🌿 [多仓库 Git multi-git](https://github.com/EinErste/pi-web-multigit) | 多仓库 Git 总览:项目目录下每个仓库的变更、差异、历史、分支、贮藏、跨仓搜索、时间线与单文件回滚,另有工作区分支聚合、Fetch/Pull(仅快进)与可选的内置终端;其余只读。 |
452
+
453
+ 想被收录,和任何条目一样只差一行:往 `plugins/catalog.json` 加一条并发 PR。不提 PR 也可以在市场里自行登记(存在
454
+ `<dataDir>/plugin-catalog.json`),或用 `pi-web-ui install --catalog <url>` 把市场指向你自托管的目录文档。
455
+
435
456
  ### 安装
436
457
 
437
458
  从 GitHub 安装(支持以下任意源写法):
@@ -512,7 +533,7 @@ pi-web-ui uninstall <id> # 卸载插件
512
533
 
513
534
  每个主题是**一份纯 `:root` 调色板覆盖** —— 只写 CSS 变量的声明文件(变量全集见 `web/src/styles.css` 的 `:root`:`--bg/--accent/--term-*` 基础色,加 `--tooltip-bg/--code-bg/--notice-*` 等派生色)。布局只存在于打包的 `web/src/styles.css` 里,选主题只是覆盖变量,因此任何主题都能在所有版本上工作,改布局也不需要碰主题文件。内置主题由 `node make-light-theme.mjs` 生成。
514
535
 
515
- 内置主题随 npm 包分发(`themes/`):`white`(浅色)、`cyberpunk` / `dazzle`(深色)、`translucent` / `transparent`(壁纸友好半透明/全透明,可配对话壁纸)。主题选择器在顶栏(🌞 图标),当前选择按浏览器存在 `localStorage`。
536
+ 内置主题随 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`。
516
537
 
517
538
  ### 使用主题
518
539
 
@@ -556,7 +577,7 @@ pi-web-ui uninstall <id> # 卸载插件
556
577
 
557
578
  | 变量 | 默认 | 作用 |
558
579
  | ------------------------------ | ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
559
- | `PI_WEB_TOOL_TIMEOUT_MS` | `1200000`(20 分) | 单工具调用看门狗;超时自动中止(`ask_user_question` 豁免)。 |
580
+ | `PI_WEB_TOOL_TIMEOUT_MS` | `1200000`(20 分) | 单工具调用看门狗;超时自动中止(`ask_user_question` 豁免)。只做默认值,设置面板「工具」页优先。 |
560
581
  | `PI_WEB_STALL_NOTIFY_MS` | `180000`(3 分) | 流式运行完全没事件时给警告(不中止);`0` = 关。 |
561
582
  | `PI_WEB_TERMINAL_IDLE_MS` | `15000` | AI 开过的终端静默这么久就催它去看一眼;`0` = 关。 |
562
583
  | `PI_WEB_TERMINAL_IDLE_LINES` | `10` | 该催命消息回送的终端尾部行数(1–500)。 |
@@ -571,7 +592,12 @@ pi-web-ui uninstall <id> # 卸载插件
571
592
  | `PI_WEB_LOCALE_BASE_URL` | GitHub raw | 语言包下载根 —— 指向镜像即可做离线/内网安装。 |
572
593
  | `PI_WEB_PKG_ROOT` | 自动 | 显式指定包根目录(非标准安装位置时用)。 |
573
594
  | `PI_CODING_AGENT_SESSION_DIR` | 空 | 让 pi 把转录扁平写入该目录(而非 `<agentDir>/sessions/--<cwd>--/`,会改变历史列表读到的内容)。 |
574
- | `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`。 |
595
+ | `PI_WEB_SDK` | `bundled` | 用哪一份 pi SDK:`bundled`(pi-web-ui 自带的副本)或 `global`(祖先链上更新的那份)。 |
596
+ | `PI_WEB_ALLOW_ORIGINS` | 空 | WebSocket Origin 校验的额外白名单(逗号分隔;dev 代理 / 反向代理用)。 |
597
+ | `PI_WEB_GIT_EXTENSION_CHECK` | `1`(默认开) | 设 `0`/`false`/`no`/`off` 关闭「全部组件更新」里的 git 行(走 `git ls-remote`),大型单体仓库场景可用。 |
598
+ | `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` 时顺手自动全部安装。 |
599
+ | `PI_WEB_LAUNCHED_BY` / `PI_WEB_SERVICE_NAME` | 空 | 由 `pi-web-ui server install` 写进服务单元/启动脚本(`service` / `--name`):服务端据此知道实例由平台服务托管,更新面板才会出现「重启服务」按钮。 |
600
+ | `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`。 |
575
601
 
576
602
  ## 安全
577
603
 
@@ -651,7 +677,7 @@ pi-web-ui 是一个小型开源项目 —— **你的贡献就是它成长的力
651
677
 
652
678
  | 贡献方式 | 如何开始 |
653
679
  | ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
654
- | 🧩 **写插件** | 打造你自己的界面 tab + AI 工具。以 `plugins/demo-mailbox` 为最小模板(它兼作测试夹具),本地开发后既可开 PR 收录进[插件目录](#插件目录),也可独立发布。 |
680
+ | 🧩 **写插件** | 打造你自己的界面 tab + AI 工具。以 `plugins/demo-mailbox` 为最小模板(它兼作测试夹具),本地开发后既可开 PR 收录进[插件目录](#插件目录),也可独立发布并照样收录(见[社区插件](#社区插件))。 |
655
681
  | 🎨 **贡献主题** | 以 `themes/white.css`(浅色)或 `themes/cyberpunk.css`(深色)为纯调色板模板,调整 `:root` 配色 + `--term-*` + `.hljs`,用 `npm run dev` 验证后开 PR —— 完整步骤见[向仓库贡献主题](#向仓库贡献主题github)。 |
656
682
  | 💻 **修 bug / 加功能** | 在 [Issues](https://github.com/xing-shuyin/pi-web-ui/issues) 里挑一个,或提出新想法。Fork → 分支 → PR。代码约定见 `AGENTS.md`(Tab 缩进、i18n 双语 key、协议改动只动 `server/protocol.ts`)。 |
657
683
  | 📖 **文档与翻译** | 完善 README、补插件文档、改错别字,或帮忙把界面/文档翻译成更多语言。 |