hunian
feat: Implement agentfs-just-bash backend with internal and public session management
c60f42b | /** | |
| * 调试 API 的路径解析与校验。 | |
| * | |
| * 数据布局复用 `lib/agentfs/paths.ts`;此处补 session id / 虚拟路径 / checkpoint 校验。 | |
| */ | |
| import { basename, join, resolve } from "node:path"; | |
| import { | |
| AGENTFS_BACKEND_NAME, | |
| resolveDataDir as resolveDataDirFromAppRoot, | |
| resolveSessionsDir as resolveSessionsDirFromDataDir, | |
| } from "../agentfs/paths.js"; | |
| import { CHECKPOINT_NAME_RE, SESSION_ID_RE } from "./constants.js"; | |
| import { AgentFsDebugError } from "./errors.js"; | |
| export { AGENTFS_BACKEND_NAME }; | |
| /** 数据目录根:`EVEAGENT_DATA_DIR` 优先,否则 `<cwd>/data`。 */ | |
| export function resolveDataDir(): string { | |
| return resolveDataDirFromAppRoot(); | |
| } | |
| /** sessions 目录绝对路径。 */ | |
| export function resolveSessionsDir(): string { | |
| return resolveSessionsDirFromDataDir(resolveDataDir()); | |
| } | |
| /** 校验 session id,防止路径穿越。 */ | |
| export function assertSessionId(id: string): string { | |
| if (!SESSION_ID_RE.test(id)) { | |
| throw new AgentFsDebugError(400, "invalid_session_id", "session id 非法"); | |
| } | |
| return id; | |
| } | |
| /** | |
| * 解析虚拟 FS 路径:必须为绝对路径、无 `..`、无空字节。 | |
| * 空或 `/` → `/`。 | |
| */ | |
| export function normalizeVirtualPath(raw: string | null | undefined): string { | |
| const input = (raw ?? "/").trim() || "/"; | |
| if (input.includes("\0")) { | |
| throw new AgentFsDebugError(400, "invalid_path", "路径含非法字符"); | |
| } | |
| const withSlash = input.startsWith("/") ? input : `/${input}`; | |
| const parts = withSlash.split("/").filter((p) => p.length > 0); | |
| const out: string[] = []; | |
| for (const part of parts) { | |
| if (part === ".") continue; | |
| if (part === "..") { | |
| throw new AgentFsDebugError(400, "invalid_path", "路径不允许包含 .."); | |
| } | |
| out.push(part); | |
| } | |
| return out.length === 0 ? "/" : `/${out.join("/")}`; | |
| } | |
| /** 将 session id 解析为磁盘上的 .db 绝对路径(id 已禁止路径分隔符)。 */ | |
| export function resolveSessionDbPath(sessionId: string): string { | |
| const id = assertSessionId(sessionId); | |
| const sessionsDir = resolveSessionsDir(); | |
| const dbPath = resolve(join(sessionsDir, `${id}.db`)); | |
| if (basename(dbPath) !== `${id}.db`) { | |
| throw new AgentFsDebugError(400, "invalid_session_id", "session 路径越界"); | |
| } | |
| return dbPath; | |
| } | |
| /** checkpoints 目录:`<sessionsDir>/checkpoints/<sessionId>/` */ | |
| export function resolveCheckpointsDir(sessionId: string): string { | |
| return join(resolveSessionsDir(), "checkpoints", assertSessionId(sessionId)); | |
| } | |
| /** 单个存档点 .db 文件路径。 */ | |
| export function resolveCheckpointDbPath( | |
| sessionId: string, | |
| name: string, | |
| ): string { | |
| if (!CHECKPOINT_NAME_RE.test(name)) { | |
| throw new AgentFsDebugError( | |
| 400, | |
| "invalid_checkpoint_name", | |
| "存档点名非法(允许中文、字母、数字、._-)", | |
| ); | |
| } | |
| return join(resolveCheckpointsDir(sessionId), `${name}.db`); | |
| } | |
| /** 拼接虚拟目录下的子路径。 */ | |
| export function joinVirtualPath(dir: string, name: string): string { | |
| return dir === "/" ? `/${name}` : `${dir}/${name}`; | |
| } | |