pi-web-ui 0.91.0 → 0.92.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 (37) hide show
  1. package/CHANGELOG.md +34 -1
  2. package/bin/pi-web-ui.mjs +21 -2
  3. package/dist/server/agent-service.js +443 -45
  4. package/dist/server/claim-files-tool.js +116 -0
  5. package/dist/server/claim-store.js +301 -0
  6. package/dist/server/client-state.js +49 -0
  7. package/dist/server/conversation-read-tool.js +369 -27
  8. package/dist/server/conversation-touches.js +357 -0
  9. package/dist/server/dsh/dsh-agent-service.js +7 -0
  10. package/dist/server/index.js +32 -4
  11. package/dist/server/model-admin.js +124 -2
  12. package/dist/server/model-enrich.js +478 -0
  13. package/dist/server/plugin-schedule.js +27 -2
  14. package/dist/server/plugins.js +65 -10
  15. package/dist/server/present-files-tool.js +303 -0
  16. package/dist/server/read-tool.js +91 -0
  17. package/dist/server/serialize.js +21 -1
  18. package/dist/server/settings-service.js +7 -0
  19. package/dist/server/text-sniff.js +15 -0
  20. package/dist/server/themes.js +17 -2
  21. package/dist/server/tool-manager.js +7 -1
  22. package/package.json +1 -1
  23. package/plugin-sdk/README.md +1 -0
  24. package/plugins/catalog.json +10 -0
  25. package/themes/catppuccin-latte.css +136 -0
  26. package/themes/catppuccin.css +140 -0
  27. package/themes/nord.css +130 -0
  28. package/themes/one-dark.css +131 -0
  29. package/themes/paper.css +12 -12
  30. package/themes/solarized-light.css +131 -0
  31. package/themes/tokyo-night.css +140 -0
  32. package/web/dist/assets/{TerminalPanel-GtDQ1h85.js → TerminalPanel-RACpk6AX.js} +1 -1
  33. package/web/dist/assets/index-BgrnP9Jz.js +364 -0
  34. package/web/dist/assets/index-Cy8dSTZt.css +1 -0
  35. package/web/dist/index.html +2 -2
  36. package/web/dist/assets/index-CdsKltOS.css +0 -1
  37. package/web/dist/assets/index-OoULNF70.js +0 -363
package/CHANGELOG.md CHANGED
@@ -10,6 +10,38 @@
10
10
 
11
11
  ## [Unreleased]
12
12
 
