Add workspace side panel with files and git

This commit is contained in:
Federico Jaramillo Martinez
2026-05-07 23:27:38 +02:00
parent 34994705e4
commit ba8f74bee2
15 changed files with 799 additions and 6 deletions
+35
View File
@@ -0,0 +1,35 @@
import { realpath } from "node:fs/promises";
import { isAbsolute, join, relative, sep } from "node:path";
export async function resolveInsideWorkspace(rootPath: string, relativePath: string | undefined): Promise<{ root: string; target: string; relativePath: string }> {
const requested = normalizeRelativePath(relativePath);
const root = await realpath(rootPath);
const joined = join(root, requested);
const target = await realpath(joined);
ensureInside(root, target);
return { root, target, relativePath: requested };
}
export async function resolveParentInsideWorkspace(rootPath: string, relativePath: string): Promise<{ root: string; target: string; relativePath: string }> {
const requested = normalizeRelativePath(relativePath);
const root = await realpath(rootPath);
const target = join(root, requested);
ensureInside(root, target);
return { root, target, relativePath: requested };
}
export function normalizeRelativePath(input: string | undefined): string {
const value = input ?? "";
if (value === "" || value === ".") return "";
if (isAbsolute(value)) throw new Error("Absolute paths are not allowed");
const parts = value.split(/[\\/]+/).filter((part) => part !== "" && part !== ".");
if (parts.some((part) => part === "..")) throw new Error("Path traversal is not allowed");
return parts.join("/");
}
function ensureInside(root: string, target: string): void {
const rel = relative(root, target);
if (rel === "") return;
if (rel.startsWith("..") || isAbsolute(rel)) throw new Error("Path escapes workspace");
if (sep !== "/" && rel.split(sep).includes("..")) throw new Error("Path escapes workspace");
}