From dabb0f5b39093eb76e00d726262ae74cd265cac1 Mon Sep 17 00:00:00 2001 From: Miguel Angel Simon Sierra Date: Thu, 29 Oct 2026 00:47:34 -0400 Subject: [PATCH] fix: cache paths follow HYPERFRAMES_CACHE_DIR Every place HyperFrames keeps downloaded or built files now takes its folder from one helper, hyperframesCacheDir() in @hyperframes/core. The default stays ~/.cache/hyperframes; HYPERFRAMES_CACHE_DIR moves it. --- docs/packages/cli.mdx | 3 + .../cli/src/audio/analysis/providers/apple.ts | 4 +- .../cli/src/background-removal/coremlTemp.ts | 11 +--- .../cli/src/background-removal/manager.ts | 5 +- packages/cli/src/browser/manager.ts | 5 +- packages/cli/src/cloud/offload.ts | 7 ++- .../src/commands/lambda/prebuiltHandler.ts | 4 +- packages/cli/src/tts/manager.ts | 4 +- packages/cli/src/tts/synthesize.ts | 4 +- packages/cli/src/utils/optionalPackages.ts | 4 +- packages/cli/src/warmCheckProtocol.ts | 3 +- packages/cli/src/whisper/manager.ts | 9 +-- packages/cli/src/whisper/sherpa.ts | 10 +--- packages/core/package.json | 10 ++++ packages/core/src/cacheDir.test.ts | 60 +++++++++++++++++++ packages/core/src/cacheDir.ts | 9 +++ packages/core/src/fonts/deterministicFonts.ts | 5 +- packages/core/src/fonts/fontCompression.ts | 5 +- .../engine/src/services/browserManager.ts | 3 +- packages/inspector/src/service.ts | 4 +- .../src/history/projectHistory.ts | 4 +- 21 files changed, 126 insertions(+), 47 deletions(-) create mode 100644 packages/core/src/cacheDir.test.ts create mode 100644 packages/core/src/cacheDir.ts diff --git a/docs/packages/cli.mdx b/docs/packages/cli.mdx index f21de16913..bf5e526df7 100644 --- a/docs/packages/cli.mdx +++ b/docs/packages/cli.mdx @@ -1835,6 +1835,9 @@ default 3); `--json` prints the results as JSON. ## Keep the environment healthy +HyperFrames keeps what it downloads and builds (the headless browser, models, optional packages, fonts and project +history) under `~/.cache/hyperframes`. Set `HYPERFRAMES_CACHE_DIR` to keep it somewhere else. + ### `doctor` Check the machine for everything a render needs. diff --git a/packages/cli/src/audio/analysis/providers/apple.ts b/packages/cli/src/audio/analysis/providers/apple.ts index 36e24a6348..ce3147147b 100644 --- a/packages/cli/src/audio/analysis/providers/apple.ts +++ b/packages/cli/src/audio/analysis/providers/apple.ts @@ -1,10 +1,10 @@ import { createHash } from "node:crypto"; import { existsSync } from "node:fs"; import { mkdir, rename, writeFile } from "node:fs/promises"; -import { homedir } from "node:os"; import { join } from "node:path"; import type { AudioAnalysisProvider, AudioSignal } from "@hyperframes/core/audio-analysis"; import { AVAILABLE, runFile, unavailable, withWavFile } from "./shared.js"; +import { hyperframesCacheDir } from "@hyperframes/core/cache-dir"; const SOUND_ANALYSIS = "/System/Library/Frameworks/SoundAnalysis.framework"; const MUSIC_UNDERSTANDING_MACOS = 27; @@ -62,7 +62,7 @@ function atLeastOneWindow(signal: AudioSignal): AudioSignal { }; } -const helperDir = () => join(homedir(), ".cache", "hyperframes", "audio-helpers"); +const helperDir = () => hyperframesCacheDir("audio-helpers"); function helperPath(name: string, source: string): string { const hash = createHash("sha256").update(source).digest("hex").slice(0, 12); diff --git a/packages/cli/src/background-removal/coremlTemp.ts b/packages/cli/src/background-removal/coremlTemp.ts index 1b92779995..3d1fb33f5f 100644 --- a/packages/cli/src/background-removal/coremlTemp.ts +++ b/packages/cli/src/background-removal/coremlTemp.ts @@ -1,17 +1,12 @@ import { mkdirSync, readdirSync, readFileSync, rmSync, writeFileSync } from "node:fs"; -import { homedir, tmpdir } from "node:os"; +import { tmpdir } from "node:os"; +import { hyperframesCacheDir } from "@hyperframes/core/cache-dir"; import { basename, join } from "node:path"; import { processIsAlive } from "../utils/processTree.js"; const COMPILED_MODEL = /^onnxruntime-.*\.mlmodelc?$/; -const COREML_TEMP_MANIFESTS = join( - homedir(), - ".cache", - "hyperframes", - "background-removal", - "coreml-temp", -); +const COREML_TEMP_MANIFESTS = hyperframesCacheDir("background-removal", "coreml-temp"); interface Manifest { pid: number; diff --git a/packages/cli/src/background-removal/manager.ts b/packages/cli/src/background-removal/manager.ts index d149c0e2ea..3a37b40dd2 100644 --- a/packages/cli/src/background-removal/manager.ts +++ b/packages/cli/src/background-removal/manager.ts @@ -1,9 +1,10 @@ import { existsSync, mkdirSync } from "node:fs"; -import { homedir, platform, arch } from "node:os"; +import { platform, arch } from "node:os"; import { join } from "node:path"; import { downloadFile } from "../utils/download.js"; +import { hyperframesCacheDir } from "@hyperframes/core/cache-dir"; -export const MODELS_DIR = join(homedir(), ".cache", "hyperframes", "background-removal", "models"); +export const MODELS_DIR = hyperframesCacheDir("background-removal", "models"); export const DEFAULT_MODEL = "u2net_human_seg" as const; export type ModelId = typeof DEFAULT_MODEL; diff --git a/packages/cli/src/browser/manager.ts b/packages/cli/src/browser/manager.ts index 7f21928792..d96e89b944 100644 --- a/packages/cli/src/browser/manager.ts +++ b/packages/cli/src/browser/manager.ts @@ -24,6 +24,7 @@ import { BrowserDownloadStalledError, installInChild } from "./installInChild.js import { normalizeErrorMessage } from "../utils/errorMessage.js"; import { runRenderSetupWorker } from "../utils/cancellableProcess.js"; import { unzipArchive } from "./unzipArchive.js"; +import { hyperframesCacheDir } from "@hyperframes/core/cache-dir"; type PuppeteerBrowsers = typeof import("@puppeteer/browsers"); @@ -39,8 +40,8 @@ async function loadPuppeteerBrowsers(): Promise { } } -const CACHE_ROOT_DIR = join(homedir(), ".cache", "hyperframes"); -const CACHE_DIR = join(homedir(), ".cache", "hyperframes", "chrome"); +const CACHE_ROOT_DIR = hyperframesCacheDir(); +const CACHE_DIR = hyperframesCacheDir("chrome"); const ARCHIVE_PLUS_UNPACKED_SHELL_MB = 512; // Puppeteer's managed cache — where `@puppeteer/browsers install // chrome-headless-shell` (and `puppeteer install`) drop binaries. The engine's diff --git a/packages/cli/src/cloud/offload.ts b/packages/cli/src/cloud/offload.ts index b96128f6dc..26ac8ae2b8 100644 --- a/packages/cli/src/cloud/offload.ts +++ b/packages/cli/src/cloud/offload.ts @@ -15,7 +15,7 @@ import { rmSync, writeFileSync, } from "node:fs"; -import { homedir, tmpdir } from "node:os"; +import { tmpdir } from "node:os"; import { basename, dirname, extname, join, posix, relative, resolve } from "node:path"; import { promisify } from "node:util"; import { parseHTML } from "linkedom"; @@ -41,6 +41,7 @@ import { stagedSize, TEXT_FILE_EXTS, } from "../utils/publishProject.js"; +import { hyperframesCacheDir } from "@hyperframes/core/cache-dir"; const execFileAsync = promisify(execFile); @@ -200,7 +201,7 @@ interface CacheEntry { } function defaultOffloadCachePath(): string { - return join(homedir(), ".cache", "hyperframes", "cloud-assets.json"); + return hyperframesCacheDir("cloud-assets.json"); } function readCache(path: string): Record { @@ -650,7 +651,7 @@ async function prepareEntryGifs( downloadDir: outputDir, outputDir, outputSrcPrefix: posix.relative(posix.dirname(entryPath), GIF_PREFIX), - cacheDir: join(homedir(), ".cache", "hyperframes", "animated-gif"), + cacheDir: hyperframesCacheDir("animated-gif"), sourceAssets, }); if (result.preparedGifs.length === 0) return; diff --git a/packages/cli/src/commands/lambda/prebuiltHandler.ts b/packages/cli/src/commands/lambda/prebuiltHandler.ts index 81d0f72fa4..2a6df0fae6 100644 --- a/packages/cli/src/commands/lambda/prebuiltHandler.ts +++ b/packages/cli/src/commands/lambda/prebuiltHandler.ts @@ -11,14 +11,14 @@ import { renameSync, unlinkSync, } from "node:fs"; -import { homedir } from "node:os"; import { dirname, join } from "node:path"; import { downloadFile } from "../../utils/download.js"; import { isMissingPackageError } from "../../utils/missingPackage.js"; import { VERSION } from "../../version.js"; +import { hyperframesCacheDir } from "@hyperframes/core/cache-dir"; const DOCS_URL = "https://hyperframes.heygen.com/deploy/aws-lambda"; -const HANDLER_CACHE_DIR = join(homedir(), ".cache", "hyperframes", "lambda-handler"); +const HANDLER_CACHE_DIR = hyperframesCacheDir("lambda-handler"); type AdapterSdk = typeof import("@hyperframes/aws-lambda/sdk"); diff --git a/packages/cli/src/tts/manager.ts b/packages/cli/src/tts/manager.ts index 317f8d307b..6181aedf43 100644 --- a/packages/cli/src/tts/manager.ts +++ b/packages/cli/src/tts/manager.ts @@ -1,9 +1,9 @@ import { existsSync, mkdirSync } from "node:fs"; -import { homedir } from "node:os"; import { join } from "node:path"; import { downloadFile } from "../utils/download.js"; +import { hyperframesCacheDir } from "@hyperframes/core/cache-dir"; -const CACHE_DIR = join(homedir(), ".cache", "hyperframes", "tts"); +const CACHE_DIR = hyperframesCacheDir("tts"); const MODELS_DIR = join(CACHE_DIR, "models"); const VOICES_DIR = join(CACHE_DIR, "voices"); diff --git a/packages/cli/src/tts/synthesize.ts b/packages/cli/src/tts/synthesize.ts index 8394ad7ae0..c0f77f75e2 100644 --- a/packages/cli/src/tts/synthesize.ts +++ b/packages/cli/src/tts/synthesize.ts @@ -2,7 +2,6 @@ import { execFileSync } from "node:child_process"; import { existsSync, mkdirSync, readdirSync, unlinkSync } from "node:fs"; import { join, dirname, basename } from "node:path"; -import { homedir } from "node:os"; import { ensureModel, ensureVoices, @@ -12,6 +11,7 @@ import { } from "./manager.js"; import { findPython, hasPythonPackage } from "./python.js"; import { writeNewFileSync } from "../utils/writeNewFile.js"; +import { hyperframesCacheDir } from "@hyperframes/core/cache-dir"; // --------------------------------------------------------------------------- // Inline Python script for Kokoro synthesis @@ -115,7 +115,7 @@ const ESPEAK_LANG_OVERRIDES: Partial> = { // Cache the script to avoid rewriting it on every invocation. // The filename carries a version suffix so older installs automatically // upgrade when the script body changes (e.g., adding the `lang` kwarg). -const SCRIPT_DIR = join(homedir(), ".cache", "hyperframes", "tts"); +const SCRIPT_DIR = hyperframesCacheDir("tts"); const SCRIPT_PATH = join(SCRIPT_DIR, "synth-v4.py"); function ensureSynthScript(): string { diff --git a/packages/cli/src/utils/optionalPackages.ts b/packages/cli/src/utils/optionalPackages.ts index 81ae64fc76..d69e01b38b 100644 --- a/packages/cli/src/utils/optionalPackages.ts +++ b/packages/cli/src/utils/optionalPackages.ts @@ -12,9 +12,9 @@ import { writeFileSync, } from "node:fs"; import { createRequire } from "node:module"; -import { homedir } from "node:os"; import { basename, dirname, join, sep } from "node:path"; import { buildNpmCommand } from "./npxCommand.js"; +import { hyperframesCacheDir } from "@hyperframes/core/cache-dir"; /** Module type of each optional package; the keys are the only names the loader accepts. */ export interface OptionalPackageModules { @@ -37,7 +37,7 @@ export const PINNED_PACKAGES = { type PinnedPackage = keyof typeof PINNED_PACKAGES; -export const CACHE_DIR = join(homedir(), ".cache", "hyperframes", "optional"); +export const CACHE_DIR = hyperframesCacheDir("optional"); /** Installed on first use only when a host bundled the CLI without its sharp dependency. */ export const SHARP_VERSION = "0.35.3"; diff --git a/packages/cli/src/warmCheckProtocol.ts b/packages/cli/src/warmCheckProtocol.ts index 1c46924a59..b0fcef0ec4 100644 --- a/packages/cli/src/warmCheckProtocol.ts +++ b/packages/cli/src/warmCheckProtocol.ts @@ -4,6 +4,7 @@ import { homedir } from "node:os"; import { join } from "node:path"; import { Writable } from "node:stream"; import { fileURLToPath } from "node:url"; +import { hyperframesCacheDir } from "@hyperframes/core/cache-dir"; export const WARM_IDLE_MS = 5 * 60_000; export const HANDSHAKE_TIMEOUT_MS = 2_000; @@ -50,7 +51,7 @@ export function warmCheckDirectory(env = process.env): string | undefined { ? join(env.LOCALAPPDATA ?? join(homedir(), "AppData", "Local"), "hyperframes", "warm") : env.XDG_RUNTIME_DIR ? join(env.XDG_RUNTIME_DIR, "hyperframes-warm") - : join(homedir(), ".cache", "hyperframes", "warm"); + : hyperframesCacheDir("warm"); try { mkdirSync(dir, { recursive: true, mode: 0o700 }); } catch { diff --git a/packages/cli/src/whisper/manager.ts b/packages/cli/src/whisper/manager.ts index 97aa68cb57..3b30d8d007 100644 --- a/packages/cli/src/whisper/manager.ts +++ b/packages/cli/src/whisper/manager.ts @@ -1,14 +1,15 @@ // fallow-ignore-file code-duplication complexity import { execFileSync } from "node:child_process"; import { existsSync, mkdirSync, readdirSync, rmSync, statSync } from "node:fs"; -import { homedir, platform } from "node:os"; +import { platform } from "node:os"; import { join } from "node:path"; import { findFFmpeg } from "../browser/ffmpeg.js"; import { downloadFile } from "../utils/download.js"; import { stoppableExecFile } from "../utils/stoppableExecFile.js"; import { verifies, type ModelFile } from "./modelFile.js"; +import { hyperframesCacheDir } from "@hyperframes/core/cache-dir"; -const MODELS_DIR = join(homedir(), ".cache", "hyperframes", "whisper", "models"); +const MODELS_DIR = hyperframesCacheDir("whisper", "models"); const DEFAULT_MODEL = "small.en"; export type WhisperSource = "env" | "system" | "brew" | "build"; @@ -144,7 +145,7 @@ function findFromSystem(): WhisperResult | undefined { // --- Build from source ------------------------------------------------------ -const BUILD_DIR = join(homedir(), ".cache", "hyperframes", "whisper", "whisper.cpp"); +const BUILD_DIR = hyperframesCacheDir("whisper", "whisper.cpp"); const WHISPER_REPO = "https://github.com/ggml-org/whisper.cpp.git"; function findBuiltBinary(): WhisperResult | undefined { @@ -168,7 +169,7 @@ async function buildFromSource( if (!existsSync(BUILD_DIR)) { onProgress?.("Downloading whisper.cpp..."); - mkdirSync(join(homedir(), ".cache", "hyperframes", "whisper"), { + mkdirSync(hyperframesCacheDir("whisper"), { recursive: true, }); await stoppableExecFile("git", ["clone", "--depth", "1", WHISPER_REPO, BUILD_DIR], { diff --git a/packages/cli/src/whisper/sherpa.ts b/packages/cli/src/whisper/sherpa.ts index f18a6c0937..f4c6631dc6 100644 --- a/packages/cli/src/whisper/sherpa.ts +++ b/packages/cli/src/whisper/sherpa.ts @@ -1,7 +1,7 @@ import { execFile, spawn, type ExecFileException } from "node:child_process"; import { randomUUID } from "node:crypto"; import { mkdirSync, renameSync, rmSync, statSync } from "node:fs"; -import { homedir } from "node:os"; +import { hyperframesCacheDir } from "@hyperframes/core/cache-dir"; import { join } from "node:path"; import { createInterface } from "node:readline"; import { fileURLToPath } from "node:url"; @@ -45,13 +45,7 @@ export const SHERPA_RUNTIME_DIR = join( const MODEL_REPO = "csukuangfj/sherpa-onnx-nemo-parakeet-tdt-0.6b-v3-int8"; const MODEL_REVISION = "2bda32ec70b097a55adaa07d9a7173915b43cc78"; -export const PARAKEET_MODEL_DIR = join( - homedir(), - ".cache", - "hyperframes", - "parakeet", - "parakeet-tdt-0.6b-v3-int8", -); +export const PARAKEET_MODEL_DIR = hyperframesCacheDir("parakeet", "parakeet-tdt-0.6b-v3-int8"); export type { ModelFile }; diff --git a/packages/core/package.json b/packages/core/package.json index f4c51f8241..7366613d43 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -80,6 +80,12 @@ "import": "./src/atomicFile.ts", "types": "./src/atomicFile.ts" }, + "./cache-dir": { + "bun": "./src/cacheDir.ts", + "node": "./dist/cacheDir.js", + "import": "./src/cacheDir.ts", + "types": "./src/cacheDir.ts" + }, "./remove-tree": { "bun": "./src/removeTree.ts", "node": "./dist/removeTree.js", @@ -662,6 +668,10 @@ "import": "./dist/atomicFile.js", "types": "./dist/atomicFile.d.ts" }, + "./cache-dir": { + "import": "./dist/cacheDir.js", + "types": "./dist/cacheDir.d.ts" + }, "./remove-tree": { "import": "./dist/removeTree.js", "types": "./dist/removeTree.d.ts" diff --git a/packages/core/src/cacheDir.test.ts b/packages/core/src/cacheDir.test.ts new file mode 100644 index 0000000000..d65f54e304 --- /dev/null +++ b/packages/core/src/cacheDir.test.ts @@ -0,0 +1,60 @@ +import { readdirSync, readFileSync } from "node:fs"; +import { homedir } from "node:os"; +import { join, resolve } from "node:path"; +import { afterEach, describe, expect, it, vi } from "vitest"; +import { hyperframesCacheDir } from "./cacheDir.js"; + +afterEach(() => vi.unstubAllEnvs()); + +describe("hyperframesCacheDir", () => { + it("defaults to ~/.cache/hyperframes", () => { + vi.stubEnv("HYPERFRAMES_CACHE_DIR", ""); + expect(hyperframesCacheDir()).toBe(join(homedir(), ".cache", "hyperframes")); + expect(hyperframesCacheDir("chrome")).toBe(join(homedir(), ".cache", "hyperframes", "chrome")); + }); + + it("follows HYPERFRAMES_CACHE_DIR, read on each call, a relative one resolved", () => { + vi.stubEnv("HYPERFRAMES_CACHE_DIR", "/elsewhere/cache"); + expect(hyperframesCacheDir("whisper", "models")).toBe( + join("/elsewhere/cache", "whisper", "models"), + ); + vi.stubEnv("HYPERFRAMES_CACHE_DIR", "rel/cache"); + expect(hyperframesCacheDir("tts")).toBe(join(resolve("rel/cache"), "tts")); + }); +}); + +/** Source files under every package's src, tests left out. */ +function sources(dir: string): string[] { + return readdirSync(dir, { recursive: true, withFileTypes: true }) + .filter((entry) => entry.isFile() && /\.(m?[jt]sx?)$/.test(entry.name)) + .filter((entry) => !/\.test\.|__tests__/.test(join(entry.parentPath, entry.name))) + .map((entry) => join(entry.parentPath, entry.name)); +} + +it("every cache path in every package goes through hyperframesCacheDir", () => { + const packages = resolve(__dirname, "..", ".."); + const built: string[] = []; + for (const name of readdirSync(packages)) { + let files: string[]; + try { + files = sources(join(packages, name, "src")); + } catch { + continue; // a package without src + } + for (const file of files) { + if (file.endsWith(join("core", "src", "cacheDir.ts"))) continue; + // Prose about the default path is fine; code that builds it is not. + const code = readFileSync(file, "utf8") + .split("\n") + .filter((line) => !/^\s*(\/\/|\*|\/\*)/.test(line)) + .join("\n"); + if ( + /["'`]\.cache["'`]\s*,\s*["'`]hyperframes["'`]|["'`][^"'`\n]*\.cache\/hyperframes/.test( + code, + ) + ) + built.push(file.slice(packages.length + 1)); + } + } + expect(built).toEqual([]); +}); diff --git a/packages/core/src/cacheDir.ts b/packages/core/src/cacheDir.ts new file mode 100644 index 0000000000..81d4715023 --- /dev/null +++ b/packages/core/src/cacheDir.ts @@ -0,0 +1,9 @@ +import { homedir } from "node:os"; +import { join, resolve } from "node:path"; + +/** Where HyperFrames keeps what it downloads, builds and caches: `HYPERFRAMES_CACHE_DIR` when set, else + * `~/.cache/hyperframes`. Read on each call. */ +export function hyperframesCacheDir(...parts: string[]): string { + const named = process.env["HYPERFRAMES_CACHE_DIR"]; + return join(named ? resolve(named) : join(homedir(), ".cache", "hyperframes"), ...parts); +} diff --git a/packages/core/src/fonts/deterministicFonts.ts b/packages/core/src/fonts/deterministicFonts.ts index 2bb382872f..1eb00e0904 100644 --- a/packages/core/src/fonts/deterministicFonts.ts +++ b/packages/core/src/fonts/deterministicFonts.ts @@ -8,7 +8,7 @@ import { rmSync, writeFileSync, } from "node:fs"; -import { homedir, tmpdir } from "node:os"; +import { tmpdir } from "node:os"; import { join } from "node:path"; import { FONT_ALIAS_MAP, resolveAliasDisplayName } from "./aliases.js"; @@ -25,6 +25,7 @@ import { type FontDiagnostics, type FontDiagPath, } from "./fontDiagnostics.js"; +import { hyperframesCacheDir } from "../cacheDir.js"; export type { FontDiagnostics }; @@ -1123,7 +1124,7 @@ function resolveFontCacheRoot(): string { lambdaFontCacheRoot ??= mkdtempSync(join(tmpdir(), "hyperframes-fonts-")); return lambdaFontCacheRoot; } - return join(homedir(), ".cache", "hyperframes", "fonts"); + return hyperframesCacheDir("fonts"); } // Chrome UA triggers woff2 responses from Google Fonts CSS API diff --git a/packages/core/src/fonts/fontCompression.ts b/packages/core/src/fonts/fontCompression.ts index bbeee94455..8bf56309fd 100644 --- a/packages/core/src/fonts/fontCompression.ts +++ b/packages/core/src/fonts/fontCompression.ts @@ -10,8 +10,9 @@ import { rmSync, writeFileSync, } from "node:fs"; -import { homedir, tmpdir } from "node:os"; +import { tmpdir } from "node:os"; import { dirname, join } from "node:path"; +import { hyperframesCacheDir } from "../cacheDir.js"; const { compress } = wawoff2 as { compress: (input: Buffer | Uint8Array) => Promise; @@ -41,7 +42,7 @@ function defaultCacheDir(): string { process.env.HYPERFRAMES_FONT_CACHE_DIR ?? (process.env.AWS_LAMBDA_FUNCTION_NAME ? join(tmpdir(), "hyperframes", "fonts") - : join(homedir(), ".cache", "hyperframes", "fonts")); + : hyperframesCacheDir("fonts")); return join(root, "local-compression-v1"); } diff --git a/packages/engine/src/services/browserManager.ts b/packages/engine/src/services/browserManager.ts index d26bfc048c..9d91a29998 100644 --- a/packages/engine/src/services/browserManager.ts +++ b/packages/engine/src/services/browserManager.ts @@ -46,6 +46,7 @@ export type { BrowserPoolState, CaptureMode, } from "./browserLeasePool.js"; +import { hyperframesCacheDir } from "@hyperframes/core/cache-dir"; let _puppeteer: PuppeteerNode | undefined; @@ -271,7 +272,7 @@ export function resolveHeadlessShellPath( } return fromEnv.path; } - const ours = join(homedir(), ".cache", "hyperframes", "chrome", "chrome-headless-shell"); + const ours = hyperframesCacheDir("chrome", "chrome-headless-shell"); const shared = join(homedir(), ".cache", "puppeteer", "chrome-headless-shell"); return ( findManagedHeadlessShell(ours) ?? diff --git a/packages/inspector/src/service.ts b/packages/inspector/src/service.ts index ab09b1a39f..a5acba70de 100644 --- a/packages/inspector/src/service.ts +++ b/packages/inspector/src/service.ts @@ -22,7 +22,6 @@ import { readdirSync, } from "node:fs"; import { resolve, join, extname, sep } from "node:path"; -import { homedir } from "node:os"; import { getHyperframeRuntimeScript } from "../../core/src/generated/runtime-inline"; import puppeteer, { type Browser, type Page } from "puppeteer-core"; import { @@ -32,6 +31,7 @@ import { import { closeServer } from "./pageServer"; import { Sources, fingerprint } from "./sources"; import type { InspectRequest, Snippet } from "./types"; +import { hyperframesCacheDir } from "@hyperframes/core/cache-dir"; const pageRunner = (page: Page): PageRunner => ({ run: (fn: (arg: A) => R, arg: A) => @@ -59,7 +59,7 @@ function chromePath() { "Set HF_INSPECT_CHROME to an installed Chrome executable; inspection does not download a browser.", ); } - const root = join(homedir(), ".cache/hyperframes/chrome/chrome-headless-shell"); + const root = hyperframesCacheDir("chrome", "chrome-headless-shell"); if (existsSync(root)) for (const version of readdirSync(root).sort().reverse()) { const dir = join(root, version); diff --git a/packages/studio-server/src/history/projectHistory.ts b/packages/studio-server/src/history/projectHistory.ts index d1e22d2cae..87d8ea3e1f 100644 --- a/packages/studio-server/src/history/projectHistory.ts +++ b/packages/studio-server/src/history/projectHistory.ts @@ -12,7 +12,6 @@ import { realpathSync, rmSync, } from "node:fs"; -import { homedir } from "node:os"; import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path"; import { replaceFileAtomically } from "@hyperframes/core/atomic-file"; import { @@ -64,9 +63,10 @@ import { type LogRecord, type Manifest, } from "./historyLog.js"; +import { hyperframesCacheDir } from "@hyperframes/core/cache-dir"; /** Where hosts keep project histories unless told otherwise: outside every project, so no tidy-up takes one away. */ -export const DEFAULT_HISTORY_ROOT = join(homedir(), ".cache", "hyperframes", "history"); +export const DEFAULT_HISTORY_ROOT = hyperframesCacheDir("history"); export interface ProjectHistoryOptions { projectDir: string;