13
+ ## [0.92.0] — 2026-09-20
14
+
15
+ ### Added
16
+
17
+ - **插件设置的 `select` 候选值可由宿主现算(`optionsFrom`)** —— manifest `settings` 里写 `"type": "select", "optionsFrom": "models" | "thinkingLevels"` 即可让宿主在浏览器侧现算候选值:模型列已配置鉴权的模型(值 `provider/id`,标签同设置面板的模型选择器)、思考强度列 SDK 档位(`off`…`max`,文案走 `thinking.<值>`);两者自动带一个空值选项 = 跟随全局默认,插件不用自己维护会过期的静态表。服务端不校验这类值(清单在浏览器侧、随配置变化),只留 200 字符长度护栏,非法值由用的时候(如 `host.chat` 切模型)报错;当前存值不在清单里(模型被删/手改过 storage.json)时也保留,不被下拉静默吃掉。
18
+ - **自定义模型提供商「补参数」支持随时中断与实时进度反馈** —— 模型配置面板中点击「补参数」后,新增实时进度显示(下载 OpenRouter / models.dev 目录、抓取依据网页、逐个匹配参数 N/M 与百分比),并提供「✕ 取消」按钮;点击取消后服务端立即截断网络连接与批处理,并自动保留中断前已匹配的模型行,避免弱网时无响应或无法停止。
19
+ - **微信通道(wechat-ilink)设置里的「模型」「思考强度」改下拉选择** —— 旧版是手打 `provider/id` 文本框,打错要到微信里跑完一轮才发现(切换失败)。现在从清单里选,空 = 跟随全局默认。
20
+ - **read 工具可直接读目录** —— 模型把目录路径交给 read 时不再报 `EISDIR`,改为列出目录条目(一行一项、目录带 `/` 后缀,`limit` 此时是条目上限),看目录不必再走 bash 的 `ls`。实现是覆盖内置 read(同名 customTool),文件/图片/不存在的路径行为与原来完全一致;设置 → 工具页新增「read 读目录」开关(默认开),关掉即恢复内置行为。仅 pi 引擎生效(DSH 引擎的工具来自预设,无此覆盖面)。
21
+ - **浏览器扩展(page-picker):点一次图标就能看见「让 AI 操作本页」** —— AI 授权入口原来只挂在拾取**确认条**里(必须先在页面上点一个元素它才出现,「只想授权」的人白点一下)。现在拾取态底部常驻一条细条:直接显示本页授权状态(未授权 / 已授权 / 「AI 操作页面」总开关关着 / 查不到后台),并给出「让 AI 操作本页…」「与另一页配对…」「退出」;在扩展设置页点完「授权该页面」回到那个页面,细条自己变成「已授权 · 模型可操作本页」(扩展监听授权表变化,不用重新点图标、不用刷新)。细条只有按钮可点,其余区域点击照旧穿透到页面元素 —— 不影响拾取手感。
22
+ - **AI 可以主动把文件「拿给你看」(`present_files`)** —— 新工具让模型把产物直接推到对话里成卡片:图片、视频、音频**在消息内直接显示/播放**(不折叠、不用点),文本/代码/Markdown/HTML 给开头摘录 + 「预览」按钮开文件预览弹窗(行号、选区、加进对话都在那边),不能内联的(PDF/二进制)只给下载与本地打开;每一行都带「预览 / 本地打开(用默认应用打开文件)/ 在文件夹中显示 / 下载 / 复制路径」,其中「本地打开」「在文件夹中显示」与右栏文件树右键菜单**同一套协议**(服务器跑在别的机器上时由服务端明确提示不支持,不是默默没反应);路径不存在时卡片直接标红说明,不会给你一个点不动的东西。模型还能把某个文件标成「先看这个」,配合设置 → 消息显示新增的「自动打开 AI 展示的预览」开关(默认关)就能自动把预览窗弹出来(只对刚发生的卡片生效,翻旧会话不会突然弹窗)。工具目录 24→25(默认开,**设置 → 工具页有独立开关**,可随时关掉)。仅 pi 引擎(DSH 引擎的工具来自预设,无此覆盖面)。
23
+
24
+ - **插件可以「没有独立视图、但每次进页都常驻加载」(manifest `preload`)** —— 有的插件根本不需要自己的 tab(界面全在浮窗 / 输入框按钮 / 消息卡片里),但它的客户端代码必须一直在跑(到点提醒的长轮询、快捷键、常驻浮窗的状态恢复)。以前这种插件只有两条路:要么写 `view: false`(宿主**不**预加载,只有点它的按钮才 import → 刷新页面后提醒/浮窗全停摆),要么被迫留一个没人用的视图 tab。现在 manifest 写 `"view": false, "preload": true` 即可:宿主每次进页都预加载它的 bundle(顶层代码跑完即算加载成功,**可以没有 `default.mount`**),但仍不给它视图 tab。笔记插件是第一个用户(见下面 Changed)。
25
+ - **SCM 提交树过滤 + 提交信息历史** —— 提交树列表头新增过滤框:按主题 / 作者 / hash / 分支·标签实时过滤(空格分隔多关键字 AND 语义,计数徽标显示「命中/总数」,切工作区自动重置);提交输入框支持 ↑/↓ 回溯最近用过的提交信息(shell 风格:↑ 记住当前草稿并翻回历史,↓ 逐级退回,localStorage 存最近 20 条,去重置顶、隐私模式静默降级)。纯前端零协议改动;过滤与回溯的纯函数带单测(`scm-history-filter` / `scm-commit-history`)。
26
+ - **顶栏插件改成单个 🧩 入口(插件视图默认不再占顶栏)** —— 以前装了视图的插件每个都在顶栏占一个 tab,插件一多就被挤进「⋯」,装得越多越难找。现在顶栏只留一个 🧩:点开是全部已装插件的面板,每行带图钉(钉住的插件视图 tab 才回到顶栏直流),行首把手可拖拽排序、聚焦后也能用 ↑/↓ 调序(只改插件视图彼此的相对次序,其它条目的排序偏好原样保留),点行本身直接切到该插件视图,底部「管理插件」直达设置 → 插件 → 市场。纯渲染器插件(`view: false`)与报错插件照样列出(后者行内显示原因),但不给图钉、行不可点。**升级注意**:插件视图默认「未钉住」= 不再出现在顶栏,之前装过插件的用户需要在 🧩 面板里挨个钉回来;钉住状态与设置「界面布局」页的勾选框是同一套存储与语义,两边改都生效。顺带两处修正:插件视图不再被历史排序偏好挤到对话/终端之前(独立区段排在 Git 之后),以及「设置」入口被固定保护 —— 不能被插件 arrange 或布局偏好隐藏(布局页该行勾选框置灰),空间不够时它也优先留下、不让位给「⋯」(`fitTopbar` 常驻项先占预算)。
27
+
28
+ ### Fixed
29
+
30
+ - **设置「工具」页漏挂的两个工具开关(`skill` / `present_files`)补齐** —— 该页的工具行是手写的,终端组/子代理组按名单循环渲染,成“其他”组逐个手写,因此工具只进 `AGENT_TOOL_CATALOG` 目录、忘了写行的时候,会出现「目录里有、设置里找不到」:工具默认开着且关不掉。现在两个开关都在「其他」组里,并新增静态守卫单测(`tests/unit/settings-tool-rows.test.ts`):目录里每个工具必须能被设置页渲染(循环组或显式行),今后再漏会直接 CI 报红。
31
+
32
+ ### Changed
33
+
34
+ - **笔记插件:去掉独立视图 tab,浮窗成为唯一界面(插件 0.2.0)** —— 以前它有两个入口:顶栏按钮开浮窗 + 🧩 插件面板里的「笔记」行开一个完整视图 tab(浮窗头部还多一个 `⤢` 按钮指向它),同一件事三个入口。现在只留一个:顶栏 **📌**(图标从「日历打勾」换成图钉,与浮窗头部同一枚)开合浮窗,浮窗里工作。同时修了浮窗里四处布局毛病:① 正文区不再按内容撑高(实测 440px 的窗口里列表高 600px,日历会画到底栏和设置层上去),现在自己收缩成可滚动的一块;② 设置从「挤在窗口底部的第三块」(一开就把正文压成一条缝、还套了两层容器)改成**盖在正文之上的覆盖层**(自带标题栏 + ✕,内部滚动,正文不被压缩);③ 设置里「语言」标签不再被下拉框挤成竖排两个字;④ 底栏在窄窗里从三行压成一行(提醒那句长了给省略号),日历格子在窄窗里也矮了一档。**升级注意**:已装插件需要更新一次(`pi-web-ui install --name notes --force` 或重装),且改完 manifest 后要触发一次重扫(设置 → 插件 → 重新扫描,或重启服务)才会生效。
35
+ - **插件声明式设置表单改成单列行式布局** —— 旧版是 `auto-fit` 网格 + `space-between`:窄列时长标签被逐字挤成**竖排**(如「允许的用户默认工作空间」一个字一行),勾选框被甩到行最右端、与标签断开,输入框/下拉/数字框宽度也各自为政。现在统一为「标签固定左列(不压缩、超长省略号 + 悬浮看全名)+ 控件右列(文本/下拉 420px、数字 120px、勾选框贴标签)」,行间细分隔线;`hint` 从只挂 `title` tooltip 改为**常显在标签下的小字**(最多两行);窄窗口(≤720px)标签与控件上下堆叠。纯渲染层改动,manifest `settings` schema、`plugin_settings` 协议与既有 class 名(`.plugin-settings-field/-save/-reset/-form`)均未变。
36
+
37
+ <!-- auto-i18n:start -->
38
+ ### i18n
39
+
40
+ - 前端新增 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
+ - 服务端新增 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
+ - 服务端文案变更(1):`convread.bad.action`
43
+ <!-- auto-i18n:end -->
44
+
13
45
  ## [0.91.0] — 2026-09-19
