hyperframes 0.7.75 → 0.7.77

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.75" : "0.0.0-dev";
53
+ VERSION = true ? "0.7.77" : "0.0.0-dev";
54
54
  }
55
55
  });
56
56
 
@@ -88675,57 +88675,15 @@ var init_system = __esm({
88675
88675
  }
88676
88676
  });
88677
88677
 
88678
- // src/telemetry/client.ts
88678
+ // src/telemetry/transport.ts
88679
88679
  import { spawn as spawn5 } from "child_process";
88680
88680
  import { randomUUID as randomUUID3 } from "crypto";
88681
- function shouldTrack() {
88682
- if (telemetryEnabled !== null) return telemetryEnabled;
88683
- if (process.env["HYPERFRAMES_NO_TELEMETRY"] === "1" || process.env["DO_NOT_TRACK"] === "1") {
88684
- telemetryEnabled = false;
88685
- return false;
88686
- }
88687
- if (isDevMode()) {
88688
- telemetryEnabled = false;
88689
- return false;
88690
- }
88691
- if (!POSTHOG_API_KEY.startsWith("phc_")) {
88692
- telemetryEnabled = false;
88693
- return false;
88694
- }
88695
- const config = readConfig();
88696
- telemetryEnabled = config.telemetryEnabled;
88697
- return telemetryEnabled;
88698
- }
88699
- function trackEvent(event, properties = {}, distinctId) {
88700
- if (!shouldTrack()) return;
88701
- const sys = getSystemMeta();
88681
+ function enqueue(event, properties, distinctId) {
88702
88682
  eventQueue.push({
88703
88683
  uuid: randomUUID3(),
88704
88684
  event,
88705
88685
  distinctId,
88706
- properties: {
88707
- ...properties,
88708
- cli_version: VERSION,
88709
- os: process.platform,
88710
- arch: process.arch,
88711
- node_version: process.version,
88712
- os_release: sys.os_release,
88713
- cpu_count: sys.cpu_count,
88714
- cpu_model: sys.cpu_model ?? void 0,
88715
- cpu_speed: sys.cpu_speed ?? void 0,
88716
- memory_total_mb: sys.memory_total_mb,
88717
- is_docker: sys.is_docker,
88718
- is_ci: sys.is_ci,
88719
- ci_name: sys.ci_name ?? void 0,
88720
- is_wsl: sys.is_wsl,
88721
- is_tty: sys.is_tty,
88722
- sandbox_runtime: sys.sandbox_runtime ?? void 0,
88723
- agent_runtime: sys.agent_runtime ?? void 0,
88724
- // New-agent discovery signals — populated only when agent_runtime is null.
88725
- agent_hint: sys.agent_hint ?? void 0,
88726
- term_program: sys.term_program ?? void 0,
88727
- agent_env_hints: sys.agent_env_hints ?? void 0
88728
- },
88686
+ properties,
88729
88687
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
88730
88688
  });
88731
88689
  }
@@ -88778,6 +88736,68 @@ function flushSync() {
88778
88736
  } catch {
88779
88737
  }
88780
88738
  }
