im_wower
·
2026-03-21
paths.ts
1import {
2 DEFAULT_RUN_LAYOUT_VERSION,
3 DEFAULT_RUNS_DIRECTORY_NAME,
4 type LocalRunDirectoryRequest,
5 type LocalRunLogTargets,
6 type LocalRunPaths
7} from "./contracts";
8
9function trimTrailingSlashes(value: string): string {
10 const trimmed = value.replace(/\/+$/u, "");
11
12 return trimmed === "" ? "/" : trimmed;
13}
14
15function sanitizePathSegment(value: string): string {
16 const trimmed = value.trim().replace(/^\/+|\/+$/gu, "");
17
18 if (trimmed === "") {
19 return "_";
20 }
21
22 return trimmed.replace(/[\\/]+/gu, "_");
23}
24
25function joinPath(basePath: string, segment: string): string {
26 const normalizedBasePath = trimTrailingSlashes(basePath);
27
28 if (normalizedBasePath === "/") {
29 return `/${segment}`;
30 }
31
32 return `${normalizedBasePath}/${segment}`;
33}
34
35export function createLocalRunPaths(request: LocalRunDirectoryRequest): LocalRunPaths {
36 const runsRootDir =
37 request.runsRootDir === undefined
38 ? joinPath(request.repoRoot, DEFAULT_RUNS_DIRECTORY_NAME)
39 : trimTrailingSlashes(request.runsRootDir);
40 const taskRunsDir = joinPath(runsRootDir, sanitizePathSegment(request.taskId));
41 const runDir = joinPath(taskRunsDir, sanitizePathSegment(request.runId));
42 const checkpointsDir = joinPath(runDir, "checkpoints");
43 const artifactsDir = joinPath(runDir, "artifacts");
44
45 return {
46 layoutVersion: DEFAULT_RUN_LAYOUT_VERSION,
47 repoRoot: trimTrailingSlashes(request.repoRoot),
48 runsRootDir,
49 taskRunsDir,
50 runDir,
51 checkpointsDir,
52 artifactsDir,
53 metaPath: joinPath(runDir, "meta.json"),
54 statePath: joinPath(runDir, "state.json"),
55 workerLogPath: joinPath(runDir, "worker.log"),
56 stdoutLogPath: joinPath(runDir, "stdout.log"),
57 stderrLogPath: joinPath(runDir, "stderr.log")
58 };
59}
60
61export function createLocalRunLogTargets(paths: LocalRunPaths): LocalRunLogTargets {
62 return {
63 worker: {
64 channel: "worker",
65 filePath: paths.workerLogPath
66 },
67 stdout: {
68 channel: "stdout",
69 filePath: paths.stdoutLogPath
70 },
71 stderr: {
72 channel: "stderr",
73 filePath: paths.stderrLogPath
74 }
75 };
76}