feat(dsh-plugin): better-sidebar 集成、会话关停与归档清理、悬浮窗修复 (#130)

* better-sidebar 集成:observation 视图迁入 better-sidebar 载体,按会话作用域展示 bsk 会话
* 会话关停与归档清理:支持会话 dispose 与归档自动清理
* 悬浮窗修复:悬浮 overlay 拖拽/缩放/PiP 弹出等问题修复
* 修复 Document PiP 空白窗口:载体卸载(关 tab、切会话、插件 HMR)时主动 close() PiP 窗口,避免残留空白窗口
This commit is contained in:
BB-fat
2026-08-25 10:33:46 +08:00
committed by GitHub
parent 4b6cdde168
commit a004291848
19 changed files with 1583 additions and 98 deletions
@@ -8,6 +8,7 @@
* GET /bsk-observation/state → { sessions, available }
* GET /bsk-observation/events → SSE stream of ObservationEvent
* POST /bsk-observation/interrupt → body {sessionId?} → {interrupted: boolean}
* POST /bsk-observation/stop → body {sessionId} → {stopped: boolean}
* GET /bsk-observation/thumbnail/<attachmentId> → image bytes
*
* Routes exist only when a webServer service is mounted (web composition);
@@ -166,6 +167,42 @@ export function registerObservationRoutes(
});
},
}),
webServer.register({
kind: "exact",
path: `${ROUTE_BASE}/stop`,
handler: (req, res) => {
if (req.method !== "POST") {
sendJson(res, 405, { error: "method not allowed" });
return;
}
if (fenceRejected(req, res)) return;
let body = "";
req.on("data", (chunk: Buffer | string) => {
body += chunk;
});
req.on("end", () => {
let sessionId: string | undefined;
try {
const parsed = JSON.parse(body || "{}") as { sessionId?: unknown };
if (typeof parsed.sessionId === "string" && parsed.sessionId !== "") {
sessionId = parsed.sessionId;
}
} catch {
sendJson(res, 400, { error: "invalid JSON body" });
return;
}
// A destructive call always names its target (never "current").
if (sessionId === undefined) {
sendJson(res, 400, { error: "sessionId required" });
return;
}
void observation.stopSession(sessionId).then(
(stopped) => sendJson(res, 200, { stopped }),
() => sendJson(res, 500, { error: "stop failed" }),
);
});
},
}),
webServer.register({
kind: "prefix",
path: `${ROUTE_BASE}/thumbnail`,