hyperframes 0.7.77 → 0.7.79

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -50,7 +50,7 @@ var VERSION;
50
50
  var init_version = __esm({
51
51
  "src/version.ts"() {
52
52
  "use strict";
53
- VERSION = true ? "0.7.77" : "0.0.0-dev";
53
+ VERSION = true ? "0.7.79" : "0.0.0-dev";
54
54
  }
55
55
  });
56
56
 
@@ -62373,6 +62373,30 @@ var init_feedbackRating = __esm({
62373
62373
  }
62374
62374
  });
62375
62375
 
62376
+ // src/utils/errorMessage.ts
62377
+ function normalizeErrorMessage(error) {
62378
+ if (error instanceof Error) return error.message;
62379
+ if (typeof error === "string") return error;
62380
+ if (typeof error === "object" && error !== null) {
62381
+ const msg = error.message;
62382
+ if (typeof msg === "string") return msg;
62383
+ try {
62384
+ return JSON.stringify(error);
62385
+ } catch {
62386
+ try {
62387
+ return `{${Object.keys(error).join(", ")}}`;
62388
+ } catch {
62389
+ }
62390
+ }
62391
+ }
62392
+ return String(error ?? "unknown error");
62393
+ }
62394
+ var init_errorMessage = __esm({
62395
+ "src/utils/errorMessage.ts"() {
62396
+ "use strict";
62397
+ }
62398
+ });
62399
+
62376
62400
  // src/telemetry/config.ts
62377
62401
  import { existsSync as existsSync2, mkdirSync, readFileSync, renameSync, writeFileSync } from "fs";
62378
62402
  import { join as join3 } from "path";
@@ -62425,7 +62449,11 @@ function readConfig() {
62425
62449
  cachedConfig = config;
62426
62450
  return { ...config };
62427
62451
  } catch {
62428
- const config = { ...DEFAULT_CONFIG, anonymousId: randomUUID() };
62452
+ const config = {
62453
+ ...DEFAULT_CONFIG,
62454
+ telemetryEnabled: false,
62455
+ anonymousId: randomUUID()
62456
+ };
62429
62457
  writeConfig(config);
62430
62458
  return config;
62431
62459
  }
@@ -62435,15 +62463,18 @@ function readConfigFresh() {
62435
62463
  return readConfig();
62436
62464
  }
62437
62465
  function writeConfig(config) {
62466
+ return writeConfigWithResult(config).ok;
62467
+ }
62468
+ function writeConfigWithResult(config) {
62438
62469
  try {
62439
62470
  mkdirSync(CONFIG_DIR, { recursive: true, mode: 448 });
62440
62471
  const tmpFile = `${CONFIG_FILE}.${process.pid}.tmp`;
62441
62472
  writeFileSync(tmpFile, JSON.stringify(config, null, 2) + "\n", { mode: 384 });
62442
62473
  renameSync(tmpFile, CONFIG_FILE);
62443
62474
  cachedConfig = { ...config };
62444
- return true;
62445
- } catch {
62446
- return false;
62475
+ return { ok: true };
62476
+ } catch (error) {
62477
+ return { ok: false, error: normalizeErrorMessage(error) };
62447
62478
  }
62448
62479
  }
