Files
sproutclaw/.pi/agent/extensions/webui/backend/routes/sessions.ts
shumengya d51a055d78
Some checks failed
CI / build-check-test (push) Has been cancelled
npm audit / audit (push) Has been cancelled
feat: update webui extensions, models, and agent config
2026-06-10 21:45:53 +08:00

130 lines
4.4 KiB
TypeScript

import type { IncomingMessage, ServerResponse } from "node:http";
import {
appendSessionName,
buildSessionListResponse,
deleteSessionFile,
pinSession,
readSessionMessages,
readSessionSummary,
resolveSessionFile,
} from "../services/sessions.ts";
import type { WebUiContext } from "../types/context.ts";
import { isSameResolvedPath } from "../utils/paths.ts";
import { json, readBody } from "../http/request.ts";
export function handleSessionsRoute(
req: IncomingMessage,
res: ServerResponse,
ctx: WebUiContext,
pathname: string,
): boolean {
const { paths } = ctx.config;
const { sendCmd } = ctx.rpc;
if (req.method === "POST" && pathname === "/api/new-session") {
void sendCmd({ type: "new_session" })
.then(async (r: any) => {
if (!r.success) return json(res, { error: r.error }, 500);
if (r.data?.cancelled) return json(res, r.data);
const state = await sendCmd({ type: "get_state" });
const sessionFile = state.success ? state.data?.sessionFile : undefined;
return json(res, { ...r.data, sessionFile });
})
.catch((err) => json(res, { error: err.message }, 500));
return true;
}
if (req.method === "GET" && pathname === "/api/sessions") {
json(res, buildSessionListResponse(paths));
return true;
}
if (req.method === "POST" && pathname === "/api/sessions/history") {
void readBody(req)
.then(({ path: sp }) => {
const messages = readSessionMessages(sp as string);
const summary = readSessionSummary(paths, sp as string);
json(res, { messages, session: summary });
})
.catch((err) => json(res, { error: err.message }, 500));
return true;
}
if (req.method === "POST" && pathname === "/api/sessions/delete") {
void readBody(req)
.then(({ path: sp }) => {
deleteSessionFile(paths, sp as string);
json(res, { ok: true });
})
.catch((err) => json(res, { error: err.message }, 500));
return true;
}
if (req.method === "POST" && pathname === "/api/sessions/pin") {
void readBody(req)
.then(({ path: sp, pinned }) => {
const result = pinSession(paths, sp as string, Boolean(pinned));
json(res, { ok: true, ...result });
})
.catch((err) => json(res, { error: err.message }, 500));
return true;
}
if (req.method === "POST" && pathname === "/api/sessions/load") {
void readBody(req)
.then(async ({ path: sp }) => {
const sw = await sendCmd({ type: "switch_session", sessionPath: sp, cwdOverride: paths.repoRoot });
if (!sw.success) throw new Error(sw.error);
const mr = await sendCmd({ type: "get_messages" });
if (!mr.success) throw new Error(mr.error);
const summary = readSessionSummary(paths, sp as string);
json(res, { messages: mr.data.messages, session: summary });
})
.catch((err) => json(res, { error: err.message }, 500));
return true;
}
if (req.method === "POST" && pathname === "/api/sessions/activate") {
void readBody(req)
.then(async ({ path: sp }) => {
const sw = await sendCmd({ type: "switch_session", sessionPath: sp, cwdOverride: paths.repoRoot });
if (!sw.success) throw new Error(sw.error);
const state = await sendCmd({ type: "get_state" });
if (!state.success) throw new Error(state.error);
json(res, { ok: true, state: state.data });
})
.catch((err) => json(res, { error: err.message }, 500));
return true;
}
if (req.method === "POST" && pathname === "/api/sessions/name") {
void readBody(req)
.then(async ({ path: sp, name }) => {
if (typeof sp !== "string" || !sp.trim()) throw new Error("无效会话路径");
const savedName = appendSessionName(paths, sp, typeof name === "string" ? name : "");
const sessionPath = resolveSessionFile(paths, sp);
const state = await sendCmd({ type: "get_state" });
if (
state.success &&
state.data?.sessionFile &&
isSameResolvedPath(String(state.data.sessionFile), sessionPath)
) {
const rename = await sendCmd({ type: "set_session_name", name: savedName });
if (!rename.success) throw new Error(rename.error || "同步当前会话名称失败");
}
json(res, { ok: true, name: savedName });
})
.catch((err) => json(res, { error: err.message }, 500));
return true;
}
if (req.method === "GET" && pathname === "/api/session-state") {
void sendCmd({ type: "get_state" })
.then((r: any) => (r.success ? json(res, r.data) : json(res, { error: r.error }, 500)))
.catch((err) => json(res, { error: err.message }, 500));
return true;
}
return false;
}