mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-01 19:42:03 +00:00
fix(cli): keep diagnostics on stderr for --json commands (#2522)
This commit is contained in:
@@ -474,7 +474,9 @@ export async function captureWebsite(
|
||||
const summary = fontsManifest.families
|
||||
.map((f) => `${f.family}${f.variable ? " (variable)" : ""} × ${f.fileCount}`)
|
||||
.join(", ");
|
||||
console.log(`Font metadata extracted: ${summary}`);
|
||||
// stderr: `capture --json` writes its envelope to stdout; this progress
|
||||
// note must not corrupt it (matches the sibling console.warn below).
|
||||
console.warn(`Font metadata extracted: ${summary}`);
|
||||
if (fontsManifest.unidentified.length > 0) {
|
||||
console.warn(
|
||||
` ${fontsManifest.unidentified.length} font file(s) could not be identified — DESIGN.md should flag these explicitly.`,
|
||||
|
||||
@@ -249,13 +249,15 @@ export default defineCommand({
|
||||
ensureDOMParser();
|
||||
const compositions = parseCompositions(html, dirname(project.indexPath));
|
||||
|
||||
if (compositions.length === 0) {
|
||||
console.log(`${c.success("◇")} ${c.accent(project.name)} — no compositions found`);
|
||||
// --json must always emit a machine-readable envelope, including the empty
|
||||
// case — check it before the human "no compositions" message on stdout.
|
||||
if (args.json) {
|
||||
console.log(JSON.stringify(withMeta({ compositions }), null, 2));
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.json) {
|
||||
console.log(JSON.stringify(withMeta({ compositions }), null, 2));
|
||||
if (compositions.length === 0) {
|
||||
console.log(`${c.success("◇")} ${c.accent(project.name)} — no compositions found`);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -56,7 +56,12 @@ function spawnNpx(args: string[], opts: { cwd?: string } = {}): Promise<void> {
|
||||
const npx = buildNpxCommand(args);
|
||||
return new Promise((resolve, reject) => {
|
||||
const child = spawn(npx.command, npx.args, {
|
||||
stdio: "inherit",
|
||||
// Route the child's stdout to the parent's stderr (fd 2), keeping stdin
|
||||
// inherited. `skills update --json` runs this installer before printing its
|
||||
// JSON envelope on stdout; child progress chatter on stdout would corrupt it.
|
||||
// Diagnostics belong on stderr regardless of mode, so this is safe for the
|
||||
// interactive path too (the user still sees the output).
|
||||
stdio: ["inherit", 2, 2],
|
||||
// We install with --full-depth (a full `git clone` of the repo, the only
|
||||
// path that bypasses the laggy skills.sh blob — see GLOBAL_INSTALL_ARGS_TAIL),
|
||||
// which is heavier than the blob fetch, so allow more headroom.
|
||||
@@ -171,7 +176,9 @@ function mirrorToInstalledAgents(): void {
|
||||
const { mirrored } = mirrorGlobalSkills({ skills: names });
|
||||
const n = mirrored.length;
|
||||
if (n > 0) {
|
||||
console.log(
|
||||
// stderr: reachable from `skills update --json` (via installSkills) before
|
||||
// the JSON envelope is written to stdout.
|
||||
console.error(
|
||||
c.dim(`Linked skills into ${n} other agent ${n === 1 ? "directory" : "directories"}.`),
|
||||
);
|
||||
}
|
||||
@@ -244,15 +251,17 @@ async function installSkills(
|
||||
|
||||
if (!skillsToolingReady(opts.strict ?? false)) return;
|
||||
|
||||
// stderr: installSkills runs on the `skills update --json` path before its JSON
|
||||
// envelope is written to stdout — progress here must not corrupt that output.
|
||||
for (const source of SOURCES) {
|
||||
console.log();
|
||||
console.log(c.bold(`Installing ${source.name} skills...`));
|
||||
console.log();
|
||||
console.error();
|
||||
console.error(c.bold(`Installing ${source.name} skills...`));
|
||||
console.error();
|
||||
try {
|
||||
await runSkillsAdd(source.url, safeSelection, opts);
|
||||
} catch (err) {
|
||||
if (opts.strict) throw err instanceof Error ? err : new Error(String(err));
|
||||
console.log(c.dim(`${source.name} skills skipped`));
|
||||
console.error(c.dim(`${source.name} skills skipped`));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -219,15 +219,18 @@ export function showTelemetryNotice(): boolean {
|
||||
config.telemetryNoticeShown = true;
|
||||
writeConfig(config);
|
||||
|
||||
console.log();
|
||||
console.log(` ${c.dim("Hyperframes collects anonymous usage data to improve the tool.")}`);
|
||||
console.log(` ${c.dim("File paths and composition content are never collected.")}`);
|
||||
console.log(
|
||||
// stderr, not stdout: this first-run disclosure is not gated by --json (the
|
||||
// guard in cli.ts filters by command only), so a stdout banner would corrupt
|
||||
// the JSON envelope of the very first `check --json` / `info --json` etc.
|
||||
console.error();
|
||||
console.error(` ${c.dim("Hyperframes collects anonymous usage data to improve the tool.")}`);
|
||||
console.error(` ${c.dim("File paths and composition content are never collected.")}`);
|
||||
console.error(
|
||||
` ${c.dim("If you sign in to HeyGen, your account (email, or username) is linked to your usage.")}`,
|
||||
);
|
||||
console.log();
|
||||
console.log(` ${c.dim("Disable anytime:")} ${c.accent("hyperframes telemetry disable")}`);
|
||||
console.log();
|
||||
console.error();
|
||||
console.error(` ${c.dim("Disable anytime:")} ${c.accent("hyperframes telemetry disable")}`);
|
||||
console.error();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1908,7 +1908,9 @@ export async function compileForRender(
|
||||
);
|
||||
}
|
||||
if (metadata.isVFR) {
|
||||
console.info(
|
||||
// defaultLogger (stderr), not console.info (stdout) — matches the sibling
|
||||
// warning above; a stdout line here corrupts `check --json` / `validate --json`.
|
||||
defaultLogger.warn(
|
||||
`[Compiler] Video "${video.id}" is variable frame rate (VFR); ` +
|
||||
`the engine will normalize it to CFR before frame extraction. ` +
|
||||
`If rendering feels slow on this video, pre-encode once with: ${reencode}`,
|
||||
|
||||
Reference in New Issue
Block a user