From e6cf46810dd4e71fc457828d872236af79ec5a94 Mon Sep 17 00:00:00 2001 From: Vance Ingalls Date: Wed, 13 May 2026 09:24:49 -0700 Subject: [PATCH] fix(studio): build:dev mode, lint exclude .hyperframes, iframe ref guard - CLAUDE.md: add build:dev guidance (source maps + React dev warnings for local dev, production build is GHA-only) - Studio lint: exclude .hyperframes/ and node_modules/ from walkDir scan (pick-design.html is a UI tool, not a composition) - App.tsx: guard handlePreviewIframeRef with identity check to prevent re-entrant setPreviewIframe when the same iframe ref is passed Co-Authored-By: Claude Opus 4.6 (1M context) --- CLAUDE.md | 14 ++++++++++++++ packages/core/src/studio-api/routes/lint.ts | 4 +++- packages/studio/src/App.tsx | 1 + 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/CLAUDE.md b/CLAUDE.md index 4c8b6990a..e56edee30 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -22,6 +22,20 @@ bun run test # Run tests **This repo uses bun**, not pnpm. Do NOT run `pnpm install` — it creates a `pnpm-lock.yaml` that should not exist. Workspace linking relies on bun's resolution from `"workspaces"` in root `package.json`. +### Studio Build + +Always use the dev build locally — source maps, no minification, React dev-mode warnings: + +```bash +bun run --cwd packages/studio build:dev +``` + +The production build (`build` without `:dev`) is only run by GitHub Actions for publish. After building, copy to CLI: + +```bash +rm -rf packages/cli/dist/studio && cp -r packages/studio/dist packages/cli/dist/studio +``` + ### Linting & Formatting This project uses **oxlint** and **oxfmt** (not biome, not eslint, not prettier). diff --git a/packages/core/src/studio-api/routes/lint.ts b/packages/core/src/studio-api/routes/lint.ts index e399e52d3..810618bfa 100644 --- a/packages/core/src/studio-api/routes/lint.ts +++ b/packages/core/src/studio-api/routes/lint.ts @@ -9,7 +9,9 @@ export function registerLintRoutes(api: Hono, adapter: StudioApiAdapter): void { const project = await adapter.resolveProject(c.req.param("id")); if (!project) return c.json({ error: "not found" }, 404); try { - const htmlFiles = walkDir(project.dir).filter((f) => f.endsWith(".html")); + const htmlFiles = walkDir(project.dir).filter( + (f) => f.endsWith(".html") && !f.startsWith(".hyperframes/") && !f.startsWith("node_modules/"), + ); const allFindings: Array<{ severity: string; message: string; diff --git a/packages/studio/src/App.tsx b/packages/studio/src/App.tsx index 4affd71c1..f1a1fbe16 100644 --- a/packages/studio/src/App.tsx +++ b/packages/studio/src/App.tsx @@ -256,6 +256,7 @@ export function StudioApp() { const { syncPreviewTimelineHotkey, syncPreviewHistoryHotkey } = appHotkeys; const handlePreviewIframeRef = useCallback( (iframe: HTMLIFrameElement | null) => { + if (previewIframeRef.current === iframe) return; previewIframeRef.current = iframe; setPreviewIframe(iframe); syncPreviewTimelineHotkey(iframe);