pi-web-ui 0.5.1 → 0.6.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.
- package/README.md +1 -0
- package/README.zh-CN.md +2 -0
- package/dist/server/agent-service.js +112 -1
- package/dist/server/index.js +6 -0
- package/package.json +1 -1
- package/web/dist/assets/{index-CcQSs9FB.js → index-Bqsvd0gO.js} +47 -47
- package/web/dist/assets/{index-BLLTs3yL.css → index-CG0Zje9G.css} +1 -1
- package/web/dist/index.html +2 -2
package/README.md
CHANGED
|
@@ -21,6 +21,7 @@ your existing pi auth/config/extensions — nothing extra to install or configur
|
|
|
21
21
|
- 📂 **Project memory**: the last workspace of each browser is remembered and restored on restart; a "Recent projects" list in the left panel switches workspaces in one click, and each project keeps its own sessions so you can always pick up an old conversation
|
|
22
22
|
- ✏️ **Edit & re-ask**: every past question has an edit button — change it and re-ask from that point. The server forks a new branch session (keeping the full history before that question) while the original conversation stays untouched in the session list
|
|
23
23
|
- ⚡ **Long chats stay fast**: past 30 messages, older messages collapse into summary rows (role + first-line preview + block counts — no Markdown/thinking/tool output rendered); click to expand the full content. The latest 15 messages always render in full
|
|
24
|
+
- ⬇️ **Self-update**: the top-right corner shows the running version; the update panel checks npm for the latest release and can run `npm i -g` in one click (a restart is required to take effect)
|
|
24
25
|
- 🔄 Model & thinking-level cycling (same as pi's TUI), new chat, abort/stop
|
|
25
26
|
- 📎 Markdown rendering with GFM tables, syntax-highlighted code blocks and copy buttons
|
|
26
27
|
- 📁 Workspace-aware: the agent reads/edits/runs code in a configurable directory using **your** `~/.pi/agent` auth, models, skills and extensions
|
package/README.zh-CN.md
CHANGED
|
@@ -23,6 +23,8 @@ pi 认证/配置/扩展——无需额外安装或配置任何东西。
|
|
|
23
23
|
新分支会话(该问题之前的历史完整保留),原对话原样留在会话列表,随时可切回
|
|
24
24
|
- ⚡ **长对话不卡**:超过 30 条消息后,早期消息自动折叠成摘要行(角色 + 首行预览 + 块计数,
|
|
25
25
|
不渲染 Markdown/思考/工具输出),点击才展开完整内容;最近 15 条始终完整显示
|
|
26
|
+
- ⬇️ **一键自更新**:右上角显示当前版本,打开更新面板检查 npm 最新版,发现新版本可一键
|
|
27
|
+
`npm i -g` 升级(更新后需重启服务生效)
|
|
26
28
|
- 🔄 模型与思考强度切换(与 pi TUI 一致)、新对话、中止/停止
|
|
27
29
|
- 📎 Markdown 渲染:GFM 表格、语法高亮代码块、复制按钮
|
|
28
30
|
- 📁 工作区感知:智能体在你指定的目录里读/改/跑代码,使用**你自己的** `~/.pi/agent` 认证、模型、技能和扩展
|
|
@@ -11,7 +11,8 @@
|
|
|
11
11
|
*/
|
|
12
12
|
import { spawn } from "node:child_process";
|
|
13
13
|
import { existsSync, readFileSync, statSync, writeFileSync, mkdirSync, } from "node:fs";
|
|
14
|
-
import { dirname, join } from "node:path";
|
|
14
|
+
import { dirname, join, resolve } from "node:path";
|
|
15
|
+
import { fileURLToPath } from "node:url";
|
|
15
16
|
import { createAgentSessionFromServices, createAgentSessionRuntime, createAgentSessionServices, getAgentDir, SessionManager, } from "@earendil-works/pi-coding-agent";
|
|
16
17
|
import { serializeMessage, serializeStreamingMessage, } from "./serialize.js";
|
|
17
18
|
import { loadCommands, saveCommandsFile, TerminalManager, } from "./terminals.js";
|
|
@@ -817,6 +818,116 @@ export class ClientSession {
|
|
|
817
818
|
* pi CLI globally (npm i -g). Auth is configured afterwards via the API key
|
|
818
819
|
* form or by running `pi` in a terminal.
|
|
819
820
|
*/
|
|
821
|
+
/**
|
|
822
|
+
* Version of the RUNNING pi-web-ui package (read from its own package.json,
|
|
823
|
+
* resolved from this compiled module: <pkg>/dist/server → <pkg>).
|
|
824
|
+
*/
|
|
825
|
+
static currentAppVersion() {
|
|
826
|
+
try {
|
|
827
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
828
|
+
const pkgRoot = resolve(here, "..", "..");
|
|
829
|
+
const pkg = JSON.parse(readFileSync(join(pkgRoot, "package.json"), "utf8"));
|
|
830
|
+
return pkg.version ?? "0.0.0";
|
|
831
|
+
}
|
|
832
|
+
catch {
|
|
833
|
+
return "0.0.0";
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
/** Simple numeric semver compare: >0 means a newer than b. */
|
|
837
|
+
static compareVersions(a, b) {
|
|
838
|
+
const pa = a.split(".").map((n) => parseInt(n, 10) || 0);
|
|
839
|
+
const pb = b.split(".").map((n) => parseInt(n, 10) || 0);
|
|
840
|
+
for (let i = 0; i < 3; i++) {
|
|
841
|
+
const x = pa[i] ?? 0;
|
|
842
|
+
const y = pb[i] ?? 0;
|
|
843
|
+
if (x !== y)
|
|
844
|
+
return x - y;
|
|
845
|
+
}
|
|
846
|
+
return 0;
|
|
847
|
+
}
|
|
848
|
+
/** True once updateApp succeeded — the process must restart to run new code. */
|
|
849
|
+
pendingRestart = false;
|
|
850
|
+
/** Ask the npm registry for the latest pi-web-ui version and report it. */
|
|
851
|
+
async checkUpdate() {
|
|
852
|
+
const current = ClientSession.currentAppVersion();
|
|
853
|
+
try {
|
|
854
|
+
const res = await fetch("https://registry.npmjs.org/pi-web-ui/latest", {
|
|
855
|
+
signal: AbortSignal.timeout(8_000),
|
|
856
|
+
});
|
|
857
|
+
if (!res.ok)
|
|
858
|
+
throw new Error(`HTTP ${res.status}`);
|
|
859
|
+
const data = (await res.json());
|
|
860
|
+
const latest = data.version ?? null;
|
|
861
|
+
const upToDate = latest === null || ClientSession.compareVersions(current, latest) >= 0;
|
|
862
|
+
this.emit({
|
|
863
|
+
type: "update_status",
|
|
864
|
+
current,
|
|
865
|
+
latest,
|
|
866
|
+
upToDate,
|
|
867
|
+
pendingRestart: this.pendingRestart,
|
|
868
|
+
});
|
|
869
|
+
}
|
|
870
|
+
catch (err) {
|
|
871
|
+
this.emit({
|
|
872
|
+
type: "update_status",
|
|
873
|
+
current,
|
|
874
|
+
latest: null,
|
|
875
|
+
upToDate: false,
|
|
876
|
+
pendingRestart: this.pendingRestart,
|
|
877
|
+
error: `检查更新失败:${err.message}`,
|
|
878
|
+
});
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
/** npm i -g pi-web-ui@latest — the new code only takes effect after a restart. */
|
|
882
|
+
async updateApp() {
|
|
883
|
+
try {
|
|
884
|
+
this.emit({
|
|
885
|
+
type: "notice",
|
|
886
|
+
level: "info",
|
|
887
|
+
text: "正在更新 pi-web-ui(npm i -g pi-web-ui@latest)…",
|
|
888
|
+
});
|
|
889
|
+
const { code, out } = await this.runAsync("npm", ["i", "-g", "pi-web-ui@latest"], 180_000);
|
|
890
|
+
if (code === 0) {
|
|
891
|
+
this.pendingRestart = true;
|
|
892
|
+
this.emit({
|
|
893
|
+
type: "update_result",
|
|
894
|
+
ok: true,
|
|
895
|
+
detail: out.slice(0, 400),
|
|
896
|
+
});
|
|
897
|
+
this.emit({
|
|
898
|
+
type: "notice",
|
|
899
|
+
level: "info",
|
|
900
|
+
text: "✅ 已更新 pi-web-ui,重启服务后生效(pi-web-ui server restart)",
|
|
901
|
+
});
|
|
902
|
+
}
|
|
903
|
+
else {
|
|
904
|
+
this.emit({
|
|
905
|
+
type: "update_result",
|
|
906
|
+
ok: false,
|
|
907
|
+
detail: `npm i 失败(${code ?? "timeout"}):${out.slice(0, 400)}`,
|
|
908
|
+
});
|
|
909
|
+
this.emit({
|
|
910
|
+
type: "notice",
|
|
911
|
+
level: "error",
|
|
912
|
+
text: `更新 pi-web-ui 失败(${code ?? "timeout"}):${out.slice(0, 300)}`,
|
|
913
|
+
});
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
catch (err) {
|
|
917
|
+
this.emit({
|
|
918
|
+
type: "update_result",
|
|
919
|
+
ok: false,
|
|
920
|
+
detail: String(err),
|
|
921
|
+
});
|
|
922
|
+
this.emit({
|
|
923
|
+
type: "notice",
|
|
924
|
+
level: "error",
|
|
925
|
+
text: `更新 pi-web-ui 失败:${err.message}`,
|
|
926
|
+
});
|
|
927
|
+
}
|
|
928
|
+
// Re-check so the UI reflects the new state (pendingRestart included).
|
|
929
|
+
void this.checkUpdate();
|
|
930
|
+
}
|
|
820
931
|
async installPiAgent() {
|
|
821
932
|
try {
|
|
822
933
|
mkdirSync(this.agentDir, { recursive: true });
|
package/dist/server/index.js
CHANGED
|
@@ -163,6 +163,12 @@ wss.on("connection", (ws) => {
|
|
|
163
163
|
case "complete_path":
|
|
164
164
|
void cs.completePath(msg.path);
|
|
165
165
|
break;
|
|
166
|
+
case "check_update":
|
|
167
|
+
void cs.checkUpdate();
|
|
168
|
+
break;
|
|
169
|
+
case "update_app":
|
|
170
|
+
void cs.updateApp();
|
|
171
|
+
break;
|
|
166
172
|
case "dialog_response":
|
|
167
173
|
cs.resolveDialog(msg.id, msg.value);
|
|
168
174
|
break;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-web-ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Web chat interface for the pi coding agent, powered by the pi SDK (@earendil-works/pi-coding-agent) — one-command run, Docker/systemd/launchd deployable",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|