session-paths.ts

 1// SPDX-FileCopyrightText: Amolith <amolith@secluded.site>
 2// SPDX-FileCopyrightText: Petr Baudis <pasky@ucw.cz>
 3//
 4// SPDX-License-Identifier: MIT
 5
 6import * as fs from "node:fs";
 7import * as path from "node:path";
 8import { getAgentDir } from "@earendil-works/pi-coding-agent";
 9
10export function getSessionsRoot(sessionFile: string | undefined): string | undefined {
11	if (!sessionFile) return undefined;
12	const normalized = sessionFile.replace(/\\/g, "/");
13	const marker = "/sessions/";
14	const idx = normalized.indexOf(marker);
15	if (idx === -1) {
16		return path.dirname(path.resolve(sessionFile));
17	}
18	return normalized.slice(0, idx + marker.length - 1);
19}
20
21export function getFallbackSessionsRoot(): string | undefined {
22	const candidate = path.resolve(getAgentDir(), "sessions");
23	return fs.existsSync(candidate) ? candidate : undefined;
24}
25
26export function normalizeSessionPath(sessionPath: string, sessionsRoot: string | undefined): string {
27	if (path.isAbsolute(sessionPath)) return path.resolve(sessionPath);
28	if (sessionsRoot) return path.resolve(sessionsRoot, sessionPath);
29	return path.resolve(sessionPath);
30}
31
32export function sessionPathAllowed(candidate: string, sessionsRoot: string | undefined): boolean {
33	if (!sessionsRoot) return false; // fail closed when root unknown
34	const root = path.resolve(sessionsRoot);
35	const resolved = path.resolve(candidate);
36	return resolved === root || resolved.startsWith(`${root}${path.sep}`);
37}