pi-web-ui 0.34.3 → 0.35.1
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 +93 -0
- package/README.zh-CN.md +80 -0
- package/bin/pi-web-ui.mjs +1736 -1722
- package/dist/server/agent-service.js +8 -2
- package/dist/server/index.js +7 -2
- package/dist/server/plugins.js +44 -2
- package/dist/server/protocol-version.js +1 -1
- package/package.json +1 -1
- package/themes/md-preview.css +7167 -7026
- package/themes/white.css +7228 -7087
- package/web/dist/assets/{TerminalPanel-__4r1Djg.js → TerminalPanel-BxezvWth.js} +1 -1
- package/web/dist/assets/index-BP593LGC.js +19 -0
- package/web/dist/assets/index-DduTNQNx.css +10 -0
- package/web/dist/index.html +2 -2
- package/web/dist/assets/index-8y0w43os.css +0 -10
- package/web/dist/assets/index-CITqw531.js +0 -19
|
@@ -2212,8 +2212,14 @@ export class ClientSession {
|
|
|
2212
2212
|
* keeps everything up to (but not including) that question, then sends the
|
|
2213
2213
|
* edited text there. The original thread is untouched and stays in the
|
|
2214
2214
|
* session list, so nothing is ever lost.
|
|
2215
|
+
*
|
|
2216
|
+
* Attachments (attachments) travel through the SAME pipeline as prompt()
|
|
2217
|
+
* — the fork intentionally drops the original attachment asides because
|
|
2218
|
+
* they live on the old branch past the fork point, so the browser re-sends
|
|
2219
|
+
* the images it kept in the edit composer (original image blocks + any
|
|
2220
|
+
* newly pasted/dropped ones). Text-only edits pass undefined.
|
|
2215
2221
|
*/
|
|
2216
|
-
async editMessage(messageId, text) {
|
|
2222
|
+
async editMessage(messageId, text, attachments) {
|
|
2217
2223
|
if (this.quiesceBlocked())
|
|
2218
2224
|
return;
|
|
2219
2225
|
const trimmed = text.trim();
|
|
@@ -2248,7 +2254,7 @@ export class ClientSession {
|
|
|
2248
2254
|
return;
|
|
2249
2255
|
}
|
|
2250
2256
|
await this.bindSession();
|
|
2251
|
-
await this.prompt(trimmed);
|
|
2257
|
+
await this.prompt(trimmed, attachments);
|
|
2252
2258
|
this.emit({
|
|
2253
2259
|
type: "notice",
|
|
2254
2260
|
level: "info",
|
package/dist/server/index.js
CHANGED
|
@@ -521,7 +521,7 @@ wss.on("connection", (ws) => {
|
|
|
521
521
|
void cs.newChat();
|
|
522
522
|
break;
|
|
523
523
|
case "edit_message":
|
|
524
|
-
void cs.editMessage(msg.messageId, msg.text);
|
|
524
|
+
void cs.editMessage(msg.messageId, msg.text, msg.attachments);
|
|
525
525
|
break;
|
|
526
526
|
case "cycle_model":
|
|
527
527
|
void cs.cycleModel();
|
|
@@ -748,7 +748,12 @@ wss.on("connection", (ws) => {
|
|
|
748
748
|
// freshly dropped plugins show up without a server restart.
|
|
749
749
|
pluginMgr
|
|
750
750
|
.ensureLoaded()
|
|
751
|
-
.then((plugins) =>
|
|
751
|
+
.then((plugins) => {
|
|
752
|
+
send({ type: "plugins", plugins, epoch: pluginMgr.epoch });
|
|
753
|
+
// 让各插件向新接入的客户端推送自身初始状态(onAttach 钩子)——
|
|
754
|
+
// 插件不要依赖客户端挂载后自己拉(见 plugins.ts onAttach 注释)。
|
|
755
|
+
pluginMgr.notifyAttach(cid);
|
|
756
|
+
})
|
|
752
757
|
.catch(() => { });
|
|
753
758
|
// Replay anything that arrived while the session was starting.
|
|
754
759
|
const queued = pending;
|
package/dist/server/plugins.js
CHANGED
|
@@ -101,12 +101,33 @@ export class PluginManager {
|
|
|
101
101
|
this.deliverAll({ type: "plugins", plugins: list, epoch: this.epochCounter });
|
|
102
102
|
}
|
|
103
103
|
/** 服务端热重载:反激活全部 → 清缓存 → 重扫重激活 → epoch+1。
|
|
104
|
-
*
|
|
104
|
+
* 返回新目录清单(含激活结果)。重激活后的插件实例是新模块,
|
|
105
|
+
* 内存状态为初始值——逐个客户端触发 onAttach 让它们重推自身状态。 */
|
|
105
106
|
async reload() {
|
|
106
107
|
this.dispose();
|
|
107
108
|
this.attempted.clear();
|
|
108
109
|
this.epochCounter += 1;
|
|
109
|
-
|
|
110
|
+
const list = await this.ensureLoaded();
|
|
111
|
+
for (const s of this.senders) {
|
|
112
|
+
const cid = s.cid();
|
|
113
|
+
if (cid)
|
|
114
|
+
this.notifyAttach(cid);
|
|
115
|
+
}
|
|
116
|
+
return list;
|
|
117
|
+
}
|
|
118
|
+
/** 每个客户端 attach 后调用:让各插件向该客户端推送自身完整状态。
|
|
119
|
+
* 异常隔离——单个插件钩子报错不影响其他插件与其他钩子。 */
|
|
120
|
+
notifyAttach(clientId) {
|
|
121
|
+
for (const [id, p] of this.loaded) {
|
|
122
|
+
for (const h of p.attachHandlers) {
|
|
123
|
+
try {
|
|
124
|
+
h(clientId);
|
|
125
|
+
}
|
|
126
|
+
catch (err) {
|
|
127
|
+
console.error(`[plugin:${id}] onAttach handler failed:`, err);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
110
131
|
}
|
|
111
132
|
/** agent-service 调:把 SDK 工具执行事件扇出给所有插件(异常隔离)。 */
|
|
112
133
|
emitToolEvent(ev) {
|
|
@@ -265,6 +286,19 @@ export class PluginManager {
|
|
|
265
286
|
icon: typeof m.icon === "string" && m.icon.trim() ? m.icon.trim() : undefined,
|
|
266
287
|
hasClient: existsSync(join(dir, "client", "entry.mjs")),
|
|
267
288
|
error: this.loaded.get(name)?.info.error,
|
|
289
|
+
// 安装来源(pi-web-ui install 写入的 .pi-source.json)——
|
|
290
|
+
// 设置面板据此显示「更新」按钮;手工拷入的插件没有此文件。
|
|
291
|
+
source: await readFile(join(dir, ".pi-source.json"), "utf8")
|
|
292
|
+
.then((raw) => {
|
|
293
|
+
try {
|
|
294
|
+
const s = JSON.parse(raw);
|
|
295
|
+
return typeof s.source === "string" && s.source ? s.source : undefined;
|
|
296
|
+
}
|
|
297
|
+
catch {
|
|
298
|
+
return undefined;
|
|
299
|
+
}
|
|
300
|
+
})
|
|
301
|
+
.catch(() => undefined),
|
|
268
302
|
});
|
|
269
303
|
}
|
|
270
304
|
catch {
|
|
@@ -279,7 +313,9 @@ export class PluginManager {
|
|
|
279
313
|
const handlers = new Set();
|
|
280
314
|
this.messageHandlers.set(info.id, handlers);
|
|
281
315
|
const toolHandlers = new Set();
|
|
316
|
+
const attachHandlers = new Set();
|
|
282
317
|
const unregisterTools = [];
|
|
318
|
+
const p = { info, toolHandlers, attachHandlers };
|
|
283
319
|
const host = {
|
|
284
320
|
broadcast: (payload) => this.broadcast(info.id, payload),
|
|
285
321
|
notify: (level, text) => this.notifyAll(level, text),
|
|
@@ -292,6 +328,10 @@ export class PluginManager {
|
|
|
292
328
|
toolHandlers.add(h);
|
|
293
329
|
return () => toolHandlers.delete(h);
|
|
294
330
|
},
|
|
331
|
+
onAttach: (h) => {
|
|
332
|
+
attachHandlers.add(h);
|
|
333
|
+
return () => attachHandlers.delete(h);
|
|
334
|
+
},
|
|
295
335
|
// 包一层:插件反激活时自动注销它注册的全部 AI 工具,不留悬挂项。
|
|
296
336
|
registerAgentTool: (tool) => {
|
|
297
337
|
const off = this.registerAgentTool(info.id, tool);
|
|
@@ -317,6 +357,7 @@ export class PluginManager {
|
|
|
317
357
|
info: { ...info },
|
|
318
358
|
deactivate: typeof ret === "function" ? ret : undefined,
|
|
319
359
|
toolHandlers,
|
|
360
|
+
attachHandlers,
|
|
320
361
|
agentToolUnsubscribers: unregisterTools,
|
|
321
362
|
});
|
|
322
363
|
console.log(`[plugin:${info.id}] activated (v${info.version ?? "?"})`);
|
|
@@ -325,6 +366,7 @@ export class PluginManager {
|
|
|
325
366
|
this.loaded.set(info.id, {
|
|
326
367
|
info: { ...info, error: err.message },
|
|
327
368
|
toolHandlers,
|
|
369
|
+
attachHandlers,
|
|
328
370
|
});
|
|
329
371
|
console.error(`[plugin:${info.id}] activate failed:`, err);
|
|
330
372
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-web-ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.35.1",
|
|
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",
|