14
46
 
15
47
  ### Added
@@ -1091,7 +1123,8 @@ when?, children?}`,也收 `topbar` / `settings` 这类简写别名);宿主
1091
1123
  - 0.35.1(2026-08-27):编辑重问保留附件(#18)+ 全窗口拖放(#19)。
1092
1124
  - 0.29.0(2026-08-23):全局搜索弹窗(Ctrl+K)+ 消息列表惰性窗口化。
1093
1125
 
1094
- [Unreleased]: https://github.com/xing-shuyin/pi-web-ui/compare/v0.91.0...main
1126
+ [Unreleased]: https://github.com/xing-shuyin/pi-web-ui/compare/v0.92.0...main
1127
+ [0.92.0]: https://github.com/xing-shuyin/pi-web-ui/releases/tag/v0.92.0
1095
1128
  [0.91.0]: https://github.com/xing-shuyin/pi-web-ui/releases/tag/v0.91.0
1096
1129
  [0.90.1]: https://github.com/xing-shuyin/pi-web-ui/releases/tag/v0.90.1
1097
1130
  [0.90.0]: https://github.com/xing-shuyin/pi-web-ui/releases/tag/v0.90.0
package/bin/pi-web-ui.mjs CHANGED
@@ -1000,6 +1000,17 @@ function systemdQuote(value) {
1000
1000
  return JSON.stringify(String(value)).replace(/%/g, "%%");
1001
1001
  }
1002
1002
 
1003
+ /**
1004
+ * systemd paths (WorkingDirectory=) must NOT be quoted: unlike Environment= and
1005
+ * ExecStart=, the path directives do not strip surrounding double quotes, so
1006
+ * WorkingDirectory="/home/me/work" makes systemd fail with "path is not absolute".
1007
+ * The whole (trimmed) value is the path, so inner spaces need no escaping —
1008
+ * only % has to be doubled to survive specifier expansion.
1009
+ */
1010
+ function systemdPath(value) {
1011
+ return String(value).replace(/%/g, "%%");
1012
+ }
1013
+
1003
1014
  /** Build the systemd unit file. */
1004
1015
  function buildUnit(cwd, env) {
1005
1016
  const envLines = Object.entries(env)
@@ -1017,7 +1028,7 @@ After=network.target
1017
1028
  [Service]
1018
1029
  Type=simple
1019
1030
  User=${process.env.SUDO_USER ?? userInfo().username}
1020
- WorkingDirectory=${systemdQuote(cwd)}
1031
+ WorkingDirectory=${systemdPath(cwd)}
1021
1032
  ${envLines}
1022
1033
  ${capabilities}ExecStart=${JSON.stringify(NODE)} ${JSON.stringify(SERVER_ENTRY)}
1023
1034
  Restart=always
@@ -1147,7 +1158,15 @@ function installSystemd(opts) {
1147
1158
  return;
1148
1159
  }
1149
1160
  // Generated units can contain credentials. install also corrects an existing unit's mode.
1150
- runSystemdRoot("install", ["-m", "600", "/dev/stdin", unitPath], content);
1161
+ // Stage through a temp file: `install /dev/stdin` fails on some hosts (WSL) with
1162
+ // ENXIO when stdin is a pipe rather than a tty.
1163
+ const staged = join(tmpdir(), `pi-web-ui-${name}-${process.pid}.service`);
1164
+ writeFileSync(staged, content, { mode: 0o600 });
1165
+ try {
1166
+ runSystemdRoot("install", ["-m", "600", staged, unitPath]);
1167
+ } finally {
1168
+ rmSync(staged, { force: true });
1169
+ }
1151
1170
  runSystemdRoot("systemctl", ["daemon-reload"]);
1152
1171
  runSystemdRoot("systemctl", ["enable", `${name}.service`]);
1153
1172
  // enable --now does not restart an already-active unit after configuration changes.