88739
+ var POSTHOG_API_KEY, POSTHOG_HOST, FLUSH_TIMEOUT_MS, eventQueue;
88740
+ var init_transport = __esm({
88741
+ "src/telemetry/transport.ts"() {
88742
+ "use strict";
88743
+ init_config();
88744
+ POSTHOG_API_KEY = "phc_zjjbX0PnWxERXrMHhkEJWj9A9BhGVLRReICgsfTMmpx";
88745
+ POSTHOG_HOST = "https://us.i.posthog.com";
88746
+ FLUSH_TIMEOUT_MS = 5e3;
88747
+ eventQueue = [];
88748
+ }
88749
+ });
88750
+
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;
88756
+ return false;
88757
+ }
88758
+ if (isDevMode()) {
88759
+ telemetryEnabled = false;
88760
+ return false;
88761
+ }
88762
+ if (!POSTHOG_API_KEY.startsWith("phc_")) {
88763
+ telemetryEnabled = false;
88764
+ return false;
88765
+ }
88766
+ const config = readConfig();
88767
+ telemetryEnabled = config.telemetryEnabled;
88768
+ return telemetryEnabled;
88769
+ }
88770
+ function trackEvent(event, properties = {}, distinctId) {
88771
+ if (!shouldTrack()) return;
88772
+ const sys = getSystemMeta();
88773
+ enqueue(
88774
+ event,
88775
+ {
88776
+ ...properties,
88777
+ cli_version: VERSION,
88778
+ os: process.platform,
88779
+ arch: process.arch,
88780
+ node_version: process.version,
88781
+ os_release: sys.os_release,
88782
+ cpu_count: sys.cpu_count,
88783
+ cpu_model: sys.cpu_model ?? void 0,
88784
+ cpu_speed: sys.cpu_speed ?? void 0,
88785
+ memory_total_mb: sys.memory_total_mb,
88786
+ is_docker: sys.is_docker,
88787
+ is_ci: sys.is_ci,
88788
+ ci_name: sys.ci_name ?? void 0,
88789
+ is_wsl: sys.is_wsl,
88790
+ is_tty: sys.is_tty,
88791
+ sandbox_runtime: sys.sandbox_runtime ?? void 0,
88792
+ agent_runtime: sys.agent_runtime ?? void 0,
88793
+ // New-agent discovery signals — populated only when agent_runtime is null.
88794
+ agent_hint: sys.agent_hint ?? void 0,
88795
+ term_program: sys.term_program ?? void 0,
88796
+ agent_env_hints: sys.agent_env_hints ?? void 0
88797
+ },
88798
+ distinctId
88799
+ );
88800
+ }
88781
88801
  function showTelemetryNotice() {
88782
88802
  if (!shouldTrack()) return false;
88783
88803
  const config = readConfig();
@@ -88795,7 +88815,7 @@ function showTelemetryNotice() {
88795
88815
  diag.notice();
88796
88816
  return true;
88797
88817
  }
88798
- var POSTHOG_API_KEY, POSTHOG_HOST, FLUSH_TIMEOUT_MS, eventQueue, telemetryEnabled;
88818
+ var telemetryEnabled;
88799
88819
  var init_client = __esm({
88800
88820
  "src/telemetry/client.ts"() {
88801
88821
  "use strict";
@@ -88805,10 +88825,8 @@ var init_client = __esm({
88805
88825
  init_diagnostics2();
88806
88826
  init_env();
88807
88827
  init_system();
88808
- POSTHOG_API_KEY = "phc_zjjbX0PnWxERXrMHhkEJWj9A9BhGVLRReICgsfTMmpx";
88809
- POSTHOG_HOST = "https://us.i.posthog.com";
88810
- FLUSH_TIMEOUT_MS = 5e3;
88811
- eventQueue = [];
88828
+ init_transport();
88829
+ init_transport();
88812
88830
  telemetryEnabled = null;
88813
88831
  }
88814
88832
  });
@@ -89121,11 +89139,10 @@ function trackSkillsInstallSkipped(props) {
89121
89139
  trackEvent("cli skill install skipped", { reason: props.reason });
89122
89140
  }
89123
89141
  function trackRenderFeedback(props) {
89124
- trackEvent("survey sent", {
89125
- $survey_id: "render_satisfaction",
89126
- $survey_response: props.rating,
89142
+ trackEvent("cli_render_feedback", {
89143
+ rating: props.rating,
89127
89144
  rating_scale: FEEDBACK_RATING_SCALE,
89128
- ...props.comment ? { $survey_response_2: props.comment } : {},
89145
+ ...props.comment ? { comment: props.comment } : {},
89129
89146
  ...props.renderDurationMs !== void 0 ? { render_duration_ms: props.renderDurationMs } : {},
89130
89147
  ...props.doctorSummary ? { doctor_summary: props.doctorSummary } : {},
89131
89148
  ...props.feedbackId ? { feedback_id: props.feedbackId } : {},
@@ -92120,7 +92137,11 @@ function downloadFile(url, dest, options = {}) {
92120
92137
  const timeoutMs = options.timeoutMs ?? DEFAULT_DOWNLOAD_TIMEOUT_MS;
92121
92138
  return new Promise((resolve77, reject) => {
92122
92139
  const follow = (u) => {
92140
+ let activeResponse;
92141
+ let responsePipelineStarted = false;
92142
+ let requestError;
92123
92143
  const request = httpsGet(u, (res) => {
92144
+ activeResponse = res;
92124
92145
  if (res.statusCode === 301 || res.statusCode === 302) {
92125
92146
  const location = res.headers.location;
92126
92147
  if (location) {
@@ -92136,18 +92157,24 @@ function downloadFile(url, dest, options = {}) {
92136
92157
  return;
92137
92158
  }
92138
92159
  const file = createWriteStream2(tmp);
92160
+ responsePipelineStarted = true;
92139
92161
  pipeline2(res, file).then(() => {
92140
92162
  renameSync5(tmp, dest);
92141
92163
  resolve77();
92142
92164
  }).catch((err) => {
92143
92165
  removePartialFile(tmp);
92144
- reject(err);
92166
+ reject(requestError ?? err);
92145
92167
  });
92146
92168
  });
92147
92169
  request.setTimeout(timeoutMs, () => {
92148
92170
  request.destroy(new Error(`Download timed out after ${timeoutMs}ms`));
92149
92171
  });
92150
92172
  request.on("error", (err) => {
92173
+ if (responsePipelineStarted) {
92174
+ requestError = err;
92175
+ activeResponse?.destroy(err);
92176
+ return;
92177
+ }
92151
92178
  removePartialFile(tmp);
92152
92179
  reject(err);
92153
92180
  });
@@ -105263,6 +105290,14 @@ function bakeVisibilityOnDelete(document2, anim) {
105263
105290
  } catch {
105264
105291
  }
105265
105292
  }
105293
+ function resolveReplacementEaseEach(scriptText, request) {
105294
+ if (request.easeEach !== void 0) return request.easeEach;
105295
+ const original = parseGsapScriptAcorn2(scriptText).animations.find(
105296
+ (animation) => animation.id === request.animationId
105297
+ );
105298
+ if (!original?.arcPath?.enabled) return void 0;
105299
+ return original?.keyframes?.easeEach ?? original?.ease;
105300
+ }
105266
105301
  async function executeGsapMutation(body, block, respond2, writer) {
105267
105302
  if (writer === "recast") {
105268
105303
  return executeGsapMutationRecast(body, block, respond2);
@@ -105617,7 +105652,8 @@ function executeGsapMutationAcorn(body, block, respond2) {
105617
105652
  body.position,
105618
105653
  body.duration,
105619
105654
  body.keyframes,
105620
- body.ease
105655
+ body.ease,
105656
+ resolveReplacementEaseEach(block.scriptText, body)
105621
105657
  );
105622
105658
  return added.script;
105623
105659
  }
@@ -105947,7 +105983,8 @@ async function executeGsapMutationRecast(body, block, respond2) {
105947
105983
  body.position,
105948
105984
  body.duration,
105949
105985
  body.keyframes,
105950
- body.ease
105986
+ body.ease,
105987
+ resolveReplacementEaseEach(block.scriptText, body)
105951
105988
  );
105952
105989
  return added.script;
105953
105990
  }
@@ -125538,6 +125575,14 @@ function isExtractionCacheCompleteSentinelPath(path2) {
125538
125575
  const segments = path2.split("/");
125539
125576
  return segments.length === 3 && segments[0] === "video-frames" && segments[1] !== "" && segments[2] === EXTRACTION_CACHE_COMPLETE_SENTINEL;
125540
125577
  }
125578
+ function resolveExtractedVideoOutputDir(planDir, videoId) {
125579
+ const videoRoot = resolve36(planDir, "video-frames");
125580
+ const outputDir = resolve36(videoRoot, videoId);
125581
+ if (outputDir === videoRoot || !outputDir.startsWith(`${videoRoot}${sep10}`)) {
125582
+ throw new PlanV2IntegrityError(`unsafe extracted video id: ${JSON.stringify(videoId)}`);
125583
+ }
125584
+ return outputDir;
125585
+ }
125541
125586
  function artifactTargets(path2, videoDependencies) {
125542
125587
  if (path2 === PLAN_AUDIO_RELATIVE_PATH) return { chunks: [], assembler: true };
125543
125588
  if (path2 === "plan.json" || path2 === "meta/chunks.json" || path2 === "meta/encoder.json") {
@@ -125556,7 +125601,7 @@ function artifactTargets(path2, videoDependencies) {
125556
125601
  }
125557
125602
  function listVideoFramePaths(planV1Dir, videos) {
125558
125603
  return videos.extracted.map((video) => {
125559
- const outputDir = join68(planV1Dir, "video-frames", video.videoId);
125604
+ const outputDir = resolveExtractedVideoOutputDir(planV1Dir, video.videoId);
125560
125605
  const frameNames = readdirSync19(outputDir).sort();
125561
125606
  const framePaths = /* @__PURE__ */ new Map();
125562
125607
  for (const frameName of frameNames) {
@@ -125670,6 +125715,14 @@ function parsePlanVideosJson(value) {
125670
125715
  });
125671
125716
  return { videos, extracted };
125672
125717
  }
125718
+ function materializeExtractedVideoDirectories(planDir) {
125719
+ const videosPath = join68(planDir, PLAN_VIDEOS_META_RELATIVE_PATH);
125720
+ if (!existsSync59(videosPath)) return;
125721
+ const videos = parsePlanVideosJson(readJsonFile(videosPath, PLAN_VIDEOS_META_RELATIVE_PATH));
125722
+ for (const video of videos.extracted) {
125723
+ mkdirSync31(resolveExtractedVideoOutputDir(planDir, video.videoId), { recursive: true });
125724
+ }
125725
+ }
125673
125726
  function parseChunkSlices(value) {
125674
125727
  if (!Array.isArray(value)) {
125675
125728
  throw new PlanV2IntegrityError("meta/chunks.json must be an array");
@@ -126077,6 +126130,7 @@ function materializePlanV2Target(planV2Dir, target, destinationDir) {
126077
126130
  mkdirSync31(dirname30(destinationPath), { recursive: true });
126078
126131
  copyFileSync8(sourcePath, destinationPath);
126079
126132
  }
126133
+ if (target.role === "chunk") materializeExtractedVideoDirectories(tempDir);
126080
126134
  writeFileSync23(
126081
126135
  join68(tempDir, PLAN_V2_MATERIALIZATION_MARKER),
126082
126136
  canonicalJsonStringify({ manifest, target }),
@@ -138752,7 +138806,7 @@ function createPageDriver(page, setTime) {
138752
138806
  setTime(time);
138753
138807
  await seekCompositionTimeline(page, time, DENSE_GEOMETRY_SEEK_OPTIONS);
138754
138808
  },
138755
- collectLayout: (time, tolerance) => collectLayout(page, time, tolerance),
138809
+ collectLayout: (time, tolerance, layout2) => collectLayout(page, time, tolerance, layout2),
138756
138810
  collectOverlap: (time) => collectOverlap(page, time),
138757
138811
  collectLayoutGeometry: () => collectLayoutGeometry(page),
138758
138812
  collectRotationSample: (time) => collectRotationSample(page, time),
@@ -138838,7 +138892,7 @@ async function collectTweenBoundaries2(page) {
138838
138892
  return boundaries.filter(Number.isFinite);
138839
138893
  });
138840
138894
  }
138841
- async function collectLayout(page, time, tolerance) {
138895
+ async function collectLayout(page, time, tolerance, layout2) {
138842
138896
  const raw = await page.evaluate(
138843
138897
  (options) => {
138844
138898
  const audit = Reflect.get(window, "__hyperframesLayoutAudit");
@@ -138846,7 +138900,11 @@ async function collectLayout(page, time, tolerance) {
138846
138900
  const result = Reflect.apply(audit, window, [options]);
138847
138901
  return Array.isArray(result) ? result : [];
138848
138902
  },
138849
- { time, tolerance }
138903
+ {
138904
+ time,
138905
+ tolerance,
138906
+ ...typeof layout2?.proseCoverageFloor === "number" ? { proseCoverageFloor: layout2.proseCoverageFloor } : {}
138907
+ }
138850
138908
  );
138851
138909
  return anchorLayoutIssues(page, raw.flatMap(parseLayoutIssue));
138852
138910
  }
@@ -139618,7 +139676,7 @@ async function collectGridSamples(driver, options, grid, motion) {
139618
139676
  await driver.seek(time);
139619
139677
  const issuesAtTime = [];
139620
139678
  if (layoutSet.has(time)) {
139621
- const layoutIssues = await driver.collectLayout(time, options.tolerance);
139679
+ const layoutIssues = await driver.collectLayout(time, options.tolerance, options.layout);
139622
139680
  collected.layoutIssues.push(...layoutIssues);
139623
139681
  issuesAtTime.push(...layoutIssues);
139624
139682
  collected.geometrySignatures.push(await driver.collectLayoutGeometry());
@@ -139770,13 +139828,63 @@ function hasEnoughRotationSamples(group) {
139770
139828
  function isActuallySpinning(group) {
139771
139829
  return maxAngleSpread(group.map((s2) => s2.angle)) > ROTATION_MIN_ANGLE_SPREAD_DEG;
139772
139830
  }
139831
+ function aabbForRotatedRect(elemW, elemH, angleDeg) {
139832
+ const rad = angleDeg * Math.PI / 180;
139833
+ const cosAbs = Math.abs(Math.cos(rad));
139834
+ const sinAbs = Math.abs(Math.sin(rad));
139835
+ return { w: elemW * cosAbs + elemH * sinAbs, h: elemW * sinAbs + elemH * cosAbs };
139836
+ }
139837
+ function unrotatedSizeFromSample(sample) {
139838
+ const rad = sample.angle * Math.PI / 180;
139839
+ const cosAbs = Math.abs(Math.cos(rad));
139840
+ const sinAbs = Math.abs(Math.sin(rad));
139841
+ const det = cosAbs * cosAbs - sinAbs * sinAbs;
139842
+ if (Math.abs(det) < ROTATION_RIGID_ESTIMATE_MIN_DET) return null;
139843
+ const elemW = (cosAbs * sample.w - sinAbs * sample.h) / det;
139844
+ const elemH = (cosAbs * sample.h - sinAbs * sample.w) / det;
139845
+ if (!(elemW > 0) || !(elemH > 0)) return null;
139846
+ return { w: elemW, h: elemH };
139847
+ }
139848
+ function aabbMatchesSample(expected, sample) {
139849
+ if (expected.w <= 0 || expected.h <= 0 || sample.w <= 0 || sample.h <= 0) return false;
139850
+ return Math.max(expected.w, sample.w) / Math.min(expected.w, sample.w) <= ROTATION_RIGID_AABB_RATIO && Math.max(expected.h, sample.h) / Math.min(expected.h, sample.h) <= ROTATION_RIGID_AABB_RATIO;
139851
+ }
139852
+ function isSingularRotationAngle(angleDeg) {
139853
+ const rad = angleDeg * Math.PI / 180;
139854
+ const cosAbs = Math.abs(Math.cos(rad));
139855
+ const sinAbs = Math.abs(Math.sin(rad));
139856
+ return Math.abs(cosAbs * cosAbs - sinAbs * sinAbs) < ROTATION_RIGID_ESTIMATE_MIN_DET;
139857
+ }
139858
+ function isNearSquareAabb(sample) {
139859
+ if (sample.w <= 0 || sample.h <= 0) return false;
139860
+ return Math.max(sample.w, sample.h) / Math.min(sample.w, sample.h) <= ROTATION_RIGID_AABB_RATIO;
139861
+ }
139862
+ function fitsSingularPhaseRigidProjection(group) {
139863
+ if (group.length === 0 || !group.every((s2) => isSingularRotationAngle(s2.angle))) return false;
139864
+ if (!group.every(isNearSquareAabb)) return false;
139865
+ const ref2 = group[0];
139866
+ if (!ref2) return false;
139867
+ return group.every((sample) => aabbMatchesSample({ w: ref2.w, h: ref2.h }, sample));
139868
+ }
139869
+ function fitsOneRigidRectangle(group) {
139870
+ for (const ref2 of group) {
139871
+ const size = unrotatedSizeFromSample(ref2);
139872
+ if (!size) continue;
139873
+ if (group.every(
139874
+ (sample) => aabbMatchesSample(aabbForRotatedRect(size.w, size.h, sample.angle), sample)
139875
+ )) {
139876
+ return true;
139877
+ }
139878
+ }
139879
+ return fitsSingularPhaseRigidProjection(group);
139880
+ }
139773
139881
  function isRotationSizeStable(group) {
139774
- const widths = group.map((s2) => s2.w);
139775
- const heights = group.map((s2) => s2.h);
139776
- const minWidth = Math.min(...widths);
139777
- const minHeight = Math.min(...heights);
139778
- if (minWidth <= 0 || minHeight <= 0) return false;
139779
- return Math.max(...widths) / minWidth <= ROTATION_MAX_SIZE_RATIO && Math.max(...heights) / minHeight <= ROTATION_MAX_SIZE_RATIO;
139882
+ if (group.some((s2) => s2.w <= 0 || s2.h <= 0)) return false;
139883
+ const longSides = group.map((s2) => Math.max(s2.w, s2.h));
139884
+ const minLong = Math.min(...longSides);
139885
+ if (minLong <= 0) return false;
139886
+ if (Math.max(...longSides) / minLong > ROTATION_MAX_SIZE_RATIO) return false;
139887
+ return fitsOneRigidRectangle(group);
139780
139888
  }
139781
139889
  function isSizableRotation(group) {
139782
139890
  return median(group.map((s2) => s2.w * s2.h)) >= ROTATION_MIN_MEDIAN_AREA_PX;
@@ -140337,7 +140445,7 @@ async function captureFindingCrops2(project, options, requests) {
140337
140445
  const module = await Promise.resolve().then(() => (init_checkBrowser(), checkBrowser_exports));
140338
140446
  return module.captureFindingCrops(project, options, requests);
140339
140447
  }
140340
- var MOTION_FPS2, MOTION_MAX_SAMPLES2, ZERO_BBOX, FRAME_BREACH_FLOOR_PX, FRAME_BREACH_FLOOR_FRACTION, DEFAULT_CHECK_OPTIONS, OVERLAP_SAMPLE_FPS, OVERLAP_MAX_SAMPLES, SWEEP_STATIC_MIN_DURATION_SEC, ZERO_LAYOUT_RECT, ROTATION_MIN_SAMPLES, ROTATION_MIN_ANGLE_SPREAD_DEG, ROTATION_MAX_SIZE_RATIO, ROTATION_MIN_MEDIAN_AREA_PX, ROTATION_DRIFT_SIZE_FRACTION, ROTATION_DRIFT_VIEWPORT_FRACTION, INDICATOR_MIN_SAMPLES, INDICATOR_MIN_ANGLE_SPREAD_DEG, INDICATOR_MIN_HUB_CIRCLES, INDICATOR_MAX_FIT_RESIDUAL_FRACTION, INDICATOR_MAX_RIGID_LEN_VARIATION, INDICATOR_DRIFT_LENGTH_FRACTION, INDICATOR_MIN_HUB_PRESENCE_FRACTION, MAX_FINDING_CROPS, DEFAULT_DEPENDENCIES;
140448
+ var MOTION_FPS2, MOTION_MAX_SAMPLES2, ZERO_BBOX, FRAME_BREACH_FLOOR_PX, FRAME_BREACH_FLOOR_FRACTION, DEFAULT_CHECK_OPTIONS, OVERLAP_SAMPLE_FPS, OVERLAP_MAX_SAMPLES, SWEEP_STATIC_MIN_DURATION_SEC, ZERO_LAYOUT_RECT, ROTATION_MIN_SAMPLES, ROTATION_MIN_ANGLE_SPREAD_DEG, ROTATION_MAX_SIZE_RATIO, ROTATION_RIGID_AABB_RATIO, ROTATION_RIGID_ESTIMATE_MIN_DET, ROTATION_MIN_MEDIAN_AREA_PX, ROTATION_DRIFT_SIZE_FRACTION, ROTATION_DRIFT_VIEWPORT_FRACTION, INDICATOR_MIN_SAMPLES, INDICATOR_MIN_ANGLE_SPREAD_DEG, INDICATOR_MIN_HUB_CIRCLES, INDICATOR_MAX_FIT_RESIDUAL_FRACTION, INDICATOR_MAX_RIGID_LEN_VARIATION, INDICATOR_DRIFT_LENGTH_FRACTION, INDICATOR_MIN_HUB_PRESENCE_FRACTION, MAX_FINDING_CROPS, DEFAULT_DEPENDENCIES;
140341
140449
  var init_checkPipeline = __esm({
140342
140450
  "src/utils/checkPipeline.ts"() {
140343
140451
  "use strict";
@@ -140380,6 +140488,8 @@ var init_checkPipeline = __esm({
140380
140488
  ROTATION_MIN_SAMPLES = 3;
140381
140489
  ROTATION_MIN_ANGLE_SPREAD_DEG = 20;
140382
140490
  ROTATION_MAX_SIZE_RATIO = 1.6;
140491
+ ROTATION_RIGID_AABB_RATIO = 1.15;
140492
+ ROTATION_RIGID_ESTIMATE_MIN_DET = 0.15;
140383
140493
  ROTATION_MIN_MEDIAN_AREA_PX = 2500;
140384
140494
  ROTATION_DRIFT_SIZE_FRACTION = 0.1;
140385
140495
  ROTATION_DRIFT_VIEWPORT_FRACTION = 0.02;
@@ -140407,7 +140517,8 @@ __export(check_exports, {
140407
140517
  createCheckCommand: () => createCheckCommand,
140408
140518
  default: () => check_default,
140409
140519
  examples: () => examples12,
140410
- parseFrameCheck: () => parseFrameCheck
140520
+ parseFrameCheck: () => parseFrameCheck,
140521
+ parseLayout: () => parseLayout
140411
140522
  });
140412
140523
  function createCheckCommand(dependencies = DEFAULT_COMMAND_DEPENDENCIES) {
140413
140524
  return defineCommand({
@@ -140483,6 +140594,10 @@ function createCheckCommand(dependencies = DEFAULT_COMMAND_DEPENDENCIES) {
140483
140594
  "frame-check": {
140484
140595
  type: "string",
140485
140596
  description: 'Bare --frame-check uses defaults (tol=2px, severity=warning, seek=.5; breach floor=max(120px, 6% of shorter canvas edge)); or pass "severity=error;seek=.25,.75;tol=4" to tune'
140597
+ },
140598
+ layout: {
140599
+ type: "string",
140600
+ description: 'Layout knobs: "proseCoverageFloor=0.05" (0\u20131; default 0.15).'
140486
140601
  }
140487
140602
  },
140488
140603
  async run({ args }) {
@@ -140530,6 +140645,7 @@ function parseCheckOptions(args) {
140530
140645
  snapshots: args.snapshots === true,
140531
140646
  captionZone: parseCaptionZone(args["caption-zone"]),
140532
140647
  frameCheck: parseFrameCheck(args["frame-check"]),
140648
+ layout: parseLayout(args.layout),
140533
140649
  autoProxy: args.proxy
140534
140650
  };
140535
140651
  }
@@ -140558,8 +140674,8 @@ function parseFrameCheckFields(value) {
140558
140674
  }
140559
140675
  function parseFrameCheckTolerance(raw) {
140560
140676
  if (raw === void 0) return void 0;
140561
- const tol = Number.parseFloat(raw);
140562
- if (!Number.isFinite(tol) || tol < 0) throw frameCheckError();
140677
+ const tol = parseNumberStrict(raw);
140678
+ if (tol === null || tol < 0) throw frameCheckError();
140563
140679
  return tol;
140564
140680
  }
140565
140681
  function frameCheckError() {
@@ -140567,6 +140683,45 @@ function frameCheckError() {
140567
140683
  'Invalid --frame-check: use bare --frame-check or "severity=warning|error;seek=.25,.75;tol=4" (all fields optional)'
140568
140684
  );
140569
140685
  }
140686
+ function parseLayout(value) {
140687
+ if (value === void 0 || value === null || value === false) return void 0;
140688
+ if (value === true || value === "") throw layoutError();
140689
+ if (typeof value !== "string") throw layoutError();
140690
+ const fields = parseLayoutFields(value);
140691
+ const proseCoverageFloor = parseProseCoverageFloor(fields.get("proseCoverageFloor"));
140692
+ if (proseCoverageFloor === void 0) throw layoutError();
140693
+ return { proseCoverageFloor };
140694
+ }
140695
+ function parseLayoutFields(value) {
140696
+ const fields = /* @__PURE__ */ new Map();
140697
+ for (const part of value.split(";")) {
140698
+ const trimmed = part.trim();
140699
+ if (!trimmed) continue;
140700
+ const separator = trimmed.indexOf("=");
140701
+ if (separator <= 0) throw layoutError();
140702
+ const key2 = trimmed.slice(0, separator).trim();
140703
+ const entry = trimmed.slice(separator + 1).trim();
140704
+ if (!LAYOUT_FIELDS.has(key2) || fields.has(key2)) throw layoutError();
140705
+ fields.set(key2, entry);
140706
+ }
140707
+ return fields;
140708
+ }
140709
+ function parseProseCoverageFloor(raw) {
140710
+ if (raw === void 0) return void 0;
140711
+ const floor = parseNumberStrict(raw);
140712
+ if (floor === null || floor < 0 || floor > 1) throw layoutError();
140713
+ return floor;
140714
+ }
140715
+ function layoutError() {
140716
+ return new Error(
140717
+ 'Invalid --layout: use "proseCoverageFloor=0.05" with a fraction from 0 to 1 (inclusive)'
140718
+ );
140719
+ }
140720
+ function parseNumberStrict(raw) {
140721
+ if (raw === "") return null;
140722
+ const value = Number(raw);
140723
+ return Number.isFinite(value) ? value : null;
140724
+ }
140570
140725
  function parseCaptionZone(value) {
140571
140726
  if (value === void 0 || value === null) return void 0;
140572
140727
  const fields = parseCaptionFields(captionZoneString(value));
@@ -140618,8 +140773,8 @@ function requiredCaptionFraction(fields, key2) {
140618
140773
  }
140619
140774
  function captionFraction(value) {
140620
140775
  if (value === void 0 || value === "") return null;
140621
- const parsed = Number(value);
140622
- return Number.isFinite(parsed) && parsed >= 0 && parsed <= 1 ? parsed : null;
140776
+ const parsed = parseNumberStrict(value);
140777
+ return parsed !== null && parsed >= 0 && parsed <= 1 ? parsed : null;
140623
140778
  }
140624
140779
  function captionSeverity(value) {
140625
140780
  if (value === void 0) return void 0;
@@ -140739,7 +140894,7 @@ function printCounts(section2) {
140739
140894
  ` ${c.dim(`${section2.errorCount} error(s), ${section2.warningCount} warning(s), ${section2.infoCount} info(s)`)}`
140740
140895
  );
140741
140896
  }
140742
- var examples12, DEFAULT_COMMAND_DEPENDENCIES, CAPTION_ZONE_FIELDS, FRAME_CHECK_FIELDS, check_default;
140897
+ var examples12, DEFAULT_COMMAND_DEPENDENCIES, CAPTION_ZONE_FIELDS, FRAME_CHECK_FIELDS, LAYOUT_FIELDS, check_default;
140743
140898
  var init_check = __esm({
140744
140899
  "src/commands/check.ts"() {
140745
140900
  "use strict";
@@ -140765,6 +140920,7 @@ var init_check = __esm({
140765
140920
  };
140766
140921
  CAPTION_ZONE_FIELDS = /* @__PURE__ */ new Set(["x0", "y0", "x1", "y1", "severity", "seek"]);
140767
140922
  FRAME_CHECK_FIELDS = /* @__PURE__ */ new Set(["severity", "seek", "tol"]);
140923
+ LAYOUT_FIELDS = /* @__PURE__ */ new Set(["proseCoverageFloor"]);
140768
140924
  check_default = createCheckCommand();
140769
140925
  }
140770
140926
  });