fix: list and open sessions across project directories

Sessions outside the server's launch directory were invisible and returned
404 on open, leaving the model picker empty. List without the SDK's
process-cwd filter and normalize working directories at the API boundary and
when reading stored session data, tolerating separator/normalization
differences (including Windows backslash vs forward slash). Requires Pi
coding agent SDK 0.78.0 or newer.
This commit is contained in:
Federico Jaramillo Martinez
2026-06-13 11:40:47 +02:00
parent 38cf334c40
commit c0d12222a2
14 changed files with 2342 additions and 2261 deletions
+45
View File
@@ -0,0 +1,45 @@
import { isAbsolute, resolve } from "node:path";
/**
* Working-directory normalization boundaries.
*
* Cwd strings reach the server from three kinds of sources with different trust:
*
* 1. HTTP requests (web UI, federation proxies): normalize strictly with
* `normalizeRequestCwd` at route parsing. Relative paths are rejected instead
* of being silently resolved against the daemon's own working directory.
* 2. Data pi-web writes itself (archive store records): canonicalized on write
* and on load with `canonicalizeStoredCwd`, so internal `===` comparisons are
* safe by construction.
* 3. Data other writers own (Pi session file headers via the SDK): canonicalized
* on read at the gateway, and compared tolerantly with `cwdPathsEqual` where a
* raw value can still appear (e.g. runtime cwd of sessions opened from files).
*
* Inside these boundaries, plain string equality on cwd values is safe.
*/
/**
* Strictly normalize a client-supplied working directory at an HTTP boundary.
* Throws for non-string, empty, or relative input; returns the resolved
* (separator- and trailing-slash-normalized) absolute path otherwise.
*/
export function normalizeRequestCwd(cwd: unknown): string {
if (typeof cwd !== "string" || cwd === "") throw new Error("cwd is required");
if (!isAbsolute(cwd)) throw new Error("cwd must be an absolute path");
return resolve(cwd);
}
/**
* Leniently canonicalize a working directory loaded from stored data.
* Absolute paths are resolved to canonical form; anything else (legacy empty or
* relative values) is preserved as-is so a single bad record cannot fail a whole
* load, and never silently resolves against this process's working directory.
*/
export function canonicalizeStoredCwd(cwd: string): string {
return isAbsolute(cwd) ? resolve(cwd) : cwd;
}
/** Compare two working-directory paths, tolerating separator and normalization differences (e.g. Windows backslash vs forward slash). */
export function cwdPathsEqual(a: string, b: string): boolean {
return resolve(a) === resolve(b);
}