62449
62480
  function incrementCommandCount() {
@@ -62456,6 +62487,7 @@ var CONFIG_DIR, CONFIG_FILE, MAX_RECENT_RENDERS, DEFAULT_CONFIG, cachedConfig, C
62456
62487
  var init_config = __esm({
62457
62488
  "src/telemetry/config.ts"() {
62458
62489
  "use strict";
62490
+ init_errorMessage();
62459
62491
  CONFIG_DIR = join3(homedir(), ".hyperframes");
62460
62492
  CONFIG_FILE = join3(CONFIG_DIR, "config.json");
62461
62493
  MAX_RECENT_RENDERS = 5;
@@ -62594,21 +62626,6 @@ var init_diagnostics2 = __esm({
62594
62626
  }
62595
62627
  });
62596
62628
 
62597
- // src/utils/env.ts
62598
- function isDevMode() {
62599
- try {
62600
- const url = new URL(import.meta.url);
62601
- return url.pathname.endsWith(".ts");
62602
- } catch {
62603
- return false;
62604
- }
62605
- }
62606
- var init_env = __esm({
62607
- "src/utils/env.ts"() {
62608
- "use strict";
62609
- }
62610
- });
62611
-
62612
62629
  // ../engine/src/services/systemMemory.ts
62613
62630
  import { readFileSync as readFileSync2 } from "fs";
62614
62631
  import { totalmem } from "os";
@@ -62886,6 +62903,15 @@ function memoryAdaptiveCacheBytesMb() {
62886
62903
  if (total <= LOW_MEMORY_TOTAL_MB_THRESHOLD) return 256;
62887
62904
  return DEFAULT_CONFIG2.frameDataUriCacheBytesLimitMb;
62888
62905
  }
62906
+ function isDrawElementPlatform(platform10) {
62907
+ return platform10 === "darwin" || platform10 === "win32";
62908
+ }
62909
+ function resolveDefaultDrawElement(args) {
62910
+ if (!args.useDrawElement) return false;
62911
+ if (args.explicitOptIn) return true;
62912
+ if (!isDrawElementPlatform(args.platform) || args.browserGpuMode === "software") return false;
62913
+ return args.workerEncode;
62914
+ }
62889
62915
  function resolveConfig(overrides) {
62890
62916
  const env = (key2) => process.env[key2];
62891
62917
  const envNum = (key2, fallback) => {
@@ -63014,12 +63040,13 @@ function resolveConfig(overrides) {
63014
63040
  ...overrides
63015
63041
  };
63016
63042
  const explicitDrawElementOptIn = env("PRODUCER_EXPERIMENTAL_FAST_CAPTURE") === "true" || overrides?.useDrawElement === true;
63017
- if (merged.useDrawElement && !explicitDrawElementOptIn && !(process.platform === "darwin" && merged.browserGpuMode !== "software")) {
63018
- merged.useDrawElement = false;
63019
- }
63020
- if (merged.useDrawElement && !explicitDrawElementOptIn && !merged.enableDrawElementWorkerEncode) {
63021
- merged.useDrawElement = false;
63022
- }
63043
+ merged.useDrawElement = resolveDefaultDrawElement({
63044
+ useDrawElement: merged.useDrawElement,
63045
+ explicitOptIn: explicitDrawElementOptIn,
63046
+ platform: process.platform,
63047
+ browserGpuMode: merged.browserGpuMode,
63048
+ workerEncode: merged.enableDrawElementWorkerEncode
63049
+ });
63023
63050
  const explicitForceScreenshotOptOut = env("PRODUCER_FORCE_SCREENSHOT") === "false" || overrides?.forceScreenshot === false;
63024
63051
  if (explicitForceScreenshotOptOut) {
63025
63052
  merged.forceScreenshotExplicitlyOptedOut = true;
@@ -64510,15 +64537,22 @@ function instrumentAcceleratedCanvases() {
64510
64537
  return ctx;
64511
64538
  };
64512
64539
  }
64513
- async function detectSwiftShader(page) {
64540
+ function classifyGpuRenderer(renderer) {
64541
+ if (!renderer) return void 0;
64542
+ const r2 = renderer.toLowerCase();
64543
+ const backend = r2.includes("swiftshader") ? "swiftshader" : r2.includes("metal") ? "metal" : r2.includes("direct3d11") || r2.includes("d3d11") ? "d3d11" : r2.includes("direct3d9") || r2.includes("d3d9") ? "d3d9" : r2.includes("vulkan") ? "vulkan" : r2.includes("opengl") || r2.includes("angle") ? "opengl" : "other";
64544
+ const vendor = r2.includes("apple") ? "apple" : r2.includes("nvidia") ? "nvidia" : r2.includes("amd") || r2.includes("radeon") ? "amd" : r2.includes("intel") ? "intel" : r2.includes("microsoft") ? "microsoft" : "other";
64545
+ return `${backend}/${vendor}`;
64546
+ }
64547
+ async function detectGpuBackend(page) {
64514
64548
  return page.evaluate(() => {
64515
64549
  const canvas = document.createElement("canvas");
64516
64550
  const gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
64517
- if (!gl) return false;
64551
+ if (!gl) return { isSwiftShader: false, renderer: null };
64518
64552
  const ext = gl.getExtension("WEBGL_debug_renderer_info");
64519
- if (!ext) return false;
64553
+ if (!ext) return { isSwiftShader: false, renderer: null };
64520
64554
  const renderer = gl.getParameter(ext.UNMASKED_RENDERER_WEBGL);
64521
- return renderer.toLowerCase().includes("swiftshader");
64555
+ return { isSwiftShader: renderer.toLowerCase().includes("swiftshader"), renderer };
64522
64556
  });
64523
64557
  }
64524
64558
  async function injectDrawElementCanvas(page, width, height) {
@@ -66248,7 +66282,9 @@ async function initDrawElementOrTransparentBackground(session, page, logInitPhas
66248
66282
  );
66249
66283
  }
66250
66284
  if (useDrawElement) {
66251
- session.isSwiftShader = await detectSwiftShader(page);
66285
+ const gpuBackend = await detectGpuBackend(page);
66286
+ session.isSwiftShader = gpuBackend.isSwiftShader;
66287
+ session.gpuRenderer = classifyGpuRenderer(gpuBackend.renderer);
66252
66288
  const transparent = session.options.format === "png";
66253
66289
  async function routeToFallback() {
66254
66290
  session.captureMode = session.launchCaptureMode;
@@ -67960,6 +67996,7 @@ function getCapturePerfSummary(session) {
67960
67996
  beginFrameNoDamage: session.beginFrameNoDamageCount,
67961
67997
  beginFrameHasDamage: session.beginFrameHasDamageCount,
67962
67998
  captureMode: session.captureMode,
67999
+ gpuRenderer: session.gpuRenderer,
67963
68000
  deGateReason: session.deGateReason,
67964
68001
  deFallbackTrigger: session.deFallbackTrigger,
67965
68002
  deWorkerEncode: session.workerEncodeEnabled ?? false,
@@ -88550,8 +88587,10 @@ __export(system_exports, {
88550
88587
  bytesToMb: () => bytesToMb,
88551
88588
  getAvailableMemoryMb: () => getAvailableMemoryMb,
88552
88589
  getFreeDiskMb: () => getFreeDiskMb,
88590
+ getPowerState: () => getPowerState,
88553
88591
  getShmSizeMb: () => getShmSizeMb,
88554
- getSystemMeta: () => getSystemMeta
88592
+ getSystemMeta: () => getSystemMeta,
88593
+ parsePmsetPowerSource: () => parsePmsetPowerSource
88555
88594
  });
88556
88595
  import { cpus as cpus2, freemem as freemem2, platform as platform3, release as release3 } from "os";
88557
88596
  import { existsSync as existsSync20, readFileSync as readFileSync10, statfsSync } from "fs";
@@ -88626,6 +88665,31 @@ function getFreeDiskMb(path2 = ".") {
88626
88665
  return null;
88627
88666
  }
88628
88667
  }
88668
+ function parsePmsetPowerSource(raw) {
88669
+ const m2 = raw.match(/Now drawing from '([^']+)'/);
88670
+ if (!m2) return null;
88671
+ return m2[1] === "Battery Power";
88672
+ }
88673
+ function getPowerState() {
88674
+ if (platform3() !== "darwin") {
88675
+ return { on_battery: null, low_power_mode: null };
88676
+ }
88677
+ let on_battery = null;
88678
+ let low_power_mode = null;
88679
+ try {
88680
+ on_battery = parsePmsetPowerSource(
88681
+ execSync2("pmset -g batt", { encoding: "utf-8", timeout: 2e3 })
88682
+ );
88683
+ } catch {
88684
+ }
88685
+ try {
88686
+ const raw = execSync2("pmset -g", { encoding: "utf-8", timeout: 2e3 });
88687
+ const m2 = raw.match(/lowpowermode\s+(\d)/);
88688
+ if (m2) low_power_mode = m2[1] === "1";
88689
+ } catch {
88690
+ }
88691
+ return { on_battery, low_power_mode };
88692
+ }
88629
88693
  function getAvailableMemoryMb() {
88630
88694
  const fallback = bytesToMb(freemem2());
88631
88695
  if (platform3() === "darwin") {
@@ -88748,18 +88812,59 @@ var init_transport = __esm({
88748
88812
  }
88749
88813
  });
88750
88814
 
88751
- // src/telemetry/client.ts
88752
- function shouldTrack() {
88753
- if (telemetryEnabled !== null) return telemetryEnabled;
88754
- if (process.env["HYPERFRAMES_NO_TELEMETRY"] === "1" || process.env["DO_NOT_TRACK"] === "1") {
88755
- telemetryEnabled = false;
88815
+ // src/utils/env.ts
88816
+ function isDevMode() {
88817
+ try {
88818
+ const url = new URL(import.meta.url);
88819
+ return url.pathname.endsWith(".ts");
88820
+ } catch {
88756
88821
  return false;
88757
88822
  }
88823
+ }
88824
+ var init_env = __esm({
88825
+ "src/utils/env.ts"() {
88826
+ "use strict";
88827
+ }
88828
+ });
88829
+
88830
+ // src/telemetry/policy.ts
88831
+ function isEnvOptOutValue(value) {
88832
+ return value !== void 0 && ENV_OPT_OUT_VALUES.has(value.trim().toLowerCase());
88833
+ }
88834
+ function telemetryRuntimeOverride() {
88835
+ if (isEnvOptOutValue(process.env["HYPERFRAMES_NO_TELEMETRY"])) {
88836
+ return "HYPERFRAMES_NO_TELEMETRY";
88837
+ }
88838
+ if (isEnvOptOutValue(process.env["DO_NOT_TRACK"])) {
88839
+ return "DO_NOT_TRACK";
88840
+ }
88758
88841
  if (isDevMode()) {
88759
- telemetryEnabled = false;
88760
- return false;
88842
+ return "dev_mode";
88761
88843
  }
88762
88844
  if (!POSTHOG_API_KEY.startsWith("phc_")) {
88845
+ return "telemetry_disabled_build";
88846
+ }
88847
+ return null;
88848
+ }
88849
+ function effectiveTelemetryStatus(configEnabled) {
88850
+ const override = telemetryRuntimeOverride();
88851
+ if (override !== null) return { enabled: false, source: override };
88852
+ return { enabled: configEnabled, source: "config" };
88853
+ }
88854
+ var ENV_OPT_OUT_VALUES;
88855
+ var init_policy = __esm({
88856
+ "src/telemetry/policy.ts"() {
88857
+ "use strict";
88858
+ init_env();
88859
+ init_transport();
88860
+ ENV_OPT_OUT_VALUES = /* @__PURE__ */ new Set(["1", "true", "yes", "on"]);
88861
+ }
88862
+ });
88863
+
88864
+ // src/telemetry/client.ts
88865
+ function shouldTrack() {
88866
+ if (telemetryEnabled !== null) return telemetryEnabled;
88867
+ if (telemetryRuntimeOverride() !== null) {
88763
88868
  telemetryEnabled = false;
88764
88869
  return false;
88765
88870
  }
@@ -88823,9 +88928,9 @@ var init_client = __esm({
88823
88928
  init_version();
88824
88929
  init_colors();
88825
88930
  init_diagnostics2();
88826
- init_env();
88827
88931
  init_system();
88828
88932
  init_transport();
88933
+ init_policy();
88829
88934
  init_transport();
88830
88935
  telemetryEnabled = null;
88831
88936
  }
@@ -88855,6 +88960,14 @@ __export(events_exports, {
88855
88960
  trackSkillsInstallSkipped: () => trackSkillsInstallSkipped,
88856
88961
  trackTranscribeUnavailable: () => trackTranscribeUnavailable
88857
88962
  });
88963
+ function powerStateFields() {
88964
+ if (!shouldTrack()) return {};
88965
+ const power = getPowerState();
88966
+ return {
88967
+ on_battery: power.on_battery ?? void 0,
88968
+ low_power_mode: power.low_power_mode ?? void 0
88969
+ };
88970
+ }
88858
88971
  function runIdField(runId3) {
88859
88972
  return runId3 !== void 0 ? { run_id: runId3 } : {};
88860
88973
  }
@@ -88892,6 +89005,7 @@ function renderObservabilityEventProperties(props) {
88892
89005
  de_worker_inversion: props.captureDeWorkerInversion,
88893
89006
  de_pre_inversion_workers: props.captureDePreInversionWorkers,
88894
89007
  de_parallel_router: props.captureDeParallelRouter,
89008
+ gpu_renderer: props.captureDeGpuRenderer,
88895
89009
  de_pre_router_workers: props.captureDePreRouterWorkers,
88896
89010
  de_self_verify_fallback: props.captureDeSelfVerifyFallback,
88897
89011
  de_fallback_reason: props.captureDeFallbackReason,
@@ -88960,6 +89074,7 @@ function trackRenderComplete(props) {
88960
89074
  de_parallel_router: props.deParallelRouter,
88961
89075
  de_pre_router_workers: props.dePreRouterWorkers,
88962
89076
  de_gate_reason: props.deGateReason,
89077
+ gpu_renderer: props.gpuRenderer,
88963
89078
  de_worker_encode: props.deWorkerEncode,
88964
89079
  de_verify_armed: props.deVerifyArmed,
88965
89080
  de_verify_checked: props.deVerifyChecked,
@@ -88975,6 +89090,7 @@ function trackRenderComplete(props) {
88975
89090
  de_blank_recaptures: props.deBlankRecaptures,
88976
89091
  de_boundary_frames: props.deBoundaryFrames,
88977
89092
  de_ncpr_fallbacks: props.deNcprFallbacks,
89093
+ ...powerStateFields(),
88978
89094
  source: props.source ?? "cli",
88979
89095
  composition_duration_ms: props.compositionDurationMs,
88980
89096
  composition_width: props.compositionWidth,
@@ -89027,6 +89143,11 @@ function trackRenderError(props) {
89027
89143
  elapsed_ms: props.elapsedMs,
89028
89144
  peak_memory_mb: props.peakMemoryMb,
89029
89145
  memory_free_mb: props.memoryFreeMb,
89146
+ ...powerStateFields(),
89147
+ // gpu_renderer arrives via renderObservabilityEventProperties below:
89148
+ // on the failure path perfSummary is never built, so live capture
89149
+ // observability is the only source. Backend attribution matters MOST
89150
+ // here — a win32 D3D11 crash is what the rollout is watching for.
89030
89151
  ...renderObservabilityEventProperties(props)
89031
89152
  },
89032
89153
  props.distinctId
@@ -89193,6 +89314,7 @@ var init_events = __esm({
89193
89314
  init_feedbackRating();
89194
89315
  init_client();
89195
89316
  init_config();
89317
+ init_system();
89196
89318
  }
89197
89319
  });
89198
89320
 
@@ -93071,6 +93193,25 @@ var init_normalize = __esm({
93071
93193
  }
93072
93194
  });
93073
93195
 
93196
+ // src/telemetry/skill.ts
93197
+ var skill_exports = {};
93198
+ __export(skill_exports, {
93199
+ SKILL_SLUG: () => SKILL_SLUG,
93200
+ normalizeSkillSlug: () => normalizeSkillSlug
93201
+ });
93202
+ function normalizeSkillSlug(raw) {
93203
+ if (typeof raw !== "string") return void 0;
93204
+ const slug = raw.trim();
93205
+ return SKILL_SLUG.test(slug) ? slug : void 0;
93206
+ }
93207
+ var SKILL_SLUG;
93208
+ var init_skill = __esm({
93209
+ "src/telemetry/skill.ts"() {
93210
+ "use strict";
93211
+ SKILL_SLUG = /^[a-z0-9][a-z0-9-]{0,63}$/;
93212
+ }
93213
+ });
93214
+
93074
93215
  // src/utils/projectConfig.ts
93075
93216
  var projectConfig_exports = {};
93076
93217
  __export(projectConfig_exports, {
@@ -93081,6 +93222,7 @@ __export(projectConfig_exports, {
93081
93222
  projectConfigPath: () => projectConfigPath,
93082
93223
  readProjectConfig: () => readProjectConfig,
93083
93224
  resolveAutoProxy: () => resolveAutoProxy,
93225
+ seedProjectAuthoringSkill: () => seedProjectAuthoringSkill,
93084
93226
  writeProjectConfig: () => writeProjectConfig
93085
93227
  });
93086
93228
  import { readFileSync as readFileSync16, writeFileSync as writeFileSync10 } from "fs";
@@ -93108,7 +93250,10 @@ function normalizeConfig(partial) {
93108
93250
  },
93109
93251
  media: {
93110
93252
  autoProxy: typeof partial.media?.autoProxy === "boolean" ? partial.media.autoProxy : DEFAULT_PROJECT_CONFIG.media?.autoProxy
93111
- }
93253
+ },
93254
+ // Slug-gate on read so a hand-edited or corrupt value never reaches the
93255
+ // telemetry stream; an invalid slug simply drops the attribution.
93256
+ authoringSkill: normalizeSkillSlug(partial.authoringSkill)
93112
93257
  };
93113
93258
  }
93114
93259
  function writeProjectConfig(projectDir, config = DEFAULT_PROJECT_CONFIG) {
@@ -93124,11 +93269,44 @@ function resolveAutoProxy(projectDir, flagValue) {
93124
93269
  }
93125
93270
  return loadProjectConfig(projectDir).media?.autoProxy ?? true;
93126
93271
  }
93272
+ function isJsonObject(value) {
93273
+ return typeof value === "object" && value !== null && !Array.isArray(value);
93274
+ }
93275
+ function isFileNotFound(error) {
93276
+ return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
93277
+ }
93278
+ function seedProjectAuthoringSkill(projectDir, rawSkill) {
93279
+ const skill = normalizeSkillSlug(rawSkill);
93280
+ if (!skill) return;
93281
+ const path2 = projectConfigPath(projectDir);
93282
+ let text2;
93283
+ try {
93284
+ text2 = readFileSync16(path2, "utf-8");
93285
+ } catch (error) {
93286
+ if (isFileNotFound(error)) {
93287
+ try {
93288
+ writeProjectConfig(projectDir, { ...DEFAULT_PROJECT_CONFIG, authoringSkill: skill });
93289
+ } catch {
93290
+ }
93291
+ }
93292
+ return;
93293
+ }
93294
+ try {
93295
+ const parsed = JSON.parse(text2);
93296
+ if (!isJsonObject(parsed)) return;
93297
+ if (normalizeSkillSlug(parsed.authoringSkill)) return;
93298
+ parsed.authoringSkill = skill;
93299
+ const indent = /\n([ \t]+)"/.exec(text2)?.[1] ?? " ";
93300
+ writeFileSync10(path2, JSON.stringify(parsed, null, indent) + "\n", "utf-8");
93301
+ } catch {
93302
+ }
93303
+ }
93127
93304
  var PROJECT_CONFIG_FILENAME, PROJECT_CONFIG_SCHEMA_URL, DEFAULT_PROJECT_CONFIG;
93128
93305
  var init_projectConfig = __esm({
93129
93306
  "src/utils/projectConfig.ts"() {
93130
93307
  "use strict";
93131
93308
  init_registry2();
93309
+ init_skill();
93132
93310
  PROJECT_CONFIG_FILENAME = "hyperframes.json";
93133
93311
  PROJECT_CONFIG_SCHEMA_URL = "https://hyperframes.heygen.com/schema/hyperframes.json";
93134
93312
  DEFAULT_PROJECT_CONFIG = {
@@ -93360,9 +93538,10 @@ async function checkForUpdate(force) {
93360
93538
  return fallbackResult(config.latestVersion);
93361
93539
  }
93362
93540
  const latest = data2.version;
93363
- config.lastUpdateCheck = (/* @__PURE__ */ new Date()).toISOString();
93364
- config.latestVersion = latest;
93365
- writeConfig(config);
93541
+ const freshConfig = readConfigFresh();
93542
+ freshConfig.lastUpdateCheck = (/* @__PURE__ */ new Date()).toISOString();
93543
+ freshConfig.latestVersion = latest;
93544
+ writeConfig(freshConfig);
93366
93545
  return { current: VERSION, latest, updateAvailable: isNewerSemver(latest, VERSION) };
93367
93546
  } catch {
93368
93547
  return fallbackResult(config.latestVersion);
@@ -94755,30 +94934,6 @@ var init_storyboard = __esm({
94755
94934
  }
94756
94935
  });
94757
94936
 
94758
- // src/utils/errorMessage.ts
94759
- function normalizeErrorMessage(error) {
94760
- if (error instanceof Error) return error.message;
94761
- if (typeof error === "string") return error;
94762
- if (typeof error === "object" && error !== null) {
94763
- const msg = error.message;
94764
- if (typeof msg === "string") return msg;
94765
- try {
94766
- return JSON.stringify(error);
94767
- } catch {
94768
- try {
94769
- return `{${Object.keys(error).join(", ")}}`;
94770
- } catch {
94771
- }
94772
- }
94773
- }
94774
- return String(error ?? "unknown error");
94775
- }
94776
- var init_errorMessage = __esm({
94777
- "src/utils/errorMessage.ts"() {
94778
- "use strict";
94779
- }
94780
- });
94781
-
94782
94937
  // src/utils/openBrowser.ts
94783
94938
  import { spawn as spawn7 } from "child_process";
94784
94939
  function parseRemoteDebuggingPort(value) {
@@ -95870,6 +96025,7 @@ function renderObservabilityTelemetryPayload(observability) {
95870
96025
  captureDeWorkerInversion: capture2.deWorkerInversion,
95871
96026
  captureDePreInversionWorkers: capture2.dePreInversionWorkers,
95872
96027
  captureDeParallelRouter: capture2.deParallelRouter,
96028
+ captureDeGpuRenderer: capture2.deGpuRenderer,
95873
96029
  captureDePreRouterWorkers: capture2.dePreRouterWorkers,
95874
96030
  captureDeSelfVerifyFallback: capture2.deSelfVerifyFallback,
95875
96031
  captureDeFallbackReason: capture2.deFallbackReason,
@@ -110227,6 +110383,9 @@ function aggregateDrawElement(perfs, de2) {
110227
110383
  const gateReasons = [
110228
110384
  ...new Set(perfs.map((p2) => p2.deGateReason).filter((r2) => !!r2))
110229
110385
  ].sort();
110386
+ const gpuRenderers = [
110387
+ ...new Set(perfs.map((p2) => p2.gpuRenderer).filter((r2) => !!r2))
110388
+ ].sort();
110230
110389
  const drain = de2.drainStats;
110231
110390
  return {
110232
110391
  mode: modes.join("|") || "unknown",
@@ -110237,6 +110396,7 @@ function aggregateDrawElement(perfs, de2) {
110237
110396
  parallelRouter: de2.parallelRouter ?? "none",
110238
110397
  preRouterWorkers: de2.preRouterWorkers,
110239
110398
  gateReason: gateReasons.length > 0 ? gateReasons.join("|") : void 0,
110399
+ gpuRenderer: gpuRenderers.length > 0 ? gpuRenderers.join("|") : void 0,
110240
110400
  workerEncode: perfs.some((p2) => p2.deWorkerEncode),
110241
110401
  verifyArmed: perfs.reduce((sum, p2) => sum + (p2.deVerifyArmed ?? 0), 0),
110242
110402
  verifyChecked: drain?.verifyChecked ?? 0,
@@ -117423,6 +117583,10 @@ function resolveVideoExtractionPolicy(env = process.env) {
117423
117583
  const maxTransientRetries = failureMode !== "off" && env.HF_VIDEO_EXTRACTION_MAX_RETRIES?.trim() === "1" ? 1 : 0;
117424
117584
  return { failureMode, maxTransientRetries };
117425
117585
  }
117586
+ function assertVideoExtractionSucceeded(result) {
117587
+ const error = buildVideoExtractionStageError(result);
117588
+ if (error) throw error;
117589
+ }
117426
117590
  function buildVideoExtractionStageError(result) {
117427
117591
  if (result.success && result.errors.length === 0) return null;
117428
117592
  const counts = /* @__PURE__ */ new Map();
@@ -121335,7 +121499,7 @@ function resolveInversionRetryPlan(args) {
121335
121499
  };
121336
121500
  }
121337
121501
  function shouldPreferParallelDrawElement(args) {
121338
- return args.routerEnabled && args.workerCount > 1 && typeof args.requestedWorkers !== "number" && args.useDrawElement && !args.deCompileGate && !args.forceScreenshot && args.outputFormat === "mp4" && args.minFrames > 0 && args.totalFrames >= args.minFrames && !args.layeredOrEffectRoute && !args.supersampling && !args.probeDeGated && !args.experimentalParallelDeOptIn && // RAM floor: routed parallel DE runs 3 concurrent hardware-GPU Chrome
121502
+ return args.routerEnabled && args.parallelStreamingAvailable && args.workerCount > 1 && typeof args.requestedWorkers !== "number" && args.useDrawElement && !args.deCompileGate && !args.forceScreenshot && args.outputFormat === "mp4" && args.minFrames > 0 && args.totalFrames >= args.minFrames && !args.layeredOrEffectRoute && !args.supersampling && !args.probeDeGated && !args.experimentalParallelDeOptIn && // RAM floor: routed parallel DE runs 3 concurrent hardware-GPU Chrome
121339
121503
  // instances. On a 16 GB machine that produced vertical black slabs in the
121340
121504
  // final MP4 (wild report, CLI 0.7.52) — compositor tiles evicted under
121341
121505
  // GPU/memory pressure, and sampled self-verify can miss partial-frame
@@ -121929,8 +122093,8 @@ async function executeRenderPipeline(input2) {
121929
122093
  });
121930
122094
  const deParallelRouterEnabled = process.env.HF_DE_PARALLEL_ROUTER === "true";
121931
122095
  const deParallelMinFramesRaw = process.env.HF_DE_PARALLEL_MIN_FRAMES;
121932
- const deParallelMinFramesNum = deParallelMinFramesRaw === void 0 || deParallelMinFramesRaw.trim() === "" ? 2e3 : Number(deParallelMinFramesRaw);
121933
- const deParallelMinFrames = Number.isFinite(deParallelMinFramesNum) ? deParallelMinFramesNum : 2e3;
122096
+ const deParallelMinFramesNum = deParallelMinFramesRaw === void 0 || deParallelMinFramesRaw.trim() === "" ? 700 : Number(deParallelMinFramesRaw);
122097
+ const deParallelMinFrames = Number.isFinite(deParallelMinFramesNum) ? deParallelMinFramesNum : 700;
121934
122098
  const deParallelMinMemRaw = process.env.HF_DE_PARALLEL_MIN_MEM_MB;
121935
122099
  const deParallelMinMemNum = deParallelMinMemRaw === void 0 || deParallelMinMemRaw.trim() === "" ? 24576 : Number(deParallelMinMemRaw);
121936
122100
  const deParallelMinMemoryMb = Number.isFinite(deParallelMinMemNum) ? deParallelMinMemNum : 24576;
@@ -121948,6 +122112,15 @@ async function executeRenderPipeline(input2) {
121948
122112
  probeDeGated: probeSession !== null && probeSession.captureMode !== "drawelement" && !probeSession.deInitDeferred,
121949
122113
  experimentalParallelDeOptIn: process.env.PRODUCER_EXPERIMENTAL_FAST_CAPTURE === "true" || process.env.HF_DE_PARALLEL_STREAM === "true",
121950
122114
  routerEnabled: deParallelRouterEnabled,
122115
+ // Router pins 3 workers for the streaming path; don't pin when the
122116
+ // duration cap (or any other streaming gate) would turn that path off.
122117
+ parallelStreamingAvailable: shouldUseStreamingEncode(
122118
+ cfg,
122119
+ outputFormat,
122120
+ 3,
122121
+ job.duration,
122122
+ true
122123
+ ),
121951
122124
  totalMemoryMb: Math.round(totalmem2() / (1024 * 1024)),
121952
122125
  minMemoryMb: deParallelMinMemoryMb
121953
122126
  });
@@ -122071,7 +122244,12 @@ async function executeRenderPipeline(input2) {
122071
122244
  // to 3 workers regardless of calibration is the leading suspect for
122072
122245
  // any resource-pressure failure unique to this cohort.
122073
122246
  dePreInversionWorkers: deWorkerInversion ? preRoutingWorkerCount : void 0,
122074
- dePreRouterWorkers: deParallelRouter ? preRoutingWorkerCount : void 0
122247
+ dePreRouterWorkers: deParallelRouter ? preRoutingWorkerCount : void 0,
122248
+ // Same rationale as the counters above: carried on live capture
122249
+ // observability, not only the success-path perfSummary, so a crash /
122250
+ // OOM / timeout still reports which GPU backend it happened on. That
122251
+ // is the cohort the win32 D3D11 rollout most needs to attribute.
122252
+ deGpuRenderer: probeSession?.gpuRenderer
122075
122253
  });
122076
122254
  observability.checkpoint("worker_resolution", "resolved", {
122077
122255
  workerCount,
@@ -124194,6 +124372,7 @@ var init_server = __esm({
124194
124372
  init_renderRequest();
124195
124373
  DEFAULT_SERVER_FPS = { num: 30, den: 1 };
124196
124374
  SAFE_RENDER_ERROR_CODES = /* @__PURE__ */ new Set([
124375
+ "INVALID_VIDEO_METADATA",
124197
124376
  "VIDEO_SOURCE_UNRENDERABLE",
124198
124377
  "VIDEO_EXTRACTION_FAILED"
124199
124378
  ]);
@@ -124578,6 +124757,154 @@ import { dirname as dirname28, join as join63 } from "path";
124578
124757
  import { existsSync as existsSync56, readFileSync as readFileSync33 } from "fs";
124579
124758
  import { fileURLToPath as fileURLToPath7 } from "url";
124580
124759
  import { promisify as promisify4 } from "util";
124760
+ function metadataError(field, expectation) {
124761
+ throw new PlanVideosMetadataError(`${field} ${expectation}`);
124762
+ }
124763
+ function readRecord(value, field) {
124764
+ if (value === null || typeof value !== "object" || Array.isArray(value)) {
124765
+ metadataError(field, "must be an object");
124766
+ }
124767
+ return value;
124768
+ }
124769
+ function readNonEmptyString(value, field) {
124770
+ if (typeof value !== "string" || value.length === 0) {
124771
+ metadataError(field, "must be a non-empty string");
124772
+ }
124773
+ return value;
124774
+ }
124775
+ function readString(value, field) {
124776
+ if (typeof value !== "string") {
124777
+ metadataError(field, "must be a string");
124778
+ }
124779
+ return value;
124780
+ }
124781
+ function readFiniteNumber(value, field) {
124782
+ if (typeof value !== "number" || !Number.isFinite(value)) {
124783
+ metadataError(field, "must be a finite number");
124784
+ }
124785
+ return value;
124786
+ }
124787
+ function readBoolean(value, field) {
124788
+ if (typeof value !== "boolean") {
124789
+ metadataError(field, "must be boolean");
124790
+ }
124791
+ return value;
124792
+ }
124793
+ function readPositiveInteger(value, field) {
124794
+ if (typeof value !== "number" || !Number.isInteger(value) || value <= 0) {
124795
+ metadataError(field, "must be a positive integer");
124796
+ }
124797
+ return value;
124798
+ }
124799
+ function readNonNegativeInteger(value, field) {
124800
+ if (typeof value !== "number" || !Number.isInteger(value) || value < 0) {
124801
+ metadataError(field, "must be a non-negative integer");
124802
+ }
124803
+ return value;
124804
+ }
124805
+ function readVideoMetadata(value, field) {
124806
+ const record = readRecord(value, field);
124807
+ let colorSpace = null;
124808
+ if (record.colorSpace !== null) {
124809
+ const color = readRecord(record.colorSpace, `${field}.colorSpace`);
124810
+ colorSpace = {
124811
+ colorTransfer: readString(color.colorTransfer, `${field}.colorSpace.colorTransfer`),
124812
+ colorPrimaries: readString(color.colorPrimaries, `${field}.colorSpace.colorPrimaries`),
124813
+ colorSpace: readString(color.colorSpace, `${field}.colorSpace.colorSpace`)
124814
+ };
124815
+ }
124816
+ return {
124817
+ durationSeconds: readFiniteNumber(record.durationSeconds, `${field}.durationSeconds`),
124818
+ videoStreamDurationSeconds: readFiniteNumber(
124819
+ record.videoStreamDurationSeconds,
124820
+ `${field}.videoStreamDurationSeconds`
124821
+ ),
124822
+ width: readPositiveInteger(record.width, `${field}.width`),
124823
+ height: readPositiveInteger(record.height, `${field}.height`),
124824
+ fps: readFiniteNumber(record.fps, `${field}.fps`),
124825
+ videoCodec: readNonEmptyString(record.videoCodec, `${field}.videoCodec`),
124826
+ hasAudio: readBoolean(record.hasAudio, `${field}.hasAudio`),
124827
+ isVFR: readBoolean(record.isVFR, `${field}.isVFR`),
124828
+ hasAlpha: readBoolean(record.hasAlpha, `${field}.hasAlpha`),
124829
+ colorSpace
124830
+ };
124831
+ }
124832
+ function parsePlanVideosJson(value) {
124833
+ const record = readRecord(value, "meta/videos.json");
124834
+ if (!Array.isArray(record.videos) || !Array.isArray(record.extracted)) {
124835
+ metadataError("meta/videos.json", "must contain videos and extracted arrays");
124836
+ }
124837
+ const videos = record.videos.map((value2, index) => {
124838
+ const field = `meta/videos.json.videos[${index}]`;
124839
+ const video = readRecord(value2, field);
124840
+ return {
124841
+ id: readNonEmptyString(video.id, `${field}.id`),
124842
+ src: readNonEmptyString(video.src, `${field}.src`),
124843
+ start: readFiniteNumber(video.start, `${field}.start`),
124844
+ end: readFiniteNumber(video.end, `${field}.end`),
124845
+ mediaStart: readFiniteNumber(video.mediaStart, `${field}.mediaStart`),
124846
+ loop: readBoolean(video.loop, `${field}.loop`),
124847
+ hasAudio: readBoolean(video.hasAudio, `${field}.hasAudio`)
124848
+ };
124849
+ });
124850
+ const extracted = record.extracted.map((value2, index) => {
124851
+ const field = `meta/videos.json.extracted[${index}]`;
124852
+ const entry = readRecord(value2, field);
124853
+ return {
124854
+ videoId: readNonEmptyString(entry.videoId, `${field}.videoId`),
124855
+ srcPath: readNonEmptyString(entry.srcPath, `${field}.srcPath`),
124856
+ framePattern: readNonEmptyString(entry.framePattern, `${field}.framePattern`),
124857
+ fps: readFiniteNumber(entry.fps, `${field}.fps`),
124858
+ totalFrames: readNonNegativeInteger(entry.totalFrames, `${field}.totalFrames`),
124859
+ metadata: readVideoMetadata(entry.metadata, `${field}.metadata`)
124860
+ };
124861
+ });
124862
+ const videoIds = /* @__PURE__ */ new Set();
124863
+ for (const video of videos) {
124864
+ if (videoIds.has(video.id)) {
124865
+ metadataError("meta/videos.json.videos", `contains duplicate id ${JSON.stringify(video.id)}`);
124866
+ }
124867
+ videoIds.add(video.id);
124868
+ }
124869
+ const extractedIds = /* @__PURE__ */ new Set();
124870
+ for (const entry of extracted) {
124871
+ if (extractedIds.has(entry.videoId)) {
124872
+ metadataError(
124873
+ "meta/videos.json.extracted",
124874
+ `contains duplicate videoId ${JSON.stringify(entry.videoId)}`
124875
+ );
124876
+ }
124877
+ extractedIds.add(entry.videoId);
124878
+ if (!videoIds.has(entry.videoId)) {
124879
+ metadataError(
124880
+ "meta/videos.json.extracted",
124881
+ `references undeclared video ${JSON.stringify(entry.videoId)}`
124882
+ );
124883
+ }
124884
+ }
124885
+ for (const video of videos) {
124886
+ if (!extractedIds.has(video.id)) {
124887
+ metadataError(
124888
+ "meta/videos.json.extracted",
124889
+ `is missing declared video ${JSON.stringify(video.id)}`
124890
+ );
124891
+ }
124892
+ }
124893
+ return { videos, extracted };
124894
+ }
124895
+ function buildPlanVideosJson(input2) {
124896
+ const videos = input2.videos.map((video, index) => {
124897
+ if (Number.isFinite(video.end)) return { ...video };
124898
+ if (!Number.isFinite(input2.compositionEnd) || input2.compositionEnd <= 0 || input2.compositionEnd <= video.start) {
124899
+ metadataError(
124900
+ `meta/videos.json.videos[${index}].end`,
124901
+ "cannot be resolved without a finite composition end after its start"
124902
+ );
124903
+ }
124904
+ return { ...video, end: input2.compositionEnd };
124905
+ });
124906
+ return parsePlanVideosJson({ videos, extracted: input2.extracted });
124907
+ }
124581
124908
  async function readFfmpegVersion() {
124582
124909
  if (cachedFfmpegVersion !== null) return cachedFfmpegVersion;
124583
124910
  const { stdout: stdout2 } = await execFile6("ffmpeg", ["-version"], { maxBuffer: 1024 * 1024 });
@@ -124634,7 +124961,7 @@ function readProducerVersion() {
124634
124961
  cachedProducerVersion = "0.0.0-unknown";
124635
124962
  return cachedProducerVersion;
124636
124963
  }
124637
- var PLAN_VIDEOS_META_RELATIVE_PATH, PLAN_AUDIO_RELATIVE_PATH, execFile6, cachedFfmpegVersion, cachedProducerVersion;
124964
+ var PLAN_VIDEOS_META_RELATIVE_PATH, PLAN_AUDIO_RELATIVE_PATH, INVALID_VIDEO_METADATA, PlanVideosMetadataError, execFile6, cachedFfmpegVersion, cachedProducerVersion;
124638
124965
  var init_shared2 = __esm({
124639
124966
  "../producer/src/services/distributed/shared.ts"() {
124640
124967
  "use strict";
@@ -124642,6 +124969,16 @@ var init_shared2 = __esm({
124642
124969
  init_logger();
124643
124970
  PLAN_VIDEOS_META_RELATIVE_PATH = "meta/videos.json";
124644
124971
  PLAN_AUDIO_RELATIVE_PATH = "audio.aac";
124972
+ INVALID_VIDEO_METADATA = "INVALID_VIDEO_METADATA";
124973
+ PlanVideosMetadataError = class extends Error {
124974
+ // Read by cloud adapters across the package boundary to classify retries.
124975
+ // fallow-ignore-next-line unused-class-member
124976
+ code = INVALID_VIDEO_METADATA;
124977
+ constructor(message) {
124978
+ super(message);
124979
+ this.name = "PlanVideosMetadataError";
124980
+ }
124981
+ };
124645
124982
  execFile6 = promisify4(execFileCallback);
124646
124983
  cachedFfmpegVersion = null;
124647
124984
  cachedProducerVersion = null;
@@ -125117,6 +125454,9 @@ async function plan(projectDir, config, planDir) {
125117
125454
  materializeSymlinks: true
125118
125455
  });
125119
125456
  if (extractResult.failureToEnforce) throw extractResult.failureToEnforce;
125457
+ if (extractResult.extractionResult) {
125458
+ assertVideoExtractionSucceeded(extractResult.extractionResult);
125459
+ }
125120
125460
  const audioResult = await runAudioStage({
125121
125461
  projectDir,
125122
125462
  workDir,
@@ -125139,8 +125479,9 @@ async function plan(projectDir, config, planDir) {
125139
125479
  }
125140
125480
  if (existsSync57(finalCompiledDir)) rmSync18(finalCompiledDir, { recursive: true, force: true });
125141
125481
  renameSync12(compiledDir, finalCompiledDir);
125142
- const planVideosJson = {
125482
+ const planVideosJson = buildPlanVideosJson({
125143
125483
  videos: composition.videos,
125484
+ compositionEnd: job.duration ?? Number.NaN,
125144
125485
  extracted: (extractResult.extractionResult?.extracted ?? []).map((ext) => ({
125145
125486
  videoId: ext.videoId,
125146
125487
  srcPath: ext.srcPath,
@@ -125149,7 +125490,7 @@ async function plan(projectDir, config, planDir) {
125149
125490
  totalFrames: ext.totalFrames,
125150
125491
  metadata: ext.metadata
125151
125492
  }))
125152
- };
125493
+ });
125153
125494
  mkdirSync29(join65(planDir, "meta"), { recursive: true });
125154
125495
  writeFileSync20(
125155
125496
  join65(planDir, PLAN_VIDEOS_META_RELATIVE_PATH),
@@ -125635,90 +125976,20 @@ function listVideoFramePaths(planV1Dir, videos) {
125635
125976
  };
125636
125977
  });
125637
125978
  }
125638
- function readFiniteNumber(value, field) {
125639
- if (typeof value !== "number" || !Number.isFinite(value)) {
125640
- throw new PlanV2IntegrityError(`${field} must be a finite number`);
125641
- }
125642
- return value;
125643
- }
125644
- function readBoolean(value, field) {
125645
- if (typeof value !== "boolean") {
125646
- throw new PlanV2IntegrityError(`${field} must be boolean`);
125647
- }
125648
- return value;
125649
- }
125650
- function readVideoMetadata(value, field) {
125651
- if (!isRecord7(value)) {
125652
- throw new PlanV2IntegrityError(`${field} must be an object`);
125653
- }
125654
- let colorSpace = null;
125655
- if (value.colorSpace !== null) {
125656
- if (!isRecord7(value.colorSpace)) {
125657
- throw new PlanV2IntegrityError(`${field}.colorSpace must be an object or null`);
125979
+ function parsePlanVideosJson2(value) {
125980
+ try {
125981
+ return parsePlanVideosJson(value);
125982
+ } catch (err) {
125983
+ if (err instanceof PlanVideosMetadataError) {
125984
+ throw new PlanV2IntegrityError(err.message);
125658
125985
  }
125659
- colorSpace = {
125660
- colorTransfer: readColorComponent(
125661
- value.colorSpace.colorTransfer,
125662
- `${field}.colorSpace.colorTransfer`
125663
- ),
125664
- colorPrimaries: readColorComponent(
125665
- value.colorSpace.colorPrimaries,
125666
- `${field}.colorSpace.colorPrimaries`
125667
- ),
125668
- colorSpace: readColorComponent(value.colorSpace.colorSpace, `${field}.colorSpace.colorSpace`)
125669
- };
125986
+ throw err;
125670
125987
  }
125671
- return {
125672
- durationSeconds: readFiniteNumber(value.durationSeconds, `${field}.durationSeconds`),
125673
- videoStreamDurationSeconds: readFiniteNumber(
125674
- value.videoStreamDurationSeconds,
125675
- `${field}.videoStreamDurationSeconds`
125676
- ),
125677
- width: readPositiveInteger(value.width, `${field}.width`),
125678
- height: readPositiveInteger(value.height, `${field}.height`),
125679
- fps: readFiniteNumber(value.fps, `${field}.fps`),
125680
- videoCodec: readString(value.videoCodec, `${field}.videoCodec`),
125681
- hasAudio: readBoolean(value.hasAudio, `${field}.hasAudio`),
125682
- isVFR: readBoolean(value.isVFR, `${field}.isVFR`),
125683
- hasAlpha: readBoolean(value.hasAlpha, `${field}.hasAlpha`),
125684
- colorSpace
125685
- };
125686
- }
125687
- function parsePlanVideosJson(value) {
125688
- if (!isRecord7(value) || !Array.isArray(value.videos) || !Array.isArray(value.extracted)) {
125689
- throw new PlanV2IntegrityError("meta/videos.json must contain videos and extracted arrays");
125690
- }
125691
- const videos = value.videos.map((video, index) => {
125692
- const field = `meta/videos.json.videos[${index}]`;
125693
- if (!isRecord7(video)) throw new PlanV2IntegrityError(`${field} must be an object`);
125694
- return {
125695
- id: readString(video.id, `${field}.id`),
125696
- src: readString(video.src, `${field}.src`),
125697
- start: readFiniteNumber(video.start, `${field}.start`),
125698
- end: readFiniteNumber(video.end, `${field}.end`),
125699
- mediaStart: readFiniteNumber(video.mediaStart, `${field}.mediaStart`),
125700
- loop: readBoolean(video.loop, `${field}.loop`),
125701
- hasAudio: readBoolean(video.hasAudio, `${field}.hasAudio`)
125702
- };
125703
- });
125704
- const extracted = value.extracted.map((entry, index) => {
125705
- const field = `meta/videos.json.extracted[${index}]`;
125706
- if (!isRecord7(entry)) throw new PlanV2IntegrityError(`${field} must be an object`);
125707
- return {
125708
- videoId: readString(entry.videoId, `${field}.videoId`),
125709
- srcPath: readString(entry.srcPath, `${field}.srcPath`),
125710
- framePattern: readString(entry.framePattern, `${field}.framePattern`),
125711
- fps: readFiniteNumber(entry.fps, `${field}.fps`),
125712
- totalFrames: readNonNegativeInteger(entry.totalFrames, `${field}.totalFrames`),
125713
- metadata: readVideoMetadata(entry.metadata, `${field}.metadata`)
125714
- };
125715
- });
125716
- return { videos, extracted };
125717
125988
  }
125718
125989
  function materializeExtractedVideoDirectories(planDir) {
125719
125990
  const videosPath = join68(planDir, PLAN_VIDEOS_META_RELATIVE_PATH);
125720
125991
  if (!existsSync59(videosPath)) return;
125721
- const videos = parsePlanVideosJson(readJsonFile(videosPath, PLAN_VIDEOS_META_RELATIVE_PATH));
125992
+ const videos = parsePlanVideosJson2(readJsonFile(videosPath, PLAN_VIDEOS_META_RELATIVE_PATH));
125722
125993
  for (const video of videos.extracted) {
125723
125994
  mkdirSync31(resolveExtractedVideoOutputDir(planDir, video.videoId), { recursive: true });
125724
125995
  }
@@ -125731,9 +126002,9 @@ function parseChunkSlices(value) {
125731
126002
  return value.map((chunk, position) => {
125732
126003
  const field = `meta/chunks.json[${position}]`;
125733
126004
  if (!isRecord7(chunk)) throw new PlanV2IntegrityError(`${field} must be an object`);
125734
- const index = readNonNegativeInteger(chunk.index, `${field}.index`);
125735
- const startFrame = readNonNegativeInteger(chunk.startFrame, `${field}.startFrame`);
125736
- const endFrame = readPositiveInteger(chunk.endFrame, `${field}.endFrame`);
126005
+ const index = readNonNegativeInteger2(chunk.index, `${field}.index`);
126006
+ const startFrame = readNonNegativeInteger2(chunk.startFrame, `${field}.startFrame`);
126007
+ const endFrame = readPositiveInteger2(chunk.endFrame, `${field}.endFrame`);
125737
126008
  if (endFrame <= startFrame) {
125738
126009
  throw new PlanV2IntegrityError(`${field}.endFrame must be greater than startFrame`);
125739
126010
  }
@@ -125754,12 +126025,12 @@ function buildVideoChunkDependencies(planV1Dir, dimensions) {
125754
126025
  const chunksPath = join68(planV1Dir, "meta", "chunks.json");
125755
126026
  const videos = readJsonFile(videosPath, PLAN_VIDEOS_META_RELATIVE_PATH);
125756
126027
  const chunks = readJsonFile(chunksPath, "meta/chunks.json");
125757
- const parsedVideos = parsePlanVideosJson(videos);
126028
+ const parsedVideos = parsePlanVideosJson2(videos);
125758
126029
  const parsedChunks = parseChunkSlices(chunks);
125759
126030
  const extracted = listVideoFramePaths(planV1Dir, parsedVideos);
125760
126031
  const table = createFrameLookupTable(parsedVideos.videos, extracted);
125761
- const fpsNum = readPositiveInteger(dimensions.fpsNum, "dimensions.fpsNum");
125762
- const fpsDen = readPositiveInteger(dimensions.fpsDen, "dimensions.fpsDen");
126032
+ const fpsNum = readPositiveInteger2(dimensions.fpsNum, "dimensions.fpsNum");
126033
+ const fpsDen = readPositiveInteger2(dimensions.fpsDen, "dimensions.fpsDen");
125763
126034
  const mutable = /* @__PURE__ */ new Map();
125764
126035
  for (const chunk of parsedChunks) {
125765
126036
  for (let frame = chunk.startFrame; frame < chunk.endFrame; frame++) {
@@ -125848,14 +126119,14 @@ function buildPlanV2Publication(planV1Dir) {
125848
126119
  const base2 = {
125849
126120
  protocol: PLAN_PROTOCOL_V2,
125850
126121
  sourcePlanV1Hash,
125851
- chunkCount: readPositiveInteger(v1Plan.chunkCount, "chunkCount"),
125852
- totalFrames: readPositiveInteger(v1Plan.totalFrames, "totalFrames"),
126122
+ chunkCount: readPositiveInteger2(v1Plan.chunkCount, "chunkCount"),
126123
+ totalFrames: readPositiveInteger2(v1Plan.totalFrames, "totalFrames"),
125853
126124
  fps: readV1PlanFps(dimensions),
125854
- width: readPositiveInteger(dimensions.width, "dimensions.width"),
125855
- height: readPositiveInteger(dimensions.height, "dimensions.height"),
126125
+ width: readPositiveInteger2(dimensions.width, "dimensions.width"),
126126
+ height: readPositiveInteger2(dimensions.height, "dimensions.height"),
125856
126127
  format: readDistributedFormat(dimensions.format),
125857
- ffmpegVersion: readString(v1Plan.ffmpegVersion, "ffmpegVersion"),
125858
- producerVersion: readString(v1Plan.producerVersion, "producerVersion"),
126128
+ ffmpegVersion: readString2(v1Plan.ffmpegVersion, "ffmpegVersion"),
126129
+ producerVersion: readString2(v1Plan.producerVersion, "producerVersion"),
125859
126130
  limitations: { videoDependencyMode: videoDependencyPlan.mode },
125860
126131
  artifacts
125861
126132
  };
@@ -125958,25 +126229,19 @@ function resultFromManifest(planV2Dir, manifest) {
125958
126229
  limitations: manifest.limitations
125959
126230
  };
125960
126231
  }
125961
- function readString(value, field) {
126232
+ function readString2(value, field) {
125962
126233
  if (typeof value !== "string" || value.length === 0) {
125963
126234
  throw new PlanV2IntegrityError(`${field} must be a non-empty string`);
125964
126235
  }
125965
126236
  return value;
125966
126237
  }
125967
- function readColorComponent(value, field) {
125968
- if (typeof value !== "string") {
125969
- throw new PlanV2IntegrityError(`${field} must be a string`);
125970
- }
125971
- return value;
125972
- }
125973
- function readPositiveInteger(value, field) {
126238
+ function readPositiveInteger2(value, field) {
125974
126239
  if (typeof value !== "number" || !Number.isInteger(value) || value <= 0) {
125975
126240
  throw new PlanV2IntegrityError(`${field} must be a positive integer`);
125976
126241
  }
125977
126242
  return value;
125978
126243
  }
125979
- function readNonNegativeInteger(value, field) {
126244
+ function readNonNegativeInteger2(value, field) {
125980
126245
  if (typeof value !== "number" || !Number.isInteger(value) || value < 0) {
125981
126246
  throw new PlanV2IntegrityError(`${field} must be a non-negative integer`);
125982
126247
  }
@@ -125989,7 +126254,7 @@ function readSupportedFps(value) {
125989
126254
  return value;
125990
126255
  }
125991
126256
  function readV1PlanFps(dimensions) {
125992
- const fpsDen = readPositiveInteger(dimensions.fpsDen, "dimensions.fpsDen");
126257
+ const fpsDen = readPositiveInteger2(dimensions.fpsDen, "dimensions.fpsDen");
125993
126258
  if (fpsDen !== 1) {
125994
126259
  throw new PlanV2IntegrityError("dimensions.fpsDen must be 1 for plan v2");
125995
126260
  }
@@ -126003,7 +126268,7 @@ function readDistributedFormat(value) {
126003
126268
  }
126004
126269
  function parseArtifact(value, index) {
126005
126270
  if (!isRecord7(value)) throw new PlanV2IntegrityError(`artifacts[${index}] must be an object`);
126006
- const path2 = readString(value.path, `artifacts[${index}].path`);
126271
+ const path2 = readString2(value.path, `artifacts[${index}].path`);
126007
126272
  assertSafeRelativePath(path2);
126008
126273
  if (!isSha256(value.sha256)) {
126009
126274
  throw new PlanV2IntegrityError(`artifacts[${index}].sha256 must be a lowercase sha256`);
@@ -126056,14 +126321,14 @@ function parsePlanV2Manifest(value) {
126056
126321
  protocol: PLAN_PROTOCOL_V2,
126057
126322
  planHash: value.planHash,
126058
126323
  sourcePlanV1Hash: value.sourcePlanV1Hash,
126059
- chunkCount: readPositiveInteger(value.chunkCount, "chunkCount"),
126060
- totalFrames: readPositiveInteger(value.totalFrames, "totalFrames"),
126324
+ chunkCount: readPositiveInteger2(value.chunkCount, "chunkCount"),
126325
+ totalFrames: readPositiveInteger2(value.totalFrames, "totalFrames"),
126061
126326
  fps: readSupportedFps(value.fps),
126062
- width: readPositiveInteger(value.width, "width"),
126063
- height: readPositiveInteger(value.height, "height"),
126327
+ width: readPositiveInteger2(value.width, "width"),
126328
+ height: readPositiveInteger2(value.height, "height"),
126064
126329
  format: readDistributedFormat(value.format),
126065
- ffmpegVersion: readString(value.ffmpegVersion, "ffmpegVersion"),
126066
- producerVersion: readString(value.producerVersion, "producerVersion"),
126330
+ ffmpegVersion: readString2(value.ffmpegVersion, "ffmpegVersion"),
126331
+ producerVersion: readString2(value.producerVersion, "producerVersion"),
126067
126332
  limitations: { videoDependencyMode: value.limitations.videoDependencyMode },
126068
126333
  artifacts
126069
126334
  };
@@ -126465,6 +126730,16 @@ var init_assemble = __esm({
126465
126730
  import { randomBytes as randomBytes2 } from "crypto";
126466
126731
  import { existsSync as existsSync61, mkdirSync as mkdirSync34, readFileSync as readFileSync36, readdirSync as readdirSync21, rmSync as rmSync23, writeFileSync as writeFileSync25 } from "fs";
126467
126732
  import { extname as extname15, join as join70 } from "path";
126733
+ function validatePlanVideosForChunk(value) {
126734
+ try {
126735
+ return parsePlanVideosJson(value);
126736
+ } catch (err) {
126737
+ throw new RenderChunkValidationError(
126738
+ INVALID_VIDEO_METADATA,
126739
+ `[renderChunk] invalid meta/videos.json: ${err instanceof Error ? err.message : String(err)}`
126740
+ );
126741
+ }
126742
+ }
126468
126743
  async function createVerifiedDistributedCaptureSession(serverUrl, framesDir, captureOptions, cfg, dependencies = distributedCaptureSessionDependencies) {
126469
126744
  const session = await dependencies.createCaptureSession(
126470
126745
  serverUrl,
@@ -126599,10 +126874,11 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath) {
126599
126874
  let planVideos = null;
126600
126875
  if (existsSync61(videosJsonPath)) {
126601
126876
  try {
126602
- planVideos = JSON.parse(readFileSync36(videosJsonPath, "utf-8"));
126877
+ planVideos = validatePlanVideosForChunk(JSON.parse(readFileSync36(videosJsonPath, "utf-8")));
126603
126878
  } catch (err) {
126879
+ if (err instanceof RenderChunkValidationError) throw err;
126604
126880
  throw new RenderChunkValidationError(
126605
- MISSING_PLAN_ARTIFACT,
126881
+ INVALID_VIDEO_METADATA,
126606
126882
  `[renderChunk] failed to parse ${videosJsonPath}: ${err instanceof Error ? err.message : String(err)}`
126607
126883
  );
126608
126884
  }
@@ -127097,6 +127373,7 @@ var init_distributed = __esm({
127097
127373
  init_renderConfigValidation();
127098
127374
  init_projectHash();
127099
127375
  init_planProtocol();
127376
+ init_shared2();
127100
127377
  init_planValidation();
127101
127378
  }
127102
127379
  });
@@ -130123,7 +130400,7 @@ function applyResolutionPreset(destDir, resolution) {
130123
130400
  if (changed) writeFileSync27(file, html, "utf-8");
130124
130401
  }
130125
130402
  }
130126
- async function scaffoldProject(destDir, name, templateId, localVideoName, durationSeconds, tailwind = false, resolution) {
130403
+ async function scaffoldProject(destDir, name, templateId, localVideoName, durationSeconds, tailwind = false, resolution, authoringSkill) {
130127
130404
  mkdirSync38(destDir, { recursive: true });
130128
130405
  const templateDir = getStaticTemplateDir(templateId);
130129
130406
  if (existsSync67(join78(templateDir, "index.html"))) {
@@ -130149,7 +130426,12 @@ async function scaffoldProject(destDir, name, templateId, localVideoName, durati
130149
130426
  );
130150
130427
  if (!existsSync67(resolve39(destDir, "hyperframes.json"))) {
130151
130428
  const { writeProjectConfig: writeProjectConfig2, DEFAULT_PROJECT_CONFIG: DEFAULT_PROJECT_CONFIG2 } = await Promise.resolve().then(() => (init_projectConfig(), projectConfig_exports));
130152
- writeProjectConfig2(destDir, DEFAULT_PROJECT_CONFIG2);
130429
+ const { normalizeSkillSlug: normalizeSkillSlug2 } = await Promise.resolve().then(() => (init_skill(), skill_exports));
130430
+ const skill = normalizeSkillSlug2(authoringSkill);
130431
+ writeProjectConfig2(
130432
+ destDir,
130433
+ skill ? { ...DEFAULT_PROJECT_CONFIG2, authoringSkill: skill } : DEFAULT_PROJECT_CONFIG2
130434
+ );
130153
130435
  }
130154
130436
  writeDefaultPackageJson(destDir, name);
130155
130437
  const sharedDir = getSharedTemplateDir();
@@ -130298,6 +130580,10 @@ var init_init = __esm({
130298
130580
  resolution: {
130299
130581
  type: "string",
130300
130582
  description: "Canvas resolution preset: landscape (1920x1080), portrait (1080x1920), landscape-4k (3840x2160), portrait-4k (2160x3840), square (1080x1080), square-4k (2160x2160). Aliases: 1080p, 4k, uhd, 1080p-square, square-1080p, 4k-square. Default: keep template dimensions (typically 1920x1080)."
130583
+ },
130584
+ skill: {
130585
+ type: "string",
130586
+ description: "Owning authoring workflow slug (e.g. product-launch-video). Stamped into hyperframes.json so every render of this project is attributed to it on anonymous telemetry, without re-passing --skill on each render. Ignored unless it is a slug."
130301
130587
  }
130302
130588
  },
130303
130589
  async run({ args }) {
@@ -130432,7 +130718,8 @@ var init_init = __esm({
130432
130718
  localVideoName2,
130433
130719
  videoDuration2,
130434
130720
  tailwind,
130435
- resolutionPreset
130721
+ resolutionPreset,
130722
+ args.skill
130436
130723
  );
130437
130724
  } catch (err) {
130438
130725
  console.error(
@@ -130620,7 +130907,8 @@ var init_init = __esm({
130620
130907
  localVideoName,
130621
130908
  videoDuration,
130622
130909
  tailwind,
130623
- resolutionPreset
130910
+ resolutionPreset,
130911
+ args.skill
130624
130912
  );
130625
130913
  if (!isBundled) {
130626
130914
  spin.stop(c.success(`Downloaded ${templateId}`));
@@ -133822,20 +134110,6 @@ var init_renderArgs = __esm({
133822
134110
  }
133823
134111
  });
133824
134112
 
133825
- // src/telemetry/skill.ts
133826
- function normalizeSkillSlug(raw) {
133827
- if (typeof raw !== "string") return void 0;
133828
- const slug = raw.trim();
133829
- return SKILL_SLUG.test(slug) ? slug : void 0;
133830
- }
133831
- var SKILL_SLUG;
133832
- var init_skill = __esm({
133833
- "src/telemetry/skill.ts"() {
133834
- "use strict";
133835
- SKILL_SLUG = /^[a-z0-9][a-z0-9-]{0,63}$/;
133836
- }
133837
- });
133838
-
133839
134113
  // src/commands/render/plan.ts
133840
134114
  import { statSync as statSync27 } from "fs";
133841
134115
  import { dirname as dirname39, join as join85, resolve as resolve51 } from "path";
@@ -133885,8 +134159,9 @@ function createRenderPlan(args, now = /* @__PURE__ */ new Date()) {
133885
134159
  failUsage();
133886
134160
  }
133887
134161
  const quality = qualityRaw;
133888
- const authoringSkill = normalizeSkillSlug(args.skill);
133889
- const invalidAuthoringSkill = typeof args.skill === "string" && args.skill.trim() !== "" && !authoringSkill ? args.skill : void 0;
134162
+ const flagSkill = normalizeSkillSlug(args.skill);
134163
+ const authoringSkill = flagSkill ?? loadProjectConfig(project.dir).authoringSkill;
134164
+ const invalidAuthoringSkill = typeof args.skill === "string" && args.skill.trim() !== "" && !flagSkill ? args.skill : void 0;
133890
134165
  const formatRaw = args.format ?? "mp4";
133891
134166
  const format = parseRenderFormat(formatRaw);
133892
134167
  if (!format) {
@@ -134122,6 +134397,7 @@ var init_plan2 = __esm({
134122
134397
  init_project();
134123
134398
  init_renderArgs();
134124
134399
  init_skill();
134400
+ init_projectConfig();
134125
134401
  VALID_QUALITY = /* @__PURE__ */ new Set(["draft", "standard", "high"]);
134126
134402
  RENDER_FORMATS = ["mp4", "webm", "mov", "png-sequence", "gif"];
134127
134403
  VALID_FORMAT = new Set(RENDER_FORMATS);
@@ -135479,7 +135755,7 @@ __export(render_exports, {
135479
135755
  renderLocal: () => renderLocal,
135480
135756
  resolveBrowserGpuForCli: () => resolveBrowserGpuForCli
135481
135757
  });
135482
- import { mkdirSync as mkdirSync43, readdirSync as readdirSync27, readFileSync as readFileSync53, statSync as statSync28, writeFileSync as writeFileSync30, rmSync as rmSync26 } from "fs";
135758
+ import { mkdtempSync as mkdtempSync11, readdirSync as readdirSync27, readFileSync as readFileSync53, statSync as statSync28, writeFileSync as writeFileSync30, rmSync as rmSync26 } from "fs";
135483
135759
  import { freemem as freemem5, tmpdir as tmpdir12 } from "os";
135484
135760
  import { resolve as resolve54, dirname as dirname41, join as join87, basename as basename16 } from "path";
135485
135761
  import { execFileSync as execFileSync11, spawn as spawn14 } from "child_process";
@@ -135547,8 +135823,7 @@ function ensureDockerImage(version2, platform10, quiet) {
135547
135823
  }
135548
135824
  if (!quiet) console.log(c.dim(` Building Docker image: ${tag} (${platform10})...`));
135549
135825
  const dockerfilePath = resolveDockerfilePath();
135550
- const tmpDir = join87(tmpdir12(), `hyperframes-docker-${Date.now()}`);
135551
- mkdirSync43(tmpDir, { recursive: true });
135826
+ const tmpDir = mkdtempSync11(join87(tmpdir12(), "hyperframes-docker-"));
135552
135827
  writeFileSync30(join87(tmpDir, "Dockerfile"), readFileSync53(dockerfilePath));
135553
135828
  const targetArch = platform10 === "linux/arm64" ? "arm64" : "amd64";
135554
135829
  try {
@@ -136098,6 +136373,7 @@ function trackRenderMetrics(job, elapsedMs, options, docker) {
136098
136373
  deParallelRouter: perf?.drawElement?.parallelRouter,
136099
136374
  dePreRouterWorkers: perf?.drawElement?.preRouterWorkers,
136100
136375
  deGateReason: perf?.drawElement?.gateReason,
136376
+ gpuRenderer: perf?.drawElement?.gpuRenderer,
136101
136377
  deWorkerEncode: perf?.drawElement?.workerEncode,
136102
136378
  deVerifyArmed: perf?.drawElement?.verifyArmed,
136103
136379
  deVerifyChecked: perf?.drawElement?.verifyChecked,
@@ -136185,6 +136461,7 @@ var init_render = __esm({
136185
136461
  init_commandResult();
136186
136462
  init_dist();
136187
136463
  init_plan2();
136464
+ init_projectConfig();
136188
136465
  init_present2();
136189
136466
  init_execute();
136190
136467
  init_producer();
@@ -136440,6 +136717,7 @@ var init_render = __esm({
136440
136717
  // Keep the transport adapter thin: each phase has one ownership boundary.
136441
136718
  async run({ args }) {
136442
136719
  const plan2 = createRenderPlan(args);
136720
+ seedProjectAuthoringSkill(plan2.project.dir, args.skill);
136443
136721
  await presentRenderPlan(plan2);
136444
136722
  await executeRenderPlan(plan2, {
136445
136723
  renderDocker,
@@ -138123,7 +138401,7 @@ __export(validate_exports, {
138123
138401
  resolveNavigationTimeoutMs: () => resolveNavigationTimeoutMs,
138124
138402
  shouldIgnoreRequestFailure: () => shouldIgnoreRequestFailure
138125
138403
  });
138126
- import { existsSync as existsSync80, mkdtempSync as mkdtempSync11, readFileSync as readFileSync56, rmSync as rmSync27 } from "fs";
138404
+ import { existsSync as existsSync80, mkdtempSync as mkdtempSync12, readFileSync as readFileSync56, rmSync as rmSync27 } from "fs";
138127
138405
  import { tmpdir as tmpdir13 } from "os";
138128
138406
  import { join as join90, dirname as dirname43 } from "path";
138129
138407
  import { fileURLToPath as fileURLToPath12 } from "url";
@@ -138290,7 +138568,7 @@ async function localizeRemoteAssets(html) {
138290
138568
  try {
138291
138569
  const { loadProducer: loadProducer2 } = await Promise.resolve().then(() => (init_producer(), producer_exports));
138292
138570
  const { localizeRemoteMediaSources: localizeRemoteMediaSources2, localizeRemoteImageSources: localizeRemoteImageSources2, localizeRemoteFontFaces: localizeRemoteFontFaces2 } = await loadProducer2();
138293
- dir = mkdtempSync11(join90(tmpdir13(), "hf-validate-assets-"));
138571
+ dir = mkdtempSync12(join90(tmpdir13(), "hf-validate-assets-"));
138294
138572
  const assetDir = dir;
138295
138573
  const media = await localizeRemoteMediaSources2(html, assetDir);
138296
138574
  const images = await localizeRemoteImageSources2(media.html, assetDir);
@@ -138601,7 +138879,7 @@ __export(checkBrowser_exports, {
138601
138879
  preResolveHostileMediaProxies: () => preResolveHostileMediaProxies,
138602
138880
  runBrowserCheck: () => runBrowserCheck
138603
138881
  });
138604
- import { mkdirSync as mkdirSync44, writeFileSync as writeFileSync31 } from "fs";
138882
+ import { mkdirSync as mkdirSync43, writeFileSync as writeFileSync31 } from "fs";
138605
138883
  import { join as join91, resolve as resolve56 } from "path";
138606
138884
  async function preResolveHostileMediaProxies(projectDir, html, autoProxyOverride) {
138607
138885
  if (!resolveAutoProxy(projectDir, autoProxyOverride)) return;
@@ -138701,7 +138979,7 @@ async function captureFindingCrops(project, options, requests) {
138701
138979
  const page = session.page;
138702
138980
  await waitForPreferredSeekTarget(page);
138703
138981
  const snapshotDir = join91(project.dir, "snapshots");
138704
- mkdirSync44(snapshotDir, { recursive: true });
138982
+ mkdirSync43(snapshotDir, { recursive: true });
138705
138983
  for (const request of requests) {
138706
138984
  await seekCompositionTimeline(page, request.time, AUDIT_SEEK_OPTIONS);
138707
138985
  const canvas = await page.evaluate(() => ({
@@ -139493,7 +139771,7 @@ var init_checkBrowser = __esm({
139493
139771
  });
139494
139772
 
139495
139773
  // src/utils/checkPipeline.ts
139496
- import { mkdirSync as mkdirSync45, writeFileSync as writeFileSync33 } from "fs";
139774
+ import { mkdirSync as mkdirSync44, writeFileSync as writeFileSync33 } from "fs";
139497
139775
  import { join as join93, relative as relative21 } from "path";
139498
139776
  function selectContrastTimes(grid) {
139499
139777
  if (grid.length <= 5) return [...grid];
@@ -139573,12 +139851,17 @@ function geometryIssueAnchor(candidate, time) {
139573
139851
  rect: candidate.rect
139574
139852
  };
139575
139853
  }
139854
+ function captionCenterInZone(rect, zone, canvas) {
139855
+ const cx = rect.left + rect.width / 2;
139856
+ const cy = rect.top + rect.height / 2;
139857
+ const inside = cx >= zone.x0 * canvas.width && cx <= zone.x1 * canvas.width && cy >= zone.y0 * canvas.height && cy <= zone.y1 * canvas.height;
139858
+ return { inside, cy };
139859
+ }
139576
139860
  function captionFinding(candidate, options, canvas, time) {
139577
139861
  const zone = options.captionZone;
139578
139862
  if (!zone || candidate.kind !== "text" || !candidateIsSized(candidate, canvas)) return null;
139579
- const cx = candidate.rect.left + candidate.rect.width / 2;
139580
- const cy = candidate.rect.top + candidate.rect.height / 2;
139581
- const inside = cx >= zone.x0 * canvas.width && cx <= zone.x1 * canvas.width && cy >= zone.y0 * canvas.height && cy <= zone.y1 * canvas.height;
139863
+ if ("data-layout-allow-caption-zone" in candidate.dataAttributes) return null;
139864
+ const { inside, cy } = captionCenterInZone(candidate.rect, zone, canvas);
139582
139865
  if (!inside) return null;
139583
139866
  const text2 = candidate.text.slice(0, 48);
139584
139867
  const pctFromBottom = Math.round((canvas.height - cy) / canvas.height * 100);
@@ -139590,7 +139873,7 @@ function captionFinding(candidate, options, canvas, time) {
139590
139873
  severity: zone.severity === "error" ? "error" : "warning",
139591
139874
  text: text2,
139592
139875
  message: `<${candidate.tag}> "${text2}" is centred in the reserved caption band (~${pctFromBottom}% up from the bottom).`,
139593
- fixHint: "Keep main content outside the configured caption band."
139876
+ fixHint: "Keep main content outside the configured caption band, or mark intentional lower-third copy with data-layout-allow-caption-zone."
139594
139877
  }
139595
139878
  };
139596
139879
  }
@@ -140435,7 +140718,7 @@ async function runBrowserCheck2(project, options, motion) {
140435
140718
  }
140436
140719
  async function writeSnapshot(projectDir, index, time, pngBase64) {
140437
140720
  const snapshotDir = join93(projectDir, "snapshots");
140438
- mkdirSync45(snapshotDir, { recursive: true });
140721
+ mkdirSync44(snapshotDir, { recursive: true });
140439
140722
  const filename = `frame-${String(index).padStart(2, "0")}-at-${time.toFixed(1)}s.png`;
140440
140723
  const path2 = join93(snapshotDir, filename);
140441
140724
  writeFileSync33(path2, Buffer.from(pngBase64, "base64"));
@@ -141132,7 +141415,7 @@ __export(beats_exports, {
141132
141415
  default: () => beats_default,
141133
141416
  examples: () => examples13
141134
141417
  });
141135
- import { existsSync as existsSync83, readFileSync as readFileSync58, mkdirSync as mkdirSync46, writeFileSync as writeFileSync34 } from "fs";
141418
+ import { existsSync as existsSync83, readFileSync as readFileSync58, mkdirSync as mkdirSync45, writeFileSync as writeFileSync34 } from "fs";
141136
141419
  import { resolve as resolve57, join as join95, dirname as dirname45 } from "path";
141137
141420
  function fail(message) {
141138
141421
  console.error(c.error(message));
@@ -141205,7 +141488,7 @@ var init_beats2 = __esm({
141205
141488
  fail(`No beats detected in ${rel} \u2014 nothing written. (Track may be silent/ambient.)`);
141206
141489
  }
141207
141490
  const outPath = join95(project.dir, "beats", `${rel}.json`);
141208
- mkdirSync46(dirname45(outPath), { recursive: true });
141491
+ mkdirSync45(dirname45(outPath), { recursive: true });
141209
141492
  writeFileSync34(outPath, serializeBeats(result.beatTimes, result.beatStrengths, rel));
141210
141493
  report(`beats/${rel}.json`, result, Boolean(args.json));
141211
141494
  }
@@ -143054,10 +143337,10 @@ __export(motionShot_exports, {
143054
143337
  captureMotionPathShot: () => captureMotionPathShot,
143055
143338
  ensureShotOutputDir: () => ensureShotOutputDir
143056
143339
  });
143057
- import { mkdirSync as mkdirSync47, writeFileSync as writeFileSync35 } from "fs";
143340
+ import { mkdirSync as mkdirSync46, writeFileSync as writeFileSync35 } from "fs";
143058
143341
  import { dirname as dirname46 } from "path";
143059
143342
  function ensureShotOutputDir(outPath) {
143060
- mkdirSync47(dirname46(outPath), { recursive: true });
143343
+ mkdirSync46(dirname46(outPath), { recursive: true });
143061
143344
  }
143062
143345
  function applyOrbitCamera(selectors, cam) {
143063
143346
  const first = document.querySelector(selectors[0] ?? "");
@@ -145130,7 +145413,7 @@ var init_remove_background = __esm({
145130
145413
 
145131
145414
  // src/whisper/parakeet.ts
145132
145415
  import { execFileSync as execFileSync12 } from "child_process";
145133
- import { existsSync as existsSync88, mkdtempSync as mkdtempSync12, readFileSync as readFileSync63, rmSync as rmSync28, writeFileSync as writeFileSync36 } from "fs";
145416
+ import { existsSync as existsSync88, mkdtempSync as mkdtempSync13, readFileSync as readFileSync63, rmSync as rmSync28, writeFileSync as writeFileSync36 } from "fs";
145134
145417
  import { homedir as homedir17, tmpdir as tmpdir14 } from "os";
145135
145418
  import { basename as basename19, extname as extname17, join as join99 } from "path";
145136
145419
  function isRunnable(bin) {
@@ -145200,7 +145483,7 @@ function transcribeWithParakeet(inputPath, dir, options) {
145200
145483
  options?.onProgress?.(
145201
145484
  cached2 ? "Transcribing with Parakeet..." : "Downloading Parakeet model (first run, ~600MB)..."
145202
145485
  );
145203
- const workDir = mkdtempSync12(join99(tmpdir14(), "hyperframes-parakeet-"));
145486
+ const workDir = mkdtempSync13(join99(tmpdir14(), "hyperframes-parakeet-"));
145204
145487
  try {
145205
145488
  const argv2 = [inputPath, "--model", model, "--output-format", "json", "--output-dir", workDir];
145206
145489
  if (options?.language) argv2.push("--language", options.language);
@@ -145507,7 +145790,7 @@ var init_transcribe2 = __esm({
145507
145790
  });
145508
145791
 
145509
145792
  // src/tts/manager.ts
145510
- import { existsSync as existsSync90, mkdirSync as mkdirSync48 } from "fs";
145793
+ import { existsSync as existsSync90, mkdirSync as mkdirSync47 } from "fs";
145511
145794
  import { homedir as homedir18 } from "os";
145512
145795
  import { join as join101 } from "path";
145513
145796
  function inferLangFromVoiceId(voiceId) {
@@ -145526,7 +145809,7 @@ async function ensureModel3(model = DEFAULT_MODEL4, options) {
145526
145809
  `Unknown TTS model: ${model}. Available: ${Object.keys(MODEL_URLS2).join(", ")}`
145527
145810
  );
145528
145811
  }
145529
- mkdirSync48(MODELS_DIR3, { recursive: true });
145812
+ mkdirSync47(MODELS_DIR3, { recursive: true });
145530
145813
  options?.onProgress?.(`Downloading TTS model ${model} (~311 MB)...`);
145531
145814
  await downloadFile(url, modelPath2);
145532
145815
  if (!existsSync90(modelPath2)) {
@@ -145537,7 +145820,7 @@ async function ensureModel3(model = DEFAULT_MODEL4, options) {
145537
145820
  async function ensureVoices(options) {
145538
145821
  const voicesPath = join101(VOICES_DIR, "voices-v1.0.bin");
145539
145822
  if (existsSync90(voicesPath)) return voicesPath;
145540
- mkdirSync48(VOICES_DIR, { recursive: true });
145823
+ mkdirSync47(VOICES_DIR, { recursive: true });
145541
145824
  options?.onProgress?.("Downloading voice data (~27 MB)...");
145542
145825
  await downloadFile(VOICES_URL, voicesPath);
145543
145826
  if (!existsSync90(voicesPath)) {
@@ -145681,12 +145964,12 @@ __export(synthesize_exports, {
145681
145964
  synthesize: () => synthesize
145682
145965
  });
145683
145966
  import { execFileSync as execFileSync14 } from "child_process";
145684
- import { existsSync as existsSync91, writeFileSync as writeFileSync38, mkdirSync as mkdirSync49, readdirSync as readdirSync30, unlinkSync as unlinkSync7 } from "fs";
145967
+ import { existsSync as existsSync91, writeFileSync as writeFileSync38, mkdirSync as mkdirSync48, readdirSync as readdirSync30, unlinkSync as unlinkSync7 } from "fs";
145685
145968
  import { join as join103, dirname as dirname50, basename as basename20 } from "path";
145686
145969
  import { homedir as homedir19 } from "os";
145687
145970
  function ensureSynthScript() {
145688
145971
  if (!existsSync91(SCRIPT_PATH)) {
145689
- mkdirSync49(SCRIPT_DIR, { recursive: true });
145972
+ mkdirSync48(SCRIPT_DIR, { recursive: true });
145690
145973
  writeFileSync38(SCRIPT_PATH, SYNTH_SCRIPT);
145691
145974
  const currentName = basename20(SCRIPT_PATH);
145692
145975
  try {
@@ -145727,7 +146010,7 @@ async function synthesize(text2, outputPath, options) {
145727
146010
  ensureVoices({ onProgress: options?.onProgress })
145728
146011
  ]);
145729
146012
  const scriptPath = ensureSynthScript();
145730
- mkdirSync49(dirname50(outputPath), { recursive: true });
146013
+ mkdirSync48(dirname50(outputPath), { recursive: true });
145731
146014
  options?.onProgress?.(`Generating speech with voice ${voice} (${lang})...`);
145732
146015
  try {
145733
146016
  const espeakLang = ESPEAK_LANG_OVERRIDES[lang] ?? lang;
@@ -147070,42 +147353,67 @@ __export(telemetry_exports, {
147070
147353
  default: () => telemetry_default,
147071
147354
  examples: () => examples27
147072
147355
  });
147073
- function runEnable() {
147074
- const config = readConfig();
147075
- config.telemetryEnabled = true;
147076
- writeConfig(config);
147077
- console.log(`
147078
- ${c.success("\u2713")} Telemetry ${c.success("enabled")}
147079
- `);
147356
+ function describeOverride(source) {
147357
+ switch (source) {
147358
+ case "HYPERFRAMES_NO_TELEMETRY":
147359
+ case "DO_NOT_TRACK":
147360
+ return `${source} is set`;
147361
+ case "dev_mode":
147362
+ return "this is a development build";
147363
+ case "telemetry_disabled_build":
147364
+ return "this build has no telemetry key";
147365
+ }
147080
147366
  }
147081
- function runDisable() {
147082
- const config = readConfig();
147083
- config.telemetryEnabled = false;
147084
- writeConfig(config);
147367
+ function setTelemetryEnabled(enabled) {
147368
+ const config = readConfigFresh();
147369
+ config.telemetryEnabled = enabled;
147370
+ const result = writeConfigWithResult(config);
147371
+ if (!result.ok) {
147372
+ console.error(
147373
+ `
147374
+ ${c.error("\u2717")} Could not persist telemetry preference to ${c.accent(CONFIG_PATH)}
147375
+ ${c.dim("Reason:")} ${result.error}
147376
+ `
147377
+ );
147378
+ failCommand();
147379
+ }
147380
+ const effective = effectiveTelemetryStatus(enabled);
147381
+ const preference = enabled ? c.success("enabled") : c.bold("disabled");
147382
+ const noun = enabled && !effective.enabled ? "Telemetry preference" : "Telemetry";
147085
147383
  console.log(`
147086
- ${c.success("\u2713")} Telemetry ${c.bold("disabled")}
147087
- `);
147384
+ ${c.success("\u2713")} ${noun} ${preference}`);
147385
+ if (effective.source !== "config") {
147386
+ console.log(
147387
+ ` ${c.dim("Note:")} Telemetry remains disabled because ${describeOverride(effective.source)}.`
147388
+ );
147389
+ }
147390
+ console.log();
147088
147391
  }
147089
147392
  function runStatus() {
147090
- const config = readConfig();
147091
- const status = config.telemetryEnabled ? c.success("enabled") : c.dim("disabled");
147393
+ const config = readConfigFresh();
147394
+ const effective = effectiveTelemetryStatus(config.telemetryEnabled);
147395
+ const status = effective.enabled ? c.success("enabled") : c.dim("disabled");
147092
147396
  console.log();
147093
147397
  console.log(` ${c.dim("Status:")} ${status}`);
147398
+ console.log(` ${c.dim("Source:")} ${effective.source}`);
147094
147399
  console.log(` ${c.dim("Config:")} ${c.accent(CONFIG_PATH)}`);
147095
- console.log(` ${c.dim("Commands:")} ${c.bold(String(config.commandCount))}`);
147400
+ console.log(` ${c.dim("Tracked commands:")} ${c.bold(String(config.commandCount))}`);
147096
147401
  console.log();
147097
147402
  console.log(` ${c.dim("Disable:")} ${c.accent("hyperframes telemetry disable")}`);
147098
- console.log(` ${c.dim("Env var:")} ${c.accent("HYPERFRAMES_NO_TELEMETRY=1")}`);
147403
+ console.log(
147404
+ ` ${c.dim("Env var:")} ${c.accent("HYPERFRAMES_NO_TELEMETRY=1")} ${c.dim("or")} ${c.accent("DO_NOT_TRACK=1")}`
147405
+ );
147099
147406
  console.log();
147100
147407
  }
147101
147408
  var examples27, telemetry_default;
147102
147409
  var init_telemetry = __esm({
147103
147410
  "src/commands/telemetry.ts"() {
147104
147411
  "use strict";
147105
- init_commandResult();
147106
147412
  init_dist();
147107
- init_colors();
147108
147413
  init_config();
147414
+ init_policy();
147415
+ init_colors();
147416
+ init_commandResult();
147109
147417
  examples27 = [
147110
147418
  ["Check current telemetry status", "hyperframes telemetry status"],
147111
147419
  ["Disable telemetry", "hyperframes telemetry disable"],
@@ -147144,15 +147452,15 @@ ${c.bold("WHAT WE DON'T COLLECT:")}
147144
147452
  ${c.dim("\u2022")} IP addresses (discarded by our analytics provider)
147145
147453
  ${c.dim("\u2022")} Any personally identifiable information
147146
147454
 
147147
- ${c.dim("You can also set")} ${c.accent("HYPERFRAMES_NO_TELEMETRY=1")} ${c.dim("to disable.")}
147455
+ ${c.dim("You can also set")} ${c.accent("HYPERFRAMES_NO_TELEMETRY=1")} ${c.dim("or")} ${c.accent("DO_NOT_TRACK=1")} ${c.dim("to disable.")}
147148
147456
  `);
147149
147457
  return;
147150
147458
  }
147151
147459
  switch (subcommand) {
147152
147460
  case "enable":
147153
- return runEnable();
147461
+ return setTelemetryEnabled(true);
147154
147462
  case "disable":
147155
- return runDisable();
147463
+ return setTelemetryEnabled(false);
147156
147464
  case "status":
147157
147465
  return runStatus();
147158
147466
  default:
@@ -187169,7 +187477,7 @@ __export(snapshot_exports, {
187169
187477
  resolveSnapshotVideoFrameTime: () => resolveSnapshotVideoFrameTime,
187170
187478
  tailFrameTime: () => tailFrameTime
187171
187479
  });
187172
- import { existsSync as existsSync98, mkdtempSync as mkdtempSync13, readFileSync as readFileSync68, mkdirSync as mkdirSync50, rmSync as rmSync29, writeFileSync as writeFileSync41 } from "fs";
187480
+ import { existsSync as existsSync98, mkdtempSync as mkdtempSync14, readFileSync as readFileSync68, mkdirSync as mkdirSync49, rmSync as rmSync29, writeFileSync as writeFileSync41 } from "fs";
187173
187481
  import { tmpdir as tmpdir15 } from "os";
187174
187482
  import { resolve as resolve67, join as join106, relative as relative24, isAbsolute as isAbsolute15, basename as basename25 } from "path";
187175
187483
  function orbitStageSource() {
@@ -187214,7 +187522,7 @@ function requireSnapshotFfmpeg(ffmpegPath) {
187214
187522
  );
187215
187523
  }
187216
187524
  async function extractVideoFrameToBuffer(videoPath, timeSeconds, useVp9AlphaDecoder = false) {
187217
- const tmp = mkdtempSync13(join106(tmpdir15(), "hf-snapshot-frame-"));
187525
+ const tmp = mkdtempSync14(join106(tmpdir15(), "hf-snapshot-frame-"));
187218
187526
  const outPath = join106(tmp, "frame.png");
187219
187527
  try {
187220
187528
  const ffmpegPath = requireSnapshotFfmpeg(findFFmpeg());
@@ -187328,7 +187636,7 @@ async function captureSnapshots(projectDir, opts) {
187328
187636
  }
187329
187637
  const cameraExpr = opts.angle && (opts.angle.yaw !== 0 || opts.angle.pitch !== 0) ? `(${orbitStageSource()})(${JSON.stringify(opts.angle)})` : null;
187330
187638
  const snapshotDir = opts.outputDir ?? join106(projectDir, "snapshots");
187331
- mkdirSync50(snapshotDir, { recursive: true });
187639
+ mkdirSync49(snapshotDir, { recursive: true });
187332
187640
  try {
187333
187641
  const { readdirSync: readdirSync38 } = await import("fs");
187334
187642
  for (const file of readdirSync38(snapshotDir)) {
@@ -188676,8 +188984,8 @@ __export(grade_compare_exports, {
188676
188984
  import {
188677
188985
  copyFileSync as copyFileSync10,
188678
188986
  existsSync as existsSync100,
188679
- mkdirSync as mkdirSync51,
188680
- mkdtempSync as mkdtempSync14,
188987
+ mkdirSync as mkdirSync50,
188988
+ mkdtempSync as mkdtempSync15,
188681
188989
  readFileSync as readFileSync70,
188682
188990
  rmSync as rmSync30,
188683
188991
  writeFileSync as writeFileSync44
@@ -188939,7 +189247,7 @@ function frameFileNameForPath(framePath) {
188939
189247
  return "frame.png";
188940
189248
  }
188941
189249
  async function prepareGradeCompareTempProject(opts) {
188942
- const tempDir = mkdtempSync14(join107(tmpdir16(), "hf-grade-compare-"));
189250
+ const tempDir = mkdtempSync15(join107(tmpdir16(), "hf-grade-compare-"));
188943
189251
  try {
188944
189252
  const frameFileName2 = opts.frameFileName ?? frameFileNameForPath(opts.framePath);
188945
189253
  writeFileSync44(join107(tempDir, frameFileName2), opts.frameBuffer);
@@ -188986,7 +189294,7 @@ function isVideoPath2(filePath) {
188986
189294
  return [".mp4", ".mov", ".m4v", ".webm", ".mkv", ".avi", ".mpeg", ".mpg", ".ogv"].includes(ext);
188987
189295
  }
188988
189296
  async function extractVideoFrameToBuffer2(videoPath) {
188989
- const tmp = mkdtempSync14(join107(tmpdir16(), "hf-grade-compare-frame-"));
189297
+ const tmp = mkdtempSync15(join107(tmpdir16(), "hf-grade-compare-frame-"));
188990
189298
  const outPath = join107(tmp, "frame.png");
188991
189299
  try {
188992
189300
  const ffmpegPath = findFFmpeg();
@@ -189183,7 +189491,7 @@ var init_grade_compare = __esm({
189183
189491
  prepared.tempDir,
189184
189492
  parsed.timeoutMs
189185
189493
  );
189186
- mkdirSync51(dirname54(parsed.outPath), { recursive: true });
189494
+ mkdirSync50(dirname54(parsed.outPath), { recursive: true });
189187
189495
  copyFileSync10(tempSheet, parsed.outPath);
189188
189496
  trackCompareSheet({
189189
189497
  command: "grade-compare",
@@ -189228,7 +189536,7 @@ __export(compare_exports, {
189228
189536
  parseCompareArgs: () => parseCompareArgs,
189229
189537
  prepareCompareVariantProjects: () => prepareCompareVariantProjects
189230
189538
  });
189231
- import { cpSync as cpSync6, existsSync as existsSync101, mkdirSync as mkdirSync53, mkdtempSync as mkdtempSync15, renameSync as renameSync16, rmSync as rmSync31, statSync as statSync35 } from "fs";
189539
+ import { cpSync as cpSync6, existsSync as existsSync101, mkdirSync as mkdirSync51, mkdtempSync as mkdtempSync16, renameSync as renameSync16, rmSync as rmSync31, statSync as statSync35 } from "fs";
189232
189540
  import { tmpdir as tmpdir17 } from "os";
189233
189541
  import { basename as basename28, dirname as dirname55, extname as extname24, join as join108 } from "path";
189234
189542
  function defaultLabelForPath(input2) {
@@ -189329,7 +189637,7 @@ function inputError(variant) {
189329
189637
  );
189330
189638
  }
189331
189639
  function stageHtmlVariant(variant) {
189332
- const stagedDir = mkdtempSync15(join108(tmpdir17(), "hf-compare-variant-"));
189640
+ const stagedDir = mkdtempSync16(join108(tmpdir17(), "hf-compare-variant-"));
189333
189641
  try {
189334
189642
  cpSync6(dirname55(variant.inputPath), stagedDir, {
189335
189643
  recursive: true,
@@ -189426,7 +189734,7 @@ async function renderCompareSheet(parsed) {
189426
189734
  const capResult = capCompareVariants(parsed.variants);
189427
189735
  const variants = capResult.variants;
189428
189736
  const prepared = prepareCompareVariantProjects(variants);
189429
- const frameDir = mkdtempSync15(join108(tmpdir17(), "hf-compare-frames-"));
189737
+ const frameDir = mkdtempSync16(join108(tmpdir17(), "hf-compare-frames-"));
189430
189738
  const framePaths = [];
189431
189739
  try {
189432
189740
  let renderReadyTimedOut = false;
@@ -189441,7 +189749,7 @@ async function renderCompareSheet(parsed) {
189441
189749
  framePaths.push(rendered.framePath);
189442
189750
  renderReadyTimedOut = renderReadyTimedOut || rendered.renderReadyTimedOut;
189443
189751
  }
189444
- mkdirSync53(dirname55(parsed.outPath), { recursive: true });
189752
+ mkdirSync51(dirname55(parsed.outPath), { recursive: true });
189445
189753
  await createContactSheet(framePaths, parsed.outPath, {
189446
189754
  cols: parsed.cols ?? defaultCompareCols(framePaths.length),
189447
189755
  maxImages: framePaths.length,
@@ -189560,7 +189868,7 @@ ${c.error("\u2717")} Compare failed: ${message}`);
189560
189868
  });
189561
189869
 
189562
189870
  // src/capture/assetDownloader.ts
189563
- import { writeFileSync as writeFileSync45, mkdirSync as mkdirSync54 } from "fs";
189871
+ import { writeFileSync as writeFileSync45, mkdirSync as mkdirSync53 } from "fs";
189564
189872
  import { join as join109, extname as extname25 } from "path";
189565
189873
  import { createHash as createHash18 } from "crypto";
189566
189874
  function svgContentHashSlug(svgSource, isLogo) {
@@ -189569,10 +189877,10 @@ function svgContentHashSlug(svgSource, isLogo) {
189569
189877
  }
189570
189878
  async function downloadAssets(tokens, outputDir, catalogedAssets, faviconLinks) {
189571
189879
  const assetsDir = join109(outputDir, "assets");
189572
- mkdirSync54(assetsDir, { recursive: true });
189880
+ mkdirSync53(assetsDir, { recursive: true });
189573
189881
  const assets = [];
189574
189882
  const downloadedUrls = /* @__PURE__ */ new Set();
189575
- mkdirSync54(join109(outputDir, "assets", "svgs"), { recursive: true });
189883
+ mkdirSync53(join109(outputDir, "assets", "svgs"), { recursive: true });
189576
189884
  const usedSvgNames = /* @__PURE__ */ new Set();
189577
189885
  for (let i2 = 0; i2 < tokens.svgs.length && i2 < 30; i2++) {
189578
189886
  const svg = tokens.svgs[i2];
@@ -189703,7 +190011,7 @@ function normalizeUrl(u) {
189703
190011
  }
189704
190012
  async function downloadAndRewriteFonts(css, outputDir) {
189705
190013
  const assetsDir = join109(outputDir, "assets", "fonts");
189706
- mkdirSync54(assetsDir, { recursive: true });
190014
+ mkdirSync53(assetsDir, { recursive: true });
189707
190015
  const fontUrlRegex = /url\(['"]?(https?:\/\/[^'")\s]+\.(?:woff2?|ttf|otf)[^'")\s]*?)['"]?\)/g;
189708
190016
  const fontUrls = /* @__PURE__ */ new Set();
189709
190017
  let match;
@@ -189896,7 +190204,7 @@ __export(video_exports, {
189896
190204
  runVideoMode: () => runVideoMode,
189897
190205
  safeFilename: () => safeFilename
189898
190206
  });
189899
- import { createWriteStream as createWriteStream4, existsSync as existsSync103, mkdirSync as mkdirSync55, readFileSync as readFileSync71, unlinkSync as unlinkSync9 } from "fs";
190207
+ import { createWriteStream as createWriteStream4, existsSync as existsSync103, mkdirSync as mkdirSync54, readFileSync as readFileSync71, unlinkSync as unlinkSync9 } from "fs";
189900
190208
  import { resolve as resolve71, join as join110, basename as basename29 } from "path";
189901
190209
  async function streamToFile(url, destPath) {
189902
190210
  const r2 = await safeFetch(url, {
@@ -190072,7 +190380,7 @@ async function runVideoMode(args) {
190072
190380
  return;
190073
190381
  }
190074
190382
  const outDir = isW2hLayout ? join110(projectDir, "capture", "assets", "videos") : join110(projectDir, "assets", "videos");
190075
- mkdirSync55(outDir, { recursive: true });
190383
+ mkdirSync54(outDir, { recursive: true });
190076
190384
  const fname = safeFilename(entry.filename || basename29(entry.url));
190077
190385
  const outPath = join110(outDir, fname);
190078
190386
  const relPath = isW2hLayout ? `capture/assets/videos/${fname}` : `assets/videos/${fname}`;
@@ -191641,7 +191949,7 @@ var init_animationCataloger = __esm({
191641
191949
  });
191642
191950
 
191643
191951
  // src/capture/mediaCapture.ts
191644
- import { mkdirSync as mkdirSync56, writeFileSync as writeFileSync47, readdirSync as readdirSync34, readFileSync as readFileSync74, statSync as statSync36 } from "fs";
191952
+ import { mkdirSync as mkdirSync55, writeFileSync as writeFileSync47, readdirSync as readdirSync34, readFileSync as readFileSync74, statSync as statSync36 } from "fs";
191645
191953
  import { join as join113, extname as extname26 } from "path";
191646
191954
  async function saveLottieAnimations(discoveredLotties, lottieDir) {
191647
191955
  let savedCount = 0;
@@ -191703,7 +192011,7 @@ async function saveLottieAnimations(discoveredLotties, lottieDir) {
191703
192011
  async function renderLottiePreviews(chromeBrowser, lottieDir, outputDir) {
191704
192012
  const manifest = [];
191705
192013
  const previewDir = join113(lottieDir, "previews");
191706
- mkdirSync56(previewDir, { recursive: true });
192014
+ mkdirSync55(previewDir, { recursive: true });
191707
192015
  for (const file of readdirSync34(lottieDir)) {
191708
192016
  if (!file.endsWith(".json")) continue;
191709
192017
  try {
@@ -191869,9 +192177,9 @@ async function captureVideoManifest(page, outputDir, progress, opts) {
191869
192177
  const merged = [...byKey.values()];
191870
192178
  if (merged.length === 0) return;
191871
192179
  const videoManifestDir = join113(outputDir, "assets", "videos");
191872
- mkdirSync56(videoManifestDir, { recursive: true });
192180
+ mkdirSync55(videoManifestDir, { recursive: true });
191873
192181
  const previewDir = join113(videoManifestDir, "previews");
191874
- mkdirSync56(previewDir, { recursive: true });
192182
+ mkdirSync55(previewDir, { recursive: true });
191875
192183
  const videoManifest = [];
191876
192184
  const dlStart = Date.now();
191877
192185
  for (let vi = 0; vi < merged.length && vi < 20; vi++) {
@@ -192577,11 +192885,11 @@ var screenshotCapture_exports = {};
192577
192885
  __export(screenshotCapture_exports, {
192578
192886
  captureScrollScreenshots: () => captureScrollScreenshots
192579
192887
  });
192580
- import { writeFileSync as writeFileSync50, mkdirSync as mkdirSync57 } from "fs";
192888
+ import { writeFileSync as writeFileSync50, mkdirSync as mkdirSync56 } from "fs";
192581
192889
  import { join as join117 } from "path";
192582
192890
  async function captureScrollScreenshots(page, outputDir) {
192583
192891
  const screenshotsDir = join117(outputDir, "screenshots");
192584
- mkdirSync57(screenshotsDir, { recursive: true });
192892
+ mkdirSync56(screenshotsDir, { recursive: true });
192585
192893
  const MAX_SCREENSHOTS = 20;
192586
192894
  const filePaths = [];
192587
192895
  try {
@@ -193021,7 +193329,7 @@ var capture_exports = {};
193021
193329
  __export(capture_exports, {
193022
193330
  captureWebsite: () => captureWebsite
193023
193331
  });
193024
- import { mkdirSync as mkdirSync58, writeFileSync as writeFileSync51, existsSync as existsSync108 } from "fs";
193332
+ import { mkdirSync as mkdirSync57, writeFileSync as writeFileSync51, existsSync as existsSync108 } from "fs";
193025
193333
  import { join as join118 } from "path";
193026
193334
  async function captureWebsite(opts, onProgress) {
193027
193335
  const {
@@ -193039,9 +193347,9 @@ async function captureWebsite(opts, onProgress) {
193039
193347
  onProgress?.(stage, detail);
193040
193348
  };
193041
193349
  loadEnvFile(outputDir);
193042
- mkdirSync58(join118(outputDir, "extracted"), { recursive: true });
193043
- mkdirSync58(join118(outputDir, "screenshots"), { recursive: true });
193044
- mkdirSync58(join118(outputDir, "assets"), { recursive: true });
193350
+ mkdirSync57(join118(outputDir, "extracted"), { recursive: true });
193351
+ mkdirSync57(join118(outputDir, "screenshots"), { recursive: true });
193352
+ mkdirSync57(join118(outputDir, "assets"), { recursive: true });
193045
193353
  progress("browser", "Launching headless Chrome...");
193046
193354
  const { ensureBrowser: ensureBrowser2 } = await Promise.resolve().then(() => (init_manager2(), manager_exports2));
193047
193355
  const browser = await ensureBrowser2();
@@ -193202,7 +193510,7 @@ async function captureWebsite(opts, onProgress) {
193202
193510
  }
193203
193511
  if (discoveredLotties.length > 0) {
193204
193512
  const lottieDir = join118(outputDir, "assets", "lottie");
193205
- mkdirSync58(lottieDir, { recursive: true });
193513
+ mkdirSync57(lottieDir, { recursive: true });
193206
193514
  const savedCount = await saveLottieAnimations(discoveredLotties, lottieDir);
193207
193515
  if (savedCount > 0) {
193208
193516
  await renderLottiePreviews(chromeBrowser, lottieDir, outputDir);
@@ -193706,8 +194014,8 @@ var init_capture2 = __esm({
193706
194014
  } catch (err) {
193707
194015
  const errMsg = normalizeErrorMessage(err);
193708
194016
  try {
193709
- const { mkdirSync: mkdirSync69, writeFileSync: writeFileSync61 } = await import("fs");
193710
- mkdirSync69(outputDir, { recursive: true });
194017
+ const { mkdirSync: mkdirSync68, writeFileSync: writeFileSync61 } = await import("fs");
194018
+ mkdirSync68(outputDir, { recursive: true });
193711
194019
  const isTimeout = /timeout|timed out/i.test(errMsg);
193712
194020
  const reason = isTimeout ? "Page navigation timed out \u2014 the site may be blocking headless browsers or requires authentication." : `Capture failed: ${errMsg}`;
193713
194021
  writeFileSync61(
@@ -193774,14 +194082,14 @@ __export(state_exports, {
193774
194082
  stateFilePath: () => stateFilePath,
193775
194083
  writeStackOutputs: () => writeStackOutputs
193776
194084
  });
193777
- import { existsSync as existsSync109, mkdirSync as mkdirSync59, readdirSync as readdirSync37, readFileSync as readFileSync77, rmSync as rmSync32, writeFileSync as writeFileSync53 } from "fs";
194085
+ import { existsSync as existsSync109, mkdirSync as mkdirSync58, readdirSync as readdirSync37, readFileSync as readFileSync77, rmSync as rmSync32, writeFileSync as writeFileSync53 } from "fs";
193778
194086
  import { dirname as dirname56, join as join119 } from "path";
193779
194087
  function stateFilePath(stackName = DEFAULT_STACK_NAME, cwd = process.cwd()) {
193780
194088
  return join119(cwd, STATE_DIR_NAME, `${STATE_FILE_PREFIX}${stackName}.json`);
193781
194089
  }
193782
194090
  function writeStackOutputs(outputs, cwd = process.cwd()) {
193783
194091
  const path2 = stateFilePath(outputs.stackName, cwd);
193784
- mkdirSync59(dirname56(path2), { recursive: true });
194092
+ mkdirSync58(dirname56(path2), { recursive: true });
193785
194093
  writeFileSync53(path2, JSON.stringify(outputs, null, 2) + "\n");
193786
194094
  return path2;
193787
194095
  }
@@ -195376,7 +195684,7 @@ __export(cloudrun_exports, {
195376
195684
  missingCloudRunAdapterMessage: () => missingCloudRunAdapterMessage
195377
195685
  });
195378
195686
  import { spawnSync as spawnSync6 } from "child_process";
195379
- import { existsSync as existsSync116, mkdirSync as mkdirSync60, readFileSync as readFileSync81, writeFileSync as writeFileSync54 } from "fs";
195687
+ import { existsSync as existsSync116, mkdirSync as mkdirSync59, readFileSync as readFileSync81, writeFileSync as writeFileSync54 } from "fs";
195380
195688
  import { homedir as homedir20 } from "os";
195381
195689
  import { join as join126, resolve as resolve76 } from "path";
195382
195690
  function loadCloudRunAdapter() {
@@ -195403,7 +195711,7 @@ function statePath() {
195403
195711
  return join126(stateDir(), "cloudrun-state.json");
195404
195712
  }
195405
195713
  function writeState(state) {
195406
- mkdirSync60(stateDir(), { recursive: true });
195714
+ mkdirSync59(stateDir(), { recursive: true });
195407
195715
  writeFileSync54(statePath(), JSON.stringify(state, null, 2));
195408
195716
  }
195409
195717
  function readState(args) {
@@ -195562,7 +195870,7 @@ function findRepoRoot(tfDir) {
195562
195870
  }
195563
195871
  function writeCloudBuildConfig(image) {
195564
195872
  const cfgPath = join126(stateDir(), "cloudrun-cloudbuild.yaml");
195565
- mkdirSync60(stateDir(), { recursive: true });
195873
+ mkdirSync59(stateDir(), { recursive: true });
195566
195874
  writeFileSync54(
195567
195875
  cfgPath,
195568
195876
  [
@@ -196215,7 +196523,7 @@ var init_poll = __esm({
196215
196523
  });
196216
196524
 
196217
196525
  // src/cloud/download.ts
196218
- import { createWriteStream as createWriteStream5, mkdirSync as mkdirSync61, unlinkSync as unlinkSync10 } from "fs";
196526
+ import { createWriteStream as createWriteStream5, mkdirSync as mkdirSync60, unlinkSync as unlinkSync10 } from "fs";
196219
196527
  import { dirname as dirname58 } from "path";
196220
196528
  async function downloadToFile(url, destPath, options = {}) {
196221
196529
  const fetchImpl = options.fetchImpl ?? fetch;
@@ -196226,7 +196534,7 @@ async function downloadToFile(url, destPath, options = {}) {
196226
196534
  if (!res.body) {
196227
196535
  throw new Error(`Failed to download ${url}: empty response body`);
196228
196536
  }
196229
- mkdirSync61(dirname58(destPath), { recursive: true });
196537
+ mkdirSync60(dirname58(destPath), { recursive: true });
196230
196538
  const totalHeader = res.headers.get("content-length");
196231
196539
  const total = totalHeader ? Number.parseInt(totalHeader, 10) : void 0;
196232
196540
  const totalOpt = total !== void 0 && Number.isFinite(total) ? total : void 0;
@@ -198783,7 +199091,7 @@ var init_parseFigmaRef = __esm({
198783
199091
  });
198784
199092
 
198785
199093
  // ../core/dist/figma/freeze.js
198786
- import { copyFileSync as copyFileSync11, mkdirSync as mkdirSync63, rmSync as rmSync33, statSync as statSync38, writeFileSync as writeFileSync55 } from "fs";
199094
+ import { copyFileSync as copyFileSync11, mkdirSync as mkdirSync61, rmSync as rmSync33, statSync as statSync38, writeFileSync as writeFileSync55 } from "fs";
198787
199095
  import { dirname as dirname59 } from "path";
198788
199096
  function exceedsFreezeCap(byteLength) {
198789
199097
  return byteLength > MAX_FREEZE_BYTES;
@@ -198793,7 +199101,7 @@ function freezeBytes(bytes, destPath) {
198793
199101
  throw new Error("freeze failed: empty bytes");
198794
199102
  if (exceedsFreezeCap(bytes.length))
198795
199103
  throw new Error(`freeze failed: ${bytes.length} bytes exceeds ${MAX_FREEZE_BYTES} cap`);
198796
- mkdirSync63(dirname59(destPath), { recursive: true });
199104
+ mkdirSync61(dirname59(destPath), { recursive: true });
198797
199105
  try {
198798
199106
  writeFileSync55(destPath, bytes, { flag: "wx" });
198799
199107
  } catch (err) {
@@ -198837,7 +199145,7 @@ var init_jsonl = __esm({
198837
199145
  });
198838
199146
 
198839
199147
  // ../core/dist/figma/manifest.js
198840
- import { appendFileSync as appendFileSync2, existsSync as existsSync119, mkdirSync as mkdirSync64, readFileSync as readFileSync85, writeFileSync as writeFileSync56 } from "fs";
199148
+ import { appendFileSync as appendFileSync2, existsSync as existsSync119, mkdirSync as mkdirSync63, readFileSync as readFileSync85, writeFileSync as writeFileSync56 } from "fs";
198841
199149
  import { join as join127 } from "path";
198842
199150
  function mediaDir(projectDir) {
198843
199151
  return join127(projectDir, ".media");
@@ -198870,7 +199178,7 @@ function readManifest(projectDir) {
198870
199178
  return readJsonlValues(manifestPath(projectDir)).filter(isFigmaManifestRecord);
198871
199179
  }
198872
199180
  function appendRecord(projectDir, record) {
198873
- mkdirSync64(typeDirPath(projectDir, record.type), { recursive: true });
199181
+ mkdirSync63(typeDirPath(projectDir, record.type), { recursive: true });
198874
199182
  appendFileSync2(manifestPath(projectDir), JSON.stringify(record) + "\n");
198875
199183
  }
198876
199184
  function findAllByFigmaNode(projectDir, fileKey, nodeId) {
@@ -198932,7 +199240,7 @@ var init_manifest = __esm({
198932
199240
  });
198933
199241
 
198934
199242
  // ../core/dist/figma/mediaIndex.js
198935
- import { mkdirSync as mkdirSync65, writeFileSync as writeFileSync57 } from "fs";
199243
+ import { mkdirSync as mkdirSync64, writeFileSync as writeFileSync57 } from "fs";
198936
199244
  import { dirname as dirname60, join as join128 } from "path";
198937
199245
  function isRow(value) {
198938
199246
  return typeof value === "object" && value !== null;
@@ -198983,7 +199291,7 @@ function regenerateIndex(projectDir) {
198983
199291
  const records = readJsonlValues(manifestPath(projectDir)).filter(isRow);
198984
199292
  const content = generateIndexContent(records);
198985
199293
  const p2 = indexPath(projectDir);
198986
- mkdirSync65(dirname60(p2), { recursive: true });
199294
+ mkdirSync64(dirname60(p2), { recursive: true });
198987
199295
  writeFileSync57(p2, content);
198988
199296
  return content;
198989
199297
  }
@@ -199049,7 +199357,7 @@ var init_sanitizeSvg = __esm({
199049
199357
  });
199050
199358
 
199051
199359
  // ../core/dist/figma/bindings.js
199052
- import { appendFileSync as appendFileSync3, mkdirSync as mkdirSync66, writeFileSync as writeFileSync58 } from "fs";
199360
+ import { appendFileSync as appendFileSync3, mkdirSync as mkdirSync65, writeFileSync as writeFileSync58 } from "fs";
199053
199361
  import { join as join129 } from "path";
199054
199362
  function bindingsPath(projectDir) {
199055
199363
  return join129(mediaDir(projectDir), BINDINGS_FILE);
@@ -199069,7 +199377,7 @@ function readBindings(projectDir) {
199069
199377
  function upsertBindings(projectDir, records) {
199070
199378
  const incoming = new Set(records.map((r2) => r2.figmaId));
199071
199379
  const survivors = readLines(projectDir).filter((line2) => !(isBindingRecord(line2) && incoming.has(line2.figmaId)));
199072
- mkdirSync66(mediaDir(projectDir), { recursive: true });
199380
+ mkdirSync65(mediaDir(projectDir), { recursive: true });
199073
199381
  const lines = [...survivors, ...records].map((r2) => JSON.stringify(r2)).join("\n");
199074
199382
  writeFileSync58(bindingsPath(projectDir), lines.length > 0 ? lines + "\n" : "");
199075
199383
  }
@@ -199938,7 +200246,7 @@ __export(component_exports, {
199938
200246
  default: () => component_default,
199939
200247
  runComponentImport: () => runComponentImport
199940
200248
  });
199941
- import { existsSync as existsSync121, mkdirSync as mkdirSync67, writeFileSync as writeFileSync60 } from "fs";
200249
+ import { existsSync as existsSync121, mkdirSync as mkdirSync66, writeFileSync as writeFileSync60 } from "fs";
199942
200250
  import { join as join133, relative as relative29 } from "path";
199943
200251
  function escapeAttr2(value) {
199944
200252
  return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
@@ -199955,7 +200263,7 @@ async function runComponentImport(refInput, deps) {
199955
200263
  console.warn(
199956
200264
  `component dir compositions/components/${name} already exists \u2014 overwriting (rename the figma frame for a separate import)`
199957
200265
  );
199958
- mkdirSync67(componentDir, { recursive: true });
200266
+ mkdirSync66(componentDir, { recursive: true });
199959
200267
  const { html, frozenAssets, failedRasterize } = await rasterizeFallback(
199960
200268
  mapped,
199961
200269
  ref2.fileKey,
@@ -200156,7 +200464,7 @@ __export(autoUpdate_exports, {
200156
200464
  scheduleBackgroundInstall: () => scheduleBackgroundInstall
200157
200465
  });
200158
200466
  import { spawn as spawn16 } from "child_process";
200159
- import { appendFileSync as appendFileSync4, mkdirSync as mkdirSync68, openSync as openSync8 } from "fs";
200467
+ import { appendFileSync as appendFileSync4, mkdirSync as mkdirSync67, openSync as openSync8 } from "fs";
200160
200468
  import { homedir as homedir21 } from "os";
200161
200469
  import { join as join134 } from "path";
200162
200470
  import { compareVersions as compareVersions3 } from "compare-versions";
@@ -200173,14 +200481,14 @@ function majorOf(version2) {
200173
200481
  }
200174
200482
  function log(line2) {
200175
200483
  try {
200176
- mkdirSync68(CONFIG_DIR3, { recursive: true, mode: 448 });
200484
+ mkdirSync67(CONFIG_DIR3, { recursive: true, mode: 448 });
200177
200485
  appendFileSync4(LOG_FILE, `${(/* @__PURE__ */ new Date()).toISOString()} ${line2}
200178
200486
  `, { mode: 384 });
200179
200487
  } catch {
200180
200488
  }
200181
200489
  }
200182
200490
  function launchDetachedInstall(invocation, displayCommand, version2) {
200183
- mkdirSync68(CONFIG_DIR3, { recursive: true, mode: 448 });
200491
+ mkdirSync67(CONFIG_DIR3, { recursive: true, mode: 448 });
200184
200492
  const configFile = join134(CONFIG_DIR3, "config.json");
200185
200493
  const nodeScript = `
200186
200494
  const { execFile } = require("node:child_process");
@@ -200727,7 +201035,7 @@ if (!isHelp && command !== "telemetry" && command !== "events" && command !== "u
200727
201035
  if (mod.shouldTrack()) mod.incrementCommandCount();
200728
201036
  });
200729
201037
  }
200730
- if (!isHelp && !hasJsonFlag && command !== "upgrade" && command !== "events" && command !== "skills") {
201038
+ if (!isHelp && !hasJsonFlag && command !== "upgrade" && command !== "events" && command !== "telemetry" && command !== "skills") {
200731
201039
  Promise.resolve().then(() => (init_autoUpdate(), autoUpdate_exports)).then((mod) => mod.reportCompletedUpdate()).catch(() => {
200732
201040
  });
200733
201041
  Promise.resolve().then(() => (init_updateCheck(), updateCheck_exports)).then(async (mod) => {