mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-10-30 09:16:55 +00:00
fix(cli): an unreadable project folder is reported as unreadable, not as holding no composition
resolveProjectOrThrow checked index.html with existsSync, which is false for EACCES/EPERM as well as a missing file. A folder the process may not open (macOS Files and Folders, a cloud-synced drive, permissions) was reported as 'No composition found, run init', and agents retried it in a loop. Only ENOENT/ENOTDIR now mean no composition; any other access error says the folder cannot be read and why.
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
||||
import { chmodSync, mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join, basename } from "node:path";
|
||||
import { InvalidProjectError, resolveLintTarget, resolveProjectOrThrow } from "./project.js";
|
||||
@@ -42,6 +42,23 @@ describe("resolveProjectOrThrow", () => {
|
||||
}
|
||||
});
|
||||
|
||||
it.skipIf(process.platform === "win32" || process.getuid?.() === 0)(
|
||||
"says a folder it may not open is unreadable, not that it holds no composition",
|
||||
() => {
|
||||
const dir = mkdtempSync(join(tmpdir(), "hf-unreadable-project-"));
|
||||
try {
|
||||
writeFileSync(join(dir, "index.html"), "<html></html>");
|
||||
chmodSync(dir, 0o444);
|
||||
expect(() => resolveProjectOrThrow(dir)).toThrowError(
|
||||
expect.objectContaining({ title: "Cannot read " + dir }),
|
||||
);
|
||||
} finally {
|
||||
chmodSync(dir, 0o755);
|
||||
rmSync(dir, { recursive: true, force: true });
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
it("rejects a directory without index.html", () => {
|
||||
const dir = mkdtempSync(join(tmpdir(), "hf-empty-project-"));
|
||||
try {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { failCommand } from "./commandResult.js";
|
||||
import { existsSync, statSync } from "node:fs";
|
||||
import { accessSync, existsSync, statSync } from "node:fs";
|
||||
import { basename, dirname, join, relative, resolve, sep } from "node:path";
|
||||
import { errorBox } from "../ui/format.js";
|
||||
import { trackCommandFailure } from "../telemetry/events.js";
|
||||
@@ -55,12 +55,24 @@ export function resolveProjectOrThrow(
|
||||
if (!existsSync(dir)) {
|
||||
throw new InvalidProjectError("Not a directory: " + dir);
|
||||
}
|
||||
if (options.requireIndex !== false && !existsSync(indexPath)) {
|
||||
throw new InvalidProjectError(
|
||||
"No composition found in " + dir,
|
||||
"No index.html file found.",
|
||||
"Run npx hyperframes init to create a new composition.",
|
||||
);
|
||||
if (options.requireIndex !== false) {
|
||||
try {
|
||||
accessSync(indexPath);
|
||||
} catch (err) {
|
||||
const code = (err as NodeJS.ErrnoException).code;
|
||||
if (code !== "ENOENT" && code !== "ENOTDIR") {
|
||||
throw new InvalidProjectError(
|
||||
"Cannot read " + dir,
|
||||
`index.html could not be checked (${code}): the folder exists but this process may not open it.`,
|
||||
"Check the folder's permissions, or on macOS allow your terminal or agent access to that folder (Files and Folders).",
|
||||
);
|
||||
}
|
||||
throw new InvalidProjectError(
|
||||
"No composition found in " + dir,
|
||||
"No index.html file found.",
|
||||
"Run npx hyperframes init to create a new composition.",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return { dir, name, indexPath };
|
||||
|
||||
Reference in New Issue
Block a user