The legacy application - its src, tests, landing site, promo assets, docs, release tooling, CI workflows, and root configs - leaves the tree; it stays reachable in history. Everything under AgentCompany-New moves up unchanged: same package name, so the production userData/database path is untouched, and e2e/build scripts already resolved paths relative to the project. The developer cred.txt stays gitignored at its new location. Full verify:ci passes from the new root.
22 lines
1.1 KiB
TypeScript
22 lines
1.1 KiB
TypeScript
import { isAbsolute, relative, resolve, sep } from "node:path";
|
|
|
|
/**
|
|
* Resolves a caller-supplied relative path against a workspace root and rejects
|
|
* anything that escapes it (absolute paths or `..` traversal). Both writing a
|
|
* deliverable and ingesting one back as a file object go through here, so an
|
|
* agent-supplied path can only ever land inside the folder the operator bound
|
|
* to the company — never `../../.ssh/id_rsa`.
|
|
*/
|
|
export function resolveWorkspacePath(workspaceRoot: string, relativePath: string): { absolute: string; relativePosix: string } {
|
|
const root = resolve(workspaceRoot);
|
|
const requested = relativePath.trim().replace(/^[\\/]+/, "");
|
|
if (!requested) throw new Error("Workspace path is required.");
|
|
if (isAbsolute(requested)) throw new Error("Workspace path must be relative to the workspace.");
|
|
const absolute = resolve(root, requested);
|
|
const rel = relative(root, absolute);
|
|
if (rel === "" || rel.startsWith("..") || isAbsolute(rel)) {
|
|
throw new Error("Workspace path escapes the workspace root.");
|
|
}
|
|
return { absolute, relativePosix: rel.split(sep).join("/") };
|
|
}
|