commit 381be8f9a8108c46bd95b6ee032bcda6277190b9
parent 8487b6f5a8c51929f064aafd4fd030cbd7b5946c
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date: Mon, 28 Sep 2026 11:54:47 -0400
umtool: CHANNELS_DIR from the checkout, not one machine's home directory
lib/paths.mjs gains REPO_ROOT, a cwd walk to pnpm-workspace.yaml (not
import.meta.url: Turbopack rewrites module URLs in the app, the SONG_CODE
rule), and CHANNELS_DIR falls back to TRANSCRIPTS_DIR/channels, then
<checkout>/transcripts/channels. report.mjs's GLOBAL_CHANNELS_DIR returns
that one value instead of repeating the literal. cues.mjs is unchanged.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Diffstat:
2 files changed, 41 insertions(+), 5 deletions(-)
diff --git a/umtool/lib/paths.mjs b/umtool/lib/paths.mjs
@@ -4,6 +4,7 @@
// directory is read and which is written must not be able to differ between
// `umtool ls` and the page it is supposed to describe. lib/paths.ts re-exports
// everything here with types; nothing computes a root twice.
+import { existsSync } from "node:fs";
import os from "node:os";
import path from "node:path";
import { SONG_DATA } from "../song/paths.mjs";
@@ -79,11 +80,44 @@ const dedupe = (list) => [...new Set(list.map((p) => path.resolve(p)))];
// render over it.
//
// Same env var the cue reader already uses (lib/projects/report.mjs
-// GLOBAL_CHANNELS_DIR), so a fixture that confines one confines both.
+// GLOBAL_CHANNELS_DIR, which now returns this one), so a fixture that confines
+// one confines both.
+//
+// With neither CHANNELS_DIR nor TRANSCRIPTS_DIR set, it is the checkout's own
+// transcripts/channels -- the corpus a plain checkout would have. It used to be
+// an absolute path in one machine's home directory, which every other clone
+// silently looked for and never found.
// ---------------------------------------------------------------------------
+
+/**
+ * The checkout this runs in: the nearest directory at or above `start` holding
+ * pnpm-workspace.yaml, or `start`'s parent when there is none.
+ *
+ * Walked from the CWD, not from import.meta.url: the Next app imports this
+ * module (eleven API routes), and Turbopack rewrites module URLs into
+ * .next/server/chunks, so a path derived from one points at the build output
+ * -- the SONG_CODE rule in lib/paths.ts. `next dev`, `next start` and the CLI
+ * all run with cwd inside the checkout (the app at umtool/, which is what the
+ * fallback assumes). report-to-video/cues.mjs keeps its import.meta.url walk:
+ * only its CLI entry points (build-video, resolve-windows) read that default.
+ */
+export function findRepoRoot(start) {
+ let dir = path.resolve(start);
+ for (;;) {
+ if (existsSync(path.join(dir, "pnpm-workspace.yaml"))) return dir;
+ const up = path.dirname(dir);
+ if (up === dir) return path.resolve(start, "..");
+ dir = up;
+ }
+}
+
+export const REPO_ROOT = findRepoRoot(process.cwd());
+
export const CHANNELS_DIR = path.resolve(
process.env.CHANNELS_DIR ??
- "/home/user/Projects/yt-dlp-transcript-browser/transcripts/channels",
+ (process.env.TRANSCRIPTS_DIR
+ ? path.join(process.env.TRANSCRIPTS_DIR, "channels")
+ : path.join(REPO_ROOT, "transcripts", "channels")),
);
export const READ_ROOTS = dedupe(
diff --git a/umtool/lib/projects/report.mjs b/umtool/lib/projects/report.mjs
@@ -9,6 +9,7 @@ import { readdir, readFile, stat } from "node:fs/promises";
import path from "node:path";
import { DEFAULT_VARIANT, cachedWindowsFor } from "umtool-report-to-video/build-video";
import { rawCacheOf } from "../report/raw-cache.mjs";
+import { CHANNELS_DIR } from "../paths.mjs";
import { channelName, cleanTitle } from "umtool-report-to-video/attribution";
/**
@@ -35,9 +36,10 @@ export { widen };
export const MANIFEST_NAME = "video.manifest.json";
-export const GLOBAL_CHANNELS_DIR = () =>
- process.env.CHANNELS_DIR ??
- "/home/user/Projects/yt-dlp-transcript-browser/transcripts/channels";
+// ONE definition: lib/paths.mjs's CHANNELS_DIR (the env var, else
+// TRANSCRIPTS_DIR/channels, else the checkout's own transcripts/channels). The
+// bench's read root and this reader cannot disagree about which corpus it is.
+export const GLOBAL_CHANNELS_DIR = () => CHANNELS_DIR;
/** The conventional name make-shadow-channels.sh builds. */
export const SHADOW_CHANNELS = ".shadow-channels";