fix(cli): validate project directory before starting preview (#1394)

Preview previously started Studio even when the path was invalid (e.g.
`hyperframes preview #`), yielding an empty project view. Align preview
with lint/render by resolving the project up front, and add a clearer
error when `#` is passed as a directory argument.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Manu Pareek
2026-06-12 20:28:48 -04:00
committed by GitHub
co-authored by Cursor
parent 7fa3696101
commit 2ec006297f
3 changed files with 95 additions and 19 deletions
+38 -5
View File
@@ -8,23 +8,56 @@ export interface ProjectDir {
indexPath: string;
}
export function resolveProject(dirArg: string | undefined): ProjectDir {
export class InvalidProjectError extends Error {
readonly title: string;
readonly hint?: string;
readonly suggestion?: string;
constructor(title: string, hint?: string, suggestion?: string) {
super(title);
this.name = "InvalidProjectError";
this.title = title;
this.hint = hint;
this.suggestion = suggestion;
}
}
export function resolveProjectOrThrow(dirArg: string | undefined): ProjectDir {
const trimmed = dirArg?.trim();
if (trimmed === "#") {
throw new InvalidProjectError(
"Invalid project directory: #",
"# is a URL fragment, not a project path.",
"Run hyperframes preview . from your project directory.",
);
}
const dir = resolve(dirArg ?? ".");
const name = basename(dir);
const indexPath = resolve(dir, "index.html");
if (!existsSync(dir) || !statSync(dir).isDirectory()) {
errorBox("Not a directory: " + dir);
process.exit(1);
throw new InvalidProjectError("Not a directory: " + dir);
}
if (!existsSync(indexPath)) {
errorBox(
throw new InvalidProjectError(
"No composition found in " + dir,
"No index.html file found.",
"Run npx hyperframes init to create a new composition.",
);
process.exit(1);
}
return { dir, name, indexPath };
}
export function resolveProject(dirArg: string | undefined): ProjectDir {
try {
return resolveProjectOrThrow(dirArg);
} catch (err) {
if (err instanceof InvalidProjectError) {
errorBox(err.title, err.hint, err.suggestion);
process.exit(1);
}
throw err;
}
}