pi-dsh-plus-surface
DSH+ 显示面的 pi 侧事实插件:把每个 pi 会话的进行中/结束/命名事实写成分片文件(~/.pi/dsh-plus/facts/),供 DSH+ 壳合并出角标与气泡。TUI 与 pi-web(RPC 模式)通用。
Package details
Install pi-dsh-plus-surface from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:pi-dsh-plus-surface- Package
pi-dsh-plus-surface- Version
0.1.2- Published
- Sep 5, 2026
- Downloads
- 185/mo · 15/wk
- Author
- kaerf15
- License
- MIT
- Types
- extension
- Size
- 18.6 KB
- Dependencies
- 0 dependencies · 0 peers
Pi manifest JSON
{
"extensions": [
"./index.ts"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
pi-dsh-plus-surface
DSH+ 显示面的 pi 侧事实插件:把每个 pi 会话的进行中/结束/命名事实写成分片文件
(~/.pi/dsh-plus/facts/<sessionId>.json),DSH+ 壳读目录合并出进行中角标、完成气泡、
点击跳回会话。TUI 与 pi-web(RPC 模式)通用——全局装一次,两边都生效。
为什么是分片
pi-web 每个会话一个 pi 进程,每个扩展实例只看得见自己这条会话。一个进程写一片,
壳按目录合并 + 心跳(5s)识别活进程:running 且心跳过期(>15s)的片被壳折算成
「中断结束」(记 finishedAt、不出完成气泡),与 dsh 侧「进程重启 = 被打断」同语义。
事实形状(与 dsh-plus-surface 的 bridge.json 同信封)
{
"protocol": "dsh-plus.fact", "version": 1, "domain": "pi.sessions",
"sessionId": "…", "pid": 12345, "heartbeat": 1787400000000, "updatedAt": 1787400000000,
"session": {
"status": "running", // running | idle
"runningSince": 1787400000000,
"finishedAt": null,
"title": "会话名(未命名取 cwd 末段)",
"cwd": "/abs/path",
"completed": false // 结束即未看;壳点气泡跳转时清,新一轮 running 重新武装
}
}
事件口径:agent_start → running;agent_settled(不是 agent_end,自动重试/压缩不算完)→ idle +
completed=true;老版 pi 无 agent_settled(如 @mariozechner 0.73.x),由 agent_end 加 3s 宽限兜底(宽限内跟上新
agent_start 视为续跑);session_shutdown 时仍在 running → 中断,completed=false。
不做 pendingInteraction:pi 的确认/询问是各扩展自己的 ctx.ui 请求,没有全局可观测事件。
安装
复制到 pi 全局扩展目录(~/.pi/agent/extensions/*/index.ts 自动发现,不走 settings 挂路径;
注意 pi install <本地路径> 只是向 settings 写路径引用、不复制文件,源码挪动/改名会断链):
mkdir -p ~/.pi/agent/extensions/pi-dsh-plus-surface
cp index.ts serve-facts.mjs package.json README.md ~/.pi/agent/extensions/pi-dsh-plus-surface/
# 源码改动后重跑一次复制;运行中的 pi 进程 /reload 或重启后加载新版
装完新启动的 pi / pi-web 会话即产事实;DSH+ 壳侧的显示规则在同一份 recipe.json
(bundled pi.sessions 域),动作是 open-pi-session(壳走 pi-web 深链 /?session=<id>)。
HTTP 事实出口(远端壳用,0.1.2+)
对应 dsh 侧的「双出口常开」(webServer.register('/dsh-plus-surface/bridge.json')):pi-web 没有可挂载的
webServer(编译死 Next.js,扩展开不了同源端点,pi-web 0.8.11 HTTP 面已逐路由核实),出口由伴生 listener
serve-facts.mjs 提供——插件在 session_start 时确保拉起(端口被占即静默退场,幂等、零配置),只读镜像
分片目录,不做任何归并/折算(语义全在壳的 FactsDirSource,与本地 fs 读法一字不差)。
- 路由:
GET /pi-dsh-plus-surface/shards.json→{version:1, shards:[{name, body}]};只读、绑127.0.0.1, 端口DSH_PLUS_FACTS_PORT默认3099 - 手动跑也行:
node serve-facts.mjs(envDSH_PLUS_FACTS_DIR/DSH_PLUS_FACTS_PORT) - 运维注记:出口是 detached 独立进程,插件文件更新后旧进程仍占着端口(新拉起会静默退场)——
改过
serve-facts.mjs后要手动杀旧进程(lsof -ti tcp:3099 | xargs kill)才会跑上新版 - 壳侧寻址(
main.jsprobeApp):分片重叠判本机 → dir;否则探app.factsUrl(独立映射端口,如http://127.0.0.1:3082)再探同源路径(远端反代把出口挂进 pi-web 端口时零配置)→ 出口就绪即全保真 (精确结束时刻/中断识别/命名),都缺席才退piweb-poll.js轮询——与 dsh 侧「出口缺席退轮询」同构 - 安全口径与 dsh 侧一致:只读、绑环回;经映射暴露时确认映射工具侧不对公网开放
配套
- 壳侧来源:
lib/surface/facts-dir.js(本机分片目录合并 + completed 粘性清除;0.1.2 起同一套逻辑 兼读 HTTP 出口镜像);出口都缺席时壳自动用lib/surface/piweb-poll.js(按/api/sessions的 running 迁移推断,零插件可用)