From 0c262375ddc644abb7ee8676fa2e8695912c14a0 Mon Sep 17 00:00:00 2001 From: James Date: Sat, 13 Jun 2026 03:18:14 +0000 Subject: [PATCH] fix(core): restore backup-only file-tree hiding reverted by #1389 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit main has been red since #1389 (3bcab3dc). #1389 ("reject unsafe keyframe values") is unrelated to studio composition discovery, but it branched off pre-#1366 main and its squash reverted #1366's walkDir refinement: it put `.hyperframes` back into IGNORE_DIRS and dropped `shouldIgnoreDir`, so the whole `.hyperframes/` tree is hidden again instead of just `.hyperframes/backup`. That re-broke #1366's intent (vendored dot-dir HTML must stay browsable in the file tree, gated only out of composition discovery), so the file-tree test from #1400 fails. Restore #1366's behavior while keeping #1397's `isSafePath` promotion: - IGNORE_DIRS back to `.thumbnails`/`node_modules`/`.git` (no `.hyperframes`). - Reinstate `shouldIgnoreDir(rel) === ".hyperframes/backup"` and the `|| shouldIgnoreDir(rel)` guard in walkDir. - Realign the walkDir test to assert `.hyperframes/examples` stays visible and only `.hyperframes/backup` is hidden (it had been flipped to hide all `.hyperframes` by the same revert). Full non-producer suite green. NOTE: studio-api/helpers/safePath.ts is a recurring conflict hotspot — #1366's fix has now been reverted twice by stale-base PRs (#1389, and earlier #1399). Worth landing in-flight branches on current main before squashing. Co-Authored-By: Claude Opus 4.8 (1M context) --- packages/core/src/studio-api/helpers/safePath.test.ts | 6 ++++-- packages/core/src/studio-api/helpers/safePath.ts | 8 ++++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/packages/core/src/studio-api/helpers/safePath.test.ts b/packages/core/src/studio-api/helpers/safePath.test.ts index fbfce353f..4a431792d 100644 --- a/packages/core/src/studio-api/helpers/safePath.test.ts +++ b/packages/core/src/studio-api/helpers/safePath.test.ts @@ -19,7 +19,7 @@ function createProjectDir(): string { } describe("walkDir", () => { - it("hides internal HyperFrames files from project listings", () => { + it("hides only internal HyperFrames backups, not vendored dot-directory files", () => { const projectDir = createProjectDir(); mkdirSync(join(projectDir, ".hyperframes", "backup"), { recursive: true }); mkdirSync(join(projectDir, ".hyperframes", "examples"), { recursive: true }); @@ -31,9 +31,11 @@ describe("walkDir", () => { writeFileSync(join(projectDir, "compositions", "scene.html"), "scene"); const files = walkDir(projectDir); + // Vendored dot-dir files stay browsable in the file tree (#1366) — only + // Studio's own backup snapshots are hidden (shouldIgnoreDir). expect(files).toContain(".cache/examples/preset.html"); + expect(files).toContain(".hyperframes/examples/preset.html"); expect(files).toContain("compositions/scene.html"); expect(files).not.toContain(".hyperframes/backup/snapshot.html"); - expect(files).not.toContain(".hyperframes/examples/preset.html"); }); }); diff --git a/packages/core/src/studio-api/helpers/safePath.ts b/packages/core/src/studio-api/helpers/safePath.ts index 4da2a529d..2f9a18e56 100644 --- a/packages/core/src/studio-api/helpers/safePath.ts +++ b/packages/core/src/studio-api/helpers/safePath.ts @@ -6,7 +6,11 @@ import { readdirSync } from "node:fs"; // Re-exported here for back-compat with existing `../helpers/safePath.js` imports. export { isSafePath } from "../../safePath.js"; -const IGNORE_DIRS = new Set([".thumbnails", ".hyperframes", "node_modules", ".git"]); +const IGNORE_DIRS = new Set([".thumbnails", "node_modules", ".git"]); + +function shouldIgnoreDir(rel: string): boolean { + return rel === ".hyperframes/backup"; +} /** * True when any directory segment of a relative path is a dot-directory or @@ -25,7 +29,7 @@ export function walkDir(dir: string, prefix = ""): string[] { const files: string[] = []; for (const entry of readdirSync(dir, { withFileTypes: true })) { const rel = prefix ? `${prefix}/${entry.name}` : entry.name; - if (IGNORE_DIRS.has(entry.name)) continue; + if (IGNORE_DIRS.has(entry.name) || shouldIgnoreDir(rel)) continue; if (entry.isDirectory()) { files.push(...walkDir(join(dir, entry.name), rel)